lwip协议之底层硬件数据交互
点对点数据在网络中传输,在不同系统中,如何保证数据传输的可靠性,可识别性,那就必须存在相应的标准,不论接收方,还是发送方,严格按照标准封装或者解封装数据,在网络中传输后,才能够正确有效的将数据提取出来,这个就依赖于tcpip协议,那么出来tcpip协议最底层的数据链路层是如何完成数据的收发呢?这里介绍下lwip链路层上网卡设备如何实现数据包的发送与接收。
在数据链路层,lwip源码中通过一个结构体netif来描述设备的网卡,结构体源码(部分成员,也是主要成员,网卡初始化不可缺少的)如下:
struct netif {
/** pointer to next in linked list */
struct netif *next; //连接netif_list链表
#if LWIP_IPV4 //基于ipv4的互联网协议
/** IP address configuration in network byte order */
ip4_addr_t ip_addr; // 网卡IP地址
ip4_addr_t netmask; // 子网掩码
ip4_addr_t gw; // 网关
#endif /* LWIP_IPV4 */
#if LWIP_IPV6 //基于ipv6的互联网协议
/** Array of IPv6 addresses for this netif. */
ip6_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; //从网卡接口提取数据包送往tcpip协议栈
#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. */
netif_output_fn output; //从ip层发送数据包到网络接口
#endif /* LWIP_IPV4 */
/** 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; //从arp层发送数据包到网络接口
。。。
/** maximum transfer unit (in bytes) */
u16_t mtu; //最大转发字节数,数据包最大长度
/** number of bytes used in hwaddr */
u8_t hwaddr_len; //mac地址长度
/** link level hardware address of this interface */
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; //mac地址
/** flags (see NETIF_FLAG_ above) */
u8_t flags; //网卡的功能定义
/** descriptive abbreviation */
char name[2]; //网卡的名字
/** number of this interface */
u8_t num;
。。。
};
介绍完netif结构体成员,现在我们回到,lwip初始化上分析下netif_add函数(主要是对netif结构体的初始化,添加到netif_list)。
netif_add(&sta_if, sta_ip_addr, sta_net_mask, sta_gw, NULL, ethernetif_init1, tcpip_input);
struct netif *
netif_add(struct netif *netif,
#if LWIP_IPV4
const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw,
#endif /* LWIP_IPV4 */
void *state, netif_init_fn init, netif_input_fn input)
{
#if LWIP_IPV6
u32_t i;
#endif
LWIP_ASSERT("No init function given", init != NULL);
/* reset new interface configuration state */
#if LWIP_IPV4
ip4_addr_set_zero(&netif->ip_addr);
ip4_addr_set_zero(&netif->netmask);
ip4_addr_set_zero(&netif->gw);
#endif /* LWIP_IPV4 */ //复位网卡的各个参数值
#if LWIP_IPV6
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip6_addr_set_zero(&netif->ip6_addr[i]);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
}
netif->output_ip6 = netif_null_output_ip6;
#endif /* LWIP_IPV6 */
netif->flags = 0; //使能网卡的功能
#if LWIP_DHCP
/* netif not under DHCP control by default */
netif->dhcp = NULL;
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/* netif not under AutoIP control by default */
netif->autoip = NULL;
#endif /* LWIP_AUTOIP */
#if LWIP_IPV6_AUTOCONFIG
/* IPv6 address autoconfiguration not enabled by default */
netif->ip6_autoconfig_enabled = IPV6_AUTOCONFIG_DISENABLED;
#endif /* LWIP_IPV6_AUTOCONFIG */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
netif->rs_interval = LWIP_ND6_PTR_SOLICITATION_INTERVAL;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_IPV6_DHCP6
/* netif not under DHCPv6 control by default */
netif->dhcp6 = NULL;
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL;
netif->wifi_callback = NULL;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
netif->link_callback = NULL;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_IGMP
netif->igmp_mac_filter = NULL;
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->mld_mac_filter = NULL;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if ENABLE_LOOPBACK
netif->loop_first = NULL;
netif->loop_last = NULL;
#endif /* ENABLE_LOOPBACK */
/* remember netif specific state information data */
netif->state = state;
netif->num = netif_num++;
netif->input = input; //给input函数赋值,netif结构体中有描述
NETIF_SET_HWADDRHINT(netif, NULL);
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
netif->loop_cnt_current = 0;
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
#if LWIP_IPV4
netif_set_addr(netif, ipaddr, netmask, gw); //设置网卡的参数
#endif /* LWIP_IPV4 */
/* call user specified initialization function for netif */
if (init(netif) != ERR_OK) { //init(netif),主要函数传参,网卡的初始化函数被执行,下文解析
return NULL;
}
/* add this netif to the list */ //将网卡加入到netif_list链表
netif->next = netif_list;
netif_list = netif;
snmp_inc_iflist();
#if LWIP_IGMP
/* start IGMP processing */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_start(netif);
}
#endif /* LWIP_IGMP */
LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP",
netif->name[0], netif->name[1]));
#if LWIP_IPV4
LWIP_DEBUGF(NETIF_DEBUG, (" addr "));
ip4_addr_debug_print(NETIF_DEBUG, ipaddr);
LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
ip4_addr_debug_print(NETIF_DEBUG, netmask);
LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
ip4_addr_debug_print(NETIF_DEBUG, gw);
#endif /* LWIP_IPV4 */
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
return netif;
}
下面解析下网卡初始化函数ethernetif_init1
err_t
ethernetif_init1(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] = IFNAME00;
netif->name[1] = IFNAME01;
/* 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; //走ip层数据包,将ip层数据发送到网络接口
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = (netif_linkoutput_fn)low_level_output_scatter; //走的arp层数据包,将arp层数据发送到网络接口
ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
/* initialize the hardware */
low_level_init1(netif); //初始化硬件接口函数
#if 0
/* Create a task that simulates an interrupt in a real system. This will
block waiting for packets, then send a message to the uIP task when data
is available. */
LOG_I(lwip, "Create RX task\n\r");
xTaskCreate(InterruptSimulator, "RX", 400, (void *)netif, 3, NULL );
#endif
return ERR_OK;
}
由此可以看出,lwip协议在底层通过一个netif结构体对网卡进行管理,多网卡就产生一个网卡链表,网卡的数据通过 netif->input,netif->output,netif->linkoutput函数指针,完成与ip层或arp层的数据交互。
netif->output最底层还是得调用netif->linkoutput接口发送数据包,两者区别在于知不知道目的mac地址,如果知道目的mac地址,就能直接调用netif->linkoutput把数据交给网卡,如果不知道,则需要走arp层,通过arp协议先找到目的mac地址才能够将数据传输出去。