LwIP 之二 网络接口 netif(netif.c、ethernetif

目前 , 网络上多数文章所使用的 LwIP 版本为 1.4.1 , 而在写本文时的最新版本为 2.0.3 。从 1.4.1 到 2.0.3(貌似从 2.0.0 开始) ,  LwIP 的源码有了一定的变化 , 甚至于源码的文件结构也不一样 , 内部的一些实现源文件也被更新和替换了 。
简介
LwIP 使用netif 来描述一个硬件网络接口 。netif 是 LwIP 抽象出来的各网络接口 , 协议栈可以使用多个不同的接口 , 而 ./src/netif/.c、./src/netif/.c 就提供了netif 访问硬件的各接口 。
但是 , 由于网络接口是直接与硬件打交道的 , 硬件接口不同则处理可能不同 , 必须由用户提供最底层接口 。源码目录 ./src/netif/ 目录下就包含了各种接口定义:
相关配置
LwIP 的所有配置项均位于 /src//lwip/opt.h 文件中 , 并由用户提供的 .h 中的同名配置项所覆盖 , 以此实现用户配置而不用更改源码 。netif 相关的配置项解释如下:
netif 结构
在 LwIP 中 , 是通过定义于/src//lwip/netif.h 中的netif 这个结构体来描述一个硬件网络接口的 。在实际使用时 , 我们需要使用netif 定义一个全局变量表示一个网络接口并注册到 LwIP 中 。该部分的定义在文件 netif.c/h 中 , 具体如下:
/** Generic data structure used for all lwIP network interfaces.*The following fields should be filled in by the initialization*function for the device driver: hwaddr_len, hwaddr[], mtu, flags */struct netif {/** pointer to next in linked list */struct netif *next;#if LWIP_IPV4/** IP address configuration in network byte order */ip_addr_t ip_addr;/* IP 地址 */ip_addr_t netmask;/* 子网掩码 */ip_addr_t gw;/* 网关 */#endif /* LWIP_IPV4 */#if LWIP_IPV6/** Array of IPv6 addresses for this netif. */ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];/** The state of each IPv6 address (Tentative, Preferred, etc).* @see ip6_addr.h */u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];#endif /* LWIP_IPV6 *//** This function is called by the network device driver*to pass a packet up the TCP/IP stack. */netif_input_fn input;/* 函数指针 , 从网卡中接收一包数据 */#if LWIP_IPV4/** This function is called by the IP module when it wants*to send a packet on the interface. This function typically*first resolves the hardware address, then sends the packet.*For ethernet physical layer, this is usually etharp_output() */netif_output_fn output;/* IP层调用此函数向网卡发送一包数据 */#endif /* LWIP_IPV4 *//** This function is called by ethernet_output() when it wants*to send a packet on the interface. This function outputs*the pbuf as-is on the link medium. */netif_linkoutput_fn linkoutput;/* ARP模块调用这个函数向网卡发送一包数据 */#if LWIP_IPV6/** This function is called by the IPv6 module when it wants*to send a packet on the interface. This function typically*first resolves the hardware address, then sends the packet.*For ethernet physical layer, this is usually ethip6_output() */netif_output_ip6_fn output_ip6;#endif /* LWIP_IPV6 */#if LWIP_NETIF_STATUS_CALLBACK/** This function is called when the netif state is set to up or down*/netif_status_callback_fn status_callback;#endif /* LWIP_NETIF_STATUS_CALLBACK */#if LWIP_NETIF_LINK_CALLBACK/** This function is called when the netif link is set to up or down*/netif_status_callback_fn link_callback;#endif /* LWIP_NETIF_LINK_CALLBACK */#if LWIP_NETIF_REMOVE_CALLBACK/** This function is called when the netif has been removed */netif_status_callback_fn remove_callback;#endif /* LWIP_NETIF_REMOVE_CALLBACK *//** This field can be set by the device driver and could point*to state information for the device. */void *state;/* 这个成员变量注意以下 , 主要是将 网卡的某些私有数据传递给上层 , 用户可以自由发挥 , 也可以不用 。下面会有详细说明 。*/#ifdef netif_get_client_datavoid* client_data[LWIP_NETIF_CLIENT_DATA_INDEX_MAX + LWIP_NUM_NETIF_CLIENT_DATA];#endif#if LWIP_IPV6_AUTOCONFIG/** is this netif enabled for IPv6 autoconfiguration */u8_t ip6_autoconfig_enabled;#endif /* LWIP_IPV6_AUTOCONFIG */#if LWIP_IPV6_SEND_ROUTER_SOLICIT/** Number of Router Solicitation messages that remain to be sent. */u8_t rs_count;#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */#if LWIP_NETIF_HOSTNAME/* the hostname for this netif, NULL is a valid value */const char*hostname;#endif /* LWIP_NETIF_HOSTNAME */#if LWIP_CHECKSUM_CTRL_PER_NETIFu16_t chksum_flags;#endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*//** maximum transfer unit (in bytes) */u16_t mtu;/* 网络一次可以传送的最大字节数 , 对于以太网一般设为 1500 *//** number of bytes used in hwaddr */u8_t hwaddr_len;/* 硬件地址长度 , 对于以太网就是 MAC 地址长度 , 为 6 各字节 *//** link level hardware address of this interface */u8_t hwaddr[NETIF_MAX_HWADDR_LEN];/** flags (@see @ref netif_flags) */u8_t flags;/* 网卡状态信息标志位 , 是很重要的控制字段 , 它包括网卡功能使能、广播使能、 ARP 使能等等重要控制位 。*//** descriptive abbreviation */char name[2]; /* 字段用于保存每一个网络网络接口的名字 。用两个字符的名字来标识网络接口使用的设备驱动的种类 , 名字由设备驱动来设置并且应该反映通过网络接口表示的硬件的种类 。比如蓝牙设备( bluetooth)的网络接口名字可以是 bt , 而 IEEE 802.11b WLAN 设备的名字就可以是 wl , 当然设置什么名字用户是可以自由发挥的 , 这并不影响用户对网络接口的使用 。当然 , 如果两个网络接口具有相同的网络名字 , 我们就用 num 字段来区分相同类别的不同网络接口 。*//** number of this interface */u8_t num;/* 用来标示使用同种驱动类型的不同网络接口 */#if MIB2_STATS/** link type (from "snmp_ifType" enum from snmp_mib2.h) */u8_t link_type;/** (estimate) link speed */u32_t link_speed;/** timestamp at last change made (up/down) */u32_t ts;/** counters */struct stats_mib2_netif_ctrs mib2_counters;#endif /* MIB2_STATS */#if LWIP_IPV4 && LWIP_IGMP/** This function could be called to add or delete an entry in the multicastfilter table of the ethernet MAC.*/netif_igmp_mac_filter_fn igmp_mac_filter;#endif /* LWIP_IPV4 && LWIP_IGMP */#if LWIP_IPV6 && LWIP_IPV6_MLD/** This function could be called to add or delete an entry in the IPv6 multicastfilter table of the ethernet MAC. */netif_mld_mac_filter_fn mld_mac_filter;#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */#if LWIP_NETIF_HWADDRHINTu8_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_PBUFSu16_t loop_cnt_current;#endif /* LWIP_LOOPBACK_MAX_PBUFS */#endif /* ENABLE_LOOPBACK */};