LWIP之IP层实现(转载)
生活随笔
收集整理的這篇文章主要介紹了
LWIP之IP层实现(转载)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文地址:http://bluefish.blog.51cto.com/214870/158417
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
這一部分的實現都是在ip.c文件中【src\cor\ipv4】,可以看到在這個文件中主要實現了3個函數,ip_input;ip_route;ip_output以及ip_output_if。下面分別來介紹它們。 ? ?????? 這些函數可以分成兩大類:接收和發送。下面就先從發送開始,首先要說的就是ip_output函數,這個也是發送過程中最重要的一個,它是被tcp層調用的,詳細可參見以上章節。 * Simple interface to ip_output_if. It finds the outgoing network * interface and calls upon ip_output_if to do the actual work. err_t? ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, ????????? u8_t ttl, u8_t tos, u8_t proto) { ? struct netif *netif; ? ? if ((netif = ip_route(dest)) == NULL) { ??? return ERR_RTE; ? } ? ? return ip_output_if(p, src, dest, ttl, tos, proto, netif); } 可以看到該函數的實現就像注釋所說的一樣,直接調用了ip_route和ip_outputif兩個函數。根據以往的經驗,先看下netif這個結構的實現情況: * 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 */ ? struct ip_addr ip_addr; ? struct ip_addr netmask; ? struct ip_addr gw; ? ? /** This function is called by the network device driver ?? *? to pass a packet up the TCP/IP stack. */ ? err_t (* input)(struct pbuf *p, struct netif *inp); ? ? /** 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. */ ? err_t (* output)(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr); ? ? /** 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. */ ? err_t (* linkoutput)(struct netif *netif, struct pbuf *p); ? #if LWIP_NETIF_STATUS_CALLBACK ? /** This function is called when the netif state is set to up or down ?? */ ? void (* status_callback)(struct netif *netif); #endif /* LWIP_NETIF_STATUS_CALLBACK */ ? #if LWIP_NETIF_LINK_CALLBACK ? /** This function is called when the netif link is set to up or down ?? */ ? void (* link_callback)(struct netif *netif); #endif /* LWIP_NETIF_LINK_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 */ ? ? /** number of bytes used in hwaddr */ ? u8_t hwaddr_len; ? ? /** link level hardware address of this interface */ ? u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; ? ? /** maximum transfer unit (in bytes) */ ? u16_t mtu; ? /** 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.*/ ? 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? */ ??? 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層的發送流程已經走完了。 ? ?????? 接下來就是ip層的接收過程了。剛才上面也有提到驅動設備收到包,丟給netif的input函數,這個input函數也是設備驅動層來設置的。無非有兩個可能,一個是ip_input,另外一個就是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 functions ????? * (unless access to them is not locked). Other threads communicate with this * 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 * ) "lwIP", lwipTCP_STACK_SIZE); ?????? tcpip_init( NULL, NULL );??? ?????? sys_set_default_state(); } ? 從上面我們知道,tcpip_init創建tcpip_thread 在tcpip_thread的開始有如下代碼: (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.c文件中【src\cor\ipv4】,可以看到在這個文件中主要實現了3個函數,ip_input;ip_route;ip_output以及ip_output_if。下面分別來介紹它們。 ? ?????? 這些函數可以分成兩大類:接收和發送。下面就先從發送開始,首先要說的就是ip_output函數,這個也是發送過程中最重要的一個,它是被tcp層調用的,詳細可參見以上章節。 * Simple interface to ip_output_if. It finds the outgoing network * interface and calls upon ip_output_if to do the actual work. err_t? ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, ????????? u8_t ttl, u8_t tos, u8_t proto) { ? struct netif *netif; ? ? if ((netif = ip_route(dest)) == NULL) { ??? return ERR_RTE; ? } ? ? return ip_output_if(p, src, dest, ttl, tos, proto, netif); } 可以看到該函數的實現就像注釋所說的一樣,直接調用了ip_route和ip_outputif兩個函數。根據以往的經驗,先看下netif這個結構的實現情況: * 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 */ ? struct ip_addr ip_addr; ? struct ip_addr netmask; ? struct ip_addr gw; ? ? /** This function is called by the network device driver ?? *? to pass a packet up the TCP/IP stack. */ ? err_t (* input)(struct pbuf *p, struct netif *inp); ? ? /** 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. */ ? err_t (* output)(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr); ? ? /** 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. */ ? err_t (* linkoutput)(struct netif *netif, struct pbuf *p); ? #if LWIP_NETIF_STATUS_CALLBACK ? /** This function is called when the netif state is set to up or down ?? */ ? void (* status_callback)(struct netif *netif); #endif /* LWIP_NETIF_STATUS_CALLBACK */ ? #if LWIP_NETIF_LINK_CALLBACK ? /** This function is called when the netif link is set to up or down ?? */ ? void (* link_callback)(struct netif *netif); #endif /* LWIP_NETIF_LINK_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 */ ? ? /** number of bytes used in hwaddr */ ? u8_t hwaddr_len; ? ? /** link level hardware address of this interface */ ? u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; ? ? /** maximum transfer unit (in bytes) */ ? u16_t mtu; ? /** 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.*/ ? 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? */ ??? 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層的發送流程已經走完了。 ? ?????? 接下來就是ip層的接收過程了。剛才上面也有提到驅動設備收到包,丟給netif的input函數,這個input函數也是設備驅動層來設置的。無非有兩個可能,一個是ip_input,另外一個就是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 functions ????? * (unless access to them is not locked). Other threads communicate with this * 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 * ) "lwIP", lwipTCP_STACK_SIZE); ?????? tcpip_init( NULL, NULL );??? ?????? sys_set_default_state(); } ? 從上面我們知道,tcpip_init創建tcpip_thread 在tcpip_thread的開始有如下代碼: (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; ? }
總結
以上是生活随笔為你收集整理的LWIP之IP层实现(转载)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小米8屏幕占比是多少?(小米官方售后服务
- 下一篇: printf 格式控制符的完整格式