From 62d8a63dbb3c204aba3e623afd7e89cd6057cc88 Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Wed, 4 Feb 2015 14:52:17 -0800 Subject: [PATCH] Basic ethernet driver and connected to lwiptest --- lib/liblwip/SConscript | 1 + lib/liblwip/src/arch/etherif.c | 360 +++++++++++++++++++++++++++++++++ tests/lwiptest.c | 6 + 3 files changed, 367 insertions(+) create mode 100644 lib/liblwip/src/arch/etherif.c diff --git a/lib/liblwip/SConscript b/lib/liblwip/SConscript index 5cbf457..c7746d6 100644 --- a/lib/liblwip/SConscript +++ b/lib/liblwip/SConscript @@ -6,6 +6,7 @@ liblwip_env = env.Clone() src = [ "src/arch/sys_arch.c", + "src/arch/etherif.c", "src/api/api_lib.c", "src/api/api_msg.c", "src/api/err.c", diff --git a/lib/liblwip/src/arch/etherif.c b/lib/liblwip/src/arch/etherif.c new file mode 100644 index 0000000..6ee3a25 --- /dev/null +++ b/lib/liblwip/src/arch/etherif.c @@ -0,0 +1,360 @@ +/** + * @file + * Ethernet Interface Skeleton + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* NIC Number */ +static int nicNo = 1; + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * Helper struct to hold private data used to operate your ethernet interface. + * Keeping the ethernet address of the MAC in this struct is not necessary + * as it is already kept in the struct netif. + * But this is only an example, anyway... + */ +struct ethernetif { + struct eth_addr *ethaddr; + /* Add whatever per-interface state that is needed here. */ +}; + +/* Forward declarations. */ +static void ethernetif_input(struct netif *netif); +static void ethernetif_thread(void *arg); + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void +low_level_init(struct netif *netif) +{ + //struct ethernetif *ethernetif = netif->state; + + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* set MAC hardware address */ + netif->hwaddr[0] = 0x11; + netif->hwaddr[1] = 0x22; + netif->hwaddr[2] = 0x33; + netif->hwaddr[3] = 0x44; + netif->hwaddr[4] = 0x55; + netif->hwaddr[5] = 0x66; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + + /* Do whatever else is needed to initialize interface. */ + sys_thread_new("ethernetif_thread", ethernetif_thread, netif, + DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become availale since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + struct MBuf mbuf; + struct pbuf *q; + char buf[1500]; + char *bufptr; + int status; + + /* initiate transfer(); */ + bufptr = &buf[0]; + + for(q = p; q != NULL; q = q->next) { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + /* send data from(q->payload, q->len); */ + memcpy(bufptr, q->payload, q->len); + bufptr += q->len; + } + + /* signal that packet should be sent(); */ + mbuf.vaddr = (uint64_t)buf; + mbuf.maddr = 0; + mbuf.len = p->tot_len; + mbuf.type = MBUF_TYPE_NULL; + mbuf.flags = 0; + mbuf.status = MBUF_STATUS_NULL; + + status = OSNICSend(nicNo, &mbuf); + if (status != 0) { + printf("OSNICSend failed!\n"); + return ERR_IF; + } + + if (mbuf.status == MBUF_STATUS_FAILED) { + printf("Failed to write packet!\n"); + return ERR_IF; + } + + return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif) +{ + struct MBuf mbuf; + struct pbuf *p, *q; + char buf[1500]; + char *bufptr; + u16_t len; + int status; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + mbuf.vaddr = (uint64_t)buf; + mbuf.maddr = 0; + mbuf.len = 1500; + mbuf.type = MBUF_TYPE_NULL; + mbuf.flags = 0; + mbuf.status = MBUF_STATUS_NULL; + + status = OSNICRecv(nicNo, &mbuf); + if (status != 0) { + printf("OSNICSend failed!\n"); + return NULL; + } + + if (mbuf.status == MBUF_STATUS_FAILED) { + printf("Failed to write packet!\n"); + return NULL; + } + + len = mbuf.len; + +#if ETH_PAD_SIZE + len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (p != NULL) { + /* We iterate over the pbuf chain until we have read the entire + packet into the pbuf. */ + bufptr = &buf[0]; + for(q = p; q != NULL; q = q->next) { + /* Read enough bytes to fill this pbuf in the chain. The + available data in the pbuf is given by the q->len + variable. */ + /* read data into(q->payload, q->len); */ + memcpy(q->payload, bufptr, q->len); + bufptr += q->len; + } + + /* acknowledge that packet has been read(); */ + LINK_STATS_INC(link.recv); + } else { + /* drop packet(); */ + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + } + + return p; +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +static void +ethernetif_input(struct netif *netif) +{ + struct eth_hdr *ethhdr; + struct pbuf *p; + + /* move received packet into a new pbuf */ + p = low_level_input(netif); + /* no packet could be read, silently ignore this */ + if (p == NULL) return; + /* points to packet payload, which starts with an Ethernet header */ + ethhdr = p->payload; + + switch (htons(ethhdr->type)) { + /* IP or ARP packet? */ + case ETHTYPE_IP: + case ETHTYPE_ARP: +#if PPPOE_SUPPORT + /* PPPoE packet? */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + /* full packet send to tcpip_thread to process */ + if (netif->input(p, netif)!=ERR_OK) + { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + break; + + default: + pbuf_free(p); + p = NULL; + break; + } +} + +/* + * Input thread + */ +static void +ethernetif_thread(void *arg) +{ + struct netif *netif = (struct netif *)arg; + + while (1) { + /* Wait for a packet to arrive. */ + ethernetif_input(netif); + } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t +ethernetif_init(struct netif *netif) +{ + struct ethernetif *ethernetif; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + ethernetif = mem_malloc(sizeof(struct ethernetif)); + if (ethernetif == NULL) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); + return ERR_MEM; + } + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ + netif->output = etharp_output; + netif->linkoutput = low_level_output; + + ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} + diff --git a/tests/lwiptest.c b/tests/lwiptest.c index 4c40dd0..e1cb1a8 100644 --- a/tests/lwiptest.c +++ b/tests/lwiptest.c @@ -3,6 +3,8 @@ #include #include +extern err_t ethernetif_init(struct netif *netif); + int main(int argc, const char *argv[]) { @@ -15,6 +17,10 @@ main(int argc, const char *argv[]) lwip_init(); + netif_add(&netif, &addr, &mask, &gw, NULL, ethernetif_init, NULL); //ethernetif_input); + netif_set_default(&netif); + netif_set_up(&netif); + lwip_socket(AF_INET, SOCK_STREAM, IP_PROTO_TCP); return 0;