file netif.c
netif 理解为网卡的抽象,一个网卡对于一个nedif。网卡这里是一个广义概念,具有IP地址的网络装置或者模块。
struct netif *netif_list; 全局链表指针,表示网卡抽象设备链表。下图所示
netif 属于LWIP的组件,其数据发送和接受的接口实现位于PHY Driver
netif 是对网络通信接口的抽象
netif关注的是给LWIP 上层使用的借口,
if = interface
/** This function is called by the network device driver
- to pass a packet up the TCP/IP stack. /
netif_input_fn input;
/* 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. /
netif_output_fn output;
/* This function is called by the ARP module 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;
/** 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;
/** IP address configuration in network byte order */
ip_addr_t ip_addr;
ip_addr_t netmask;
ip_addr_t gw;
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
netif_input_fn input;
/** 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. */
netif_output_fn output;
/** This function is called by the ARP module 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;
#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;
#if LWIP_DHCP
/** the DHCP client state information for this netif */
struct dhcp *dhcp;
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/** the AutoIP client state information for this netif */
struct autoip *autoip;
#endif
#if LWIP_NETIF_HOSTNAME
/* the hostname for this netif, NULL is a valid value */
char* hostname;
#endif /* LWIP_NETIF_HOSTNAME */
/** maximum transfer unit (in bytes) */
u16_t mtu;
/** number of bytes used in hwaddr */
u8_t hwaddr_len;
/** link level hardware address of this interface */
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
/** flags (see NETIF_FLAG_ above) */
u8_t flags;
/** descriptive abbreviation */
char name[2];
/** number of this interface */
u8_t num;
#if LWIP_SNMP
/** link type (from "snmp_ifType" enum from snmp.h) */
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 */
};
netif中的接口都是函数指针,所以函数指针需要初始化才能由函数实体。所以很容易联想到,网卡的初始化。
netif 中其他变量的作用在了解LWIP整体前,细究其作用并不大。
所以对于网卡来说,需要提供给netif 几个接口
- in :网络设备取货的数据,完成对应的解析,装载到pbuf ,提供给IP层
- out:上层不数据状图pbuf然后调用函数发送数据
- 初始化,netif初始化和网络设备的初始化。
把netif 加入到struct netif *netif_list; 全局链表指针 的过程称为注册。
/**
* Add a network interface to the list of lwIP netifs.
*
* @param netif a pre-allocated netif structure
* @param ipaddr IP address for the new netif
* @param netmask network mask for the new netif
* @param gw default gateway IP address for the new netif
* @param state opaque data passed to the new netif
* @param init callback function that initializes the interface
* @param input callback function that is called to pass
* ingress packets up in the protocol layer stack.
*
* @return netif, or NULL if failed.
*/
struct netif *
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
ethernetif.c 是一个例子
/* * 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. */
ethernetif_init(struct netif *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 */
网络设备的初始化时通过
/* initialize the hardware */
low_level_init(netif);
low_level_XXX函数时网络设备的接口实现。
一个netif 初始化过程
void
netif_init(void)
{
#if LWIP_HAVE_LOOPIF
ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
IP4_ADDR(&loop_gw, 127,0,0,1);
IP4_ADDR(&loop_ipaddr, 127,0,0,1);
IP4_ADDR(&loop_netmask, 255,0,0,0);
#if NO_SYS
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
#else /* NO_SYS */
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
#endif /* NO_SYS */
netif_set_up(&loop_netif);
#endif /* LWIP_HAVE_LOOPIF */
}
netif 输入与输出
/**
* 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)
ethernetif_input调用low_level_input获取网络设备接收到的数据
根据帧类型忘上层递交
ethernetif_input 会递交到ethernet_input
IRQ 中断发送后代表 ETH网络设备首到一帧数据,LWIP对网络设备数据输入从ethernetif_input开始
ethernetif_input调用ETH网络设备的 Low_level_input获取以太网帧到pbuf
ethernetif_input把收到的数据往上递交到erthnet_input。erthnet_input 在netif_add作为参数传入到netif。
所以接收以太网帧的过程是一个数据递交过程。erthnet_input 位于ARP
对长度和类型判断数据包是ARP包还是IP包。IP包需要递交到IP。ARP递交到ARP。
以太网帧的数据是向上递交的过程。
etharp_ip_input,
1.etharp_ip_input会判断这个IP数据报中的目的IP是不是本地网络,如果不是那么丢弃。
2.收到的IP报可以用于更新ARP列表。
ip_input 分支做简单的处理后发往上层(例如TCP)
etharp_arp_input分支。完成对ARP的应答和处理。