#if LWIP_SNMP
/** link type (from \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.*/
err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);
#endif /* LWIP_IGMP */
#if LWIP_NETIF_HWADDRHINT u8_t *addr_hint;
#endif /* LWIP_NETIF_HWADDRHINT */ };
该结构体实现在【src\\include\\lwip\\netif.h】,注意到该结构体成员中有3个函数指针变量。好了,这个结构体先做一大体了解。用到的时候再详细讲。
接下来先看下ip_route函数的实现:
* Finds the appropriate network interface for a given IP address. It * searches the list of network interfaces linearly. A match is found * if the masked IP address of the network interface equals the masked * IP address given to the function.
struct netif * ip_route(struct ip_addr *dest) {
struct netif *netif;
/* iterate through netifs */
for(netif = netif_list; netif != NULL; netif = netif->next) { /* network mask matches? */
36
if (netif_is_up(netif)) {
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { /* return netif on which to forward IP packet */ return netif; } } }
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
snmp_inc_ipoutnoroutes(); return NULL; }
/* no matching netif found, use default netif */ return netif_default; }
可以说这个函数的实现很简单,且作用也很容易看懂,就像其注释所说的一样。不过在这个函数中我们还是发现了一些什么,对了,就是struct netif *netif_list;【src\\core\\netif.c】的使用。既然这里都使用了这个网络接口链表,那它是在哪里被初始化的呢?
好了,首先我们发现在netif_add函数中有对netif_list的调用,netif_add是被do_netifapi_netif_add函数调用的,而do_netifapi_netif_add是在netifapi_netif_add中通过netifapi_msg被TCPIP_NETIFAPI调用的。问题似乎很清楚,只要找到nnetifapi_netif_add是被谁调用的就好了,然而,搜遍整个工程也没有发现这个函数的影子,除了一个声明一个实现外。My god,又进入死胡同了?好吧,这里先标识一下,待解【见下面的解释】
我们接着看ip_output_if这个函数,具体函数可参考【src\\core\\ipv4\\ip.c】。它的函数* Sends an IP packet on a network interface. This function constructs * the IP header and calculates the IP header checksum. If the source * IP address is NULL, the IP address of the outgoing network * interface is filled in as source address.
* If the destination IP address is IP_HDRINCL, p is assumed to already * include an IP header and p->payload points to it instead of the data. 再看最后一句:return netif->output(netif, p, dest);
嗯,看来这个netif还是关键啊,如果估计不错的话,接收的时候也要用到这个结构的。那就看它在什么地方被赋值的吧。又经过一番搜索,看来在目前的代码中是找不到的了。查看lwip协议栈的设计与实现,特别是网络接口层的那一节,终于明白了,原来这些是要有设备驱动来参与的:【一下为引用】
当收到一个信息包时,设备驱动程序调用input指针指向的函数。网络接口通过output指针连接到设备驱动。这个指针指向设备驱动中一个向物理网络发送信息包的函数,当信息包包被发送时由IP层调用,这个字段由设备驱动的初始设置函数填充。
接下来就是ip层的接收过程了。刚才上面也有提到驱动设备收到包,丢给netif的input函数,这个input函数也是设备驱动层来设置的。无非有两个可能,一个是ip_input,另外一
37
定义注释如下:
嗯,那就这样吧,到这里我们可以说IP层的发送流程已经走完了。
个就是tcpip_input。因为tcpip_input函数的处理是最终调用到了ip_input【在tcpip_thread中】。按照正常情况下应该是ip_input函数的,我们先来看下这个函数。 * This function is called by the network interface device driver when * an IP packet is received. The function does the basic checks of the * IP header such as packet size being at least larger than the header * size etc. If the packet was not destined for us, the packet is * forwarded (using ip_forward). The IP checksum is always checked. 原型:err_t ip_input(struct pbuf *p, struct netif *inp)
该函数大致的处理过程是:处理ip包头;找到对应的netif;检查如果是广播或多播包,则丢掉;如果是tcp协议的话就直接调用了tcp_input函数处理数据。
到此,ip层的东西大致就说完了。最后,由于tcp和ip层的东西都说完了,所以此时我们顺便看下,tcpip的整体实现,这个主要是在src\\api\\tcpip.c文件中实现。我们知道发送过程是由socket直接调用的,所以这个文件中不涉及,说白了,这个文件主要是涉及到整个接收过程。这里实现的函数有tcpip_input,和tcpip_thread以及tcpip_init函数。 Tcpip_init函数很简单就是创建系统线程(sys_thread_new)tcpip_thread。 Tcpip_thread函数的注释如下:
* The main lwIP thread. This thread has exclusive access to lwIP core fun* (unless access to them is not locked). Other threads communicate with * thread using message boxes.
它的整个过程就是一直从mbox中取出msg,对各种msg的一个处理过程。 Tcpip_input函数,是在tcpip_thread中被调用的处理设备驱动接收到的信息包,并调用
ip_input来进一步处理。
整个启动过程: main---> vlwIPInit() void vlwIPInit( void ) {
/* Initialize lwIP and its interface layer. */ sys_init();
mem_init(); memp_init(); pbuf_init(); netif_init(); ip_init();
sys_set_state(( signed portCHAR * ) \ tcpip_init( NULL, NULL ); sys_set_default_state(); }
从上面我们知道,tcpip_init创建tcpip_thread 在tcpip_thread的开始有如下代码:
38
ctions this
(void)arg; ip_init();
#if LWIP_UDP udp_init(); #endif
#if LWIP_TCP tcp_init(); #endif
#if IP_REASSEMBLY
sys_timeout(1000, ip_timer, NULL); #endif
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg); }
下面是tcp_init的实现 Void tcp_init(void) {
/* Clear globals. */
tcp_listen_pcbs.listen_pcbs = NULL; tcp_active_pcbs = NULL; tcp_tw_pcbs = NULL; tcp_tmp_pcb = NULL;
/* initialize timer */ tcp_ticks = 0; tcp_timer = 0; }
底层结构(物理层)
们前面讲到说是ip层的发送和接收都是直接调用了底层,也就是设备驱动层的函数实现,在这里暂且称之为物理层吧。下面就接着ip层的讲,不过由于这里的设备驱动各平台的都不一样,为此,我们选择ARM9_STR91X_IAR这个Demo作为实例,该平台的网络设备驱动在\\libra
39
ry\\source\\91x_enet.c文件中。而ethernetif.c文件就是我们需要的,它是连接设备驱动程序与ip层的桥梁。
Ethernetif.c文件中提供的函数主要有以下这么几个:
(1) low_level_init (2) low_level_input (3) low_level_output (4) ethernetif_init (5) ethernetif_input (6) ethernetif_output
这里对外的接口只有ethernetif_init函数,它是main函数中通过
netif_add( &EMAC_if, &xIpAddr, &xNetMast, &xGateway, NULL, ethernetif_init, tcpip_input );来被调用的。我们可以清楚的看到,tcpip_input的使用,它就是被用来当有数据接收的时候被调用的以使接收到的数据进入tcpip协议栈。
在netif_add函数中,我们可以看到 netif->input = input; if (init(netif) != ERR_OK) {
return NULL; }
Ok,从这里就进入到ethernetif_init函数了,在这个函数中,我们主要看以下几句: netif->output = ethernetif_output; netif->linkoutput = low_level_output; low_level_init(netif); etharp_init();
可以看到,netif->output 和netif->linkoutput被赋值了,这个很重要的,等会再说。
好,再接着看low_level_init函数
s_pxNetIf = netif;//对全局变量s_pxNetIf 赋初值 ENET_InitClocksGPIO(); ENET_Init();
ENET_Start();//这3句是对网络设备的寄存等的配置
xTaskCreate( ethernetif_input, ( signed portCHAR * ) \netifINTERFACE_TASK_STACK_SIZE, NULL, netifINTERFACE_TASK_PRIORITY, NULL ); 以ethernet_input创建task,这个函数也很有意思,首先可以看到的是一个无限循环,在循环体中有以下调用:
p = low_level_input( s_pxNetIf );
s_pxNetIf->input(p, s_pxNetIf);//tcpip_input
虽然有了这两句,还不是很清楚,可以确定的是后一句是把接收到的数据送入tcpip协议栈处理,为此,我们想到上一句是从硬件读出数据。看下具体的low_level_input函数实现: len = ENET_HandleRxPkt(s_rxBuff); 这个函数很好理解,主要的是上面的那一句。
40