/** link type (from \ u8_t link_type; /** (estimate) link speed */ u32_t link_speed; /** timestamp at last change made (up/down) */ u32_t ts; /** counters */ u32_t ifinoctets; u32_t ifinucastpkts; u32_t ifinnucastpkts; u32_t ifindiscards; u32_t ifoutoctets; u32_t ifoutucastpkts; u32_t ifoutnucastpkts; u32_t ifoutdiscards; #endif /* LWIP_SNMP */ #if LWIP_IGMP /** This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/ netif_igmp_mac_filter_fn igmp_mac_filter; #endif /* LWIP_IGMP */ #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; #endif /* LWIP_NETIF_HWADDRHINT */ #if ENABLE_LOOPBACK /* List of packets to be queued for ourselves. */ struct pbuf *loop_first; struct pbuf *loop_last; #if LWIP_LOOPBACK_MAX_PBUFS u16_t loop_cnt_current; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* ENABLE_LOOPBACK */ };
struct pbuf
一个网络包可能由多个pbuf组成,字段tot_len指定这个网络包的大小,字段len是当前pbuf包含数据的大小。
判断一个网络包的最后一个包不能以next字段等于空来判断,它可能不为空,下一个pbuf为下一个网络包的内容。应该计算tot_len来判断一个包的结束。
struct pbuf { /** next pbuf in singly linked pbuf chain */ struct pbuf *next; //下一个pbuf /** pointer to the actual data in the buffer */ void *payload; // 当前结构数据内容 /** * total length of this buffer and all next buffers in chain * belonging to the same packet. * * For non-queue packet chains this is the invariant: * p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ u16_t tot_len; /** length of this buffer */ u16_t len; /** pbuf_type as u8_t instead of enum to save space */ u8_t /*pbuf_type*/ type; /** misc flags */ u8_t flags; /** * the reference count always equals the number of pointers * that refer to this pbuf. This can be pointers from an application, * the stack itself, or pbuf->next pointers from a chain. */ u16_t ref; };
Ethernetif.c
它是你要移植的网卡驱动程序与lwip连接的文件。源代码提供了一个模板。
struct ethernetif结构
它是网卡私有数据结构
struct ethernetif { struct eth_addr *ethaddr; /* Add whatever per-interface state that is needed here. */在这里添加自定义的数据 };
ethernetif_input
网卡有数据时应该调用这个函数。过程大致如下:
网卡读任务 中断处理 (1)信号量pend(等待数据到来如果有中断表明数据包到达,给“网卡读任务”中断) 发送信号量。 (2)pend成功,调用ethernetif_input (3)回到步骤1.
ethernetif_input做的工作有:
(1) 调用low_level_input读取数据包
(2) 判断数据包的以太网类型并调用netif->input。netif->input是在协议栈初始化添加的。如netif_add(mLocalNetif, &ipaddr, &netmask, &gw, NULL,ethernetif_init, tcpip_input),那么它是tcpip_input,tcpip_input做的工作发送消息给tcpip主线线程,它把数据包交给上层处理。
/** * 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 ethernetif *ethernetif; struct eth_hdr *ethhdr; struct pbuf *p; ethernetif = netif->state; /* 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, (\ pbuf_free(p); p = NULL; } break; default: pbuf_free(p); p = NULL; break; }