日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

LWIP之IP层实现(转载)

發(fā)布時(shí)間:2023/12/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LWIP之IP层实现(转载) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文地址:http://bluefish.blog.51cto.com/214870/158417
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
這一部分的實(shí)現(xiàn)都是在ip.c文件中【src\cor\ipv4】,可以看到在這個(gè)文件中主要實(shí)現(xiàn)了3個(gè)函數(shù),ip_inputip_routeip_output以及ip_output_if。下面分別來介紹它們。 ? ?????? 這些函數(shù)可以分成兩大類:接收和發(fā)送。下面就先從發(fā)送開始,首先要說的就是ip_output函數(shù),這個(gè)也是發(fā)送過程中最重要的一個(gè),它是被tcp層調(diào)用的,詳細(xì)可參見以上章節(jié)。 * 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); } 可以看到該函數(shù)的實(shí)現(xiàn)就像注釋所說的一樣,直接調(diào)用了ip_routeip_outputif兩個(gè)函數(shù)。根據(jù)以往的經(jīng)驗(yàn),先看下netif這個(gè)結(jié)構(gòu)的實(shí)現(xiàn)情況: * 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//這幾個(gè)是要用驅(qū)動(dòng)層填寫的 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 */ }; 該結(jié)構(gòu)體實(shí)現(xiàn)在【src\include\lwip\netif.h】,注意到該結(jié)構(gòu)體成員中有3個(gè)函數(shù)指針變量。好了,這個(gè)結(jié)構(gòu)體先做一大體了解。用到的時(shí)候再詳細(xì)講。 ?????? 接下來先看下ip_route函數(shù)的實(shí)現(xiàn): * 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; } 可以說這個(gè)函數(shù)的實(shí)現(xiàn)很簡(jiǎn)單,且作用也很容易看懂,就像其注釋所說的一樣。不過在這個(gè)函數(shù)中我們還是發(fā)現(xiàn)了一些什么,對(duì)了,就是struct netif *netif_list;src\core\netif.c】的使用。既然這里都使用了這個(gè)網(wǎng)絡(luò)接口鏈表,那它是在哪里被初始化的呢? ?????? 好了,首先我們發(fā)現(xiàn)在netif_add函數(shù)中有對(duì)netif_list的調(diào)用,netif_add是被do_netifapi_netif_add函數(shù)調(diào)用的,而do_netifapi_netif_add是在netifapi_netif_add中通過netifapi_msgTCPIP_NETIFAPI調(diào)用的。問題似乎很清楚,只要找到nnetifapi_netif_add是被誰調(diào)用的就好了,然而,搜遍整個(gè)工程也沒有發(fā)現(xiàn)這個(gè)函數(shù)的影子,除了一個(gè)聲明一個(gè)實(shí)現(xiàn)外。My god,又進(jìn)入死胡同了?好吧,這里先標(biāo)識(shí)一下,待解【見下面的解釋】 ? ?????? 我們接著看ip_output_if這個(gè)函數(shù),具體函數(shù)可參考【src\core\ipv4\ip.c】。它的函數(shù)定義注釋如下: * 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); 嗯,看來這個(gè)netif還是關(guān)鍵啊,如果估計(jì)不錯(cuò)的話,接收的時(shí)候也要用到這個(gè)結(jié)構(gòu)的。那就看它在什么地方被賦值的吧。又經(jīng)過一番搜索,看來在目前的代碼中是找不到的了。查看lwip協(xié)議棧的設(shè)計(jì)與實(shí)現(xiàn),特別是網(wǎng)絡(luò)接口層的那一節(jié),終于明白了,原來這些是要有設(shè)備驅(qū)動(dòng)來參與的:【一下為引用】 當(dāng)收到一個(gè)信息包時(shí),設(shè)備驅(qū)動(dòng)程序調(diào)用input指針指向的函數(shù)。網(wǎng)絡(luò)接口通過output指針連接到設(shè)備驅(qū)動(dòng)。這個(gè)指針指向設(shè)備驅(qū)動(dòng)中一個(gè)向物理網(wǎng)絡(luò)發(fā)送信息包的函數(shù),當(dāng)信息包包被發(fā)送時(shí)由IP層調(diào)用,這個(gè)字段由設(shè)備驅(qū)動(dòng)的初始設(shè)置函數(shù)填充。 ?????? 嗯,那就這樣吧,到這里我們可以說IP層的發(fā)送流程已經(jīng)走完了。 ? ?????? 接下來就是ip層的接收過程了。剛才上面也有提到驅(qū)動(dòng)設(shè)備收到包,丟給netifinput函數(shù),這個(gè)input函數(shù)也是設(shè)備驅(qū)動(dòng)層來設(shè)置的。無非有兩個(gè)可能,一個(gè)是ip_input,另外一個(gè)就是tcpip_input。因?yàn)?span style="color:#000000;" lang="en-us">tcpip_input函數(shù)的處理是最終調(diào)用到了ip_input【在tcpip_thread中】。按照正常情況下應(yīng)該是ip_input函數(shù)的,我們先來看下這個(gè)函數(shù)。 * 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) 該函數(shù)大致的處理過程是:處理ip包頭;找到對(duì)應(yīng)的netif;檢查如果是廣播或多播包,則丟掉;如果是tcp協(xié)議的話就直接調(diào)用了tcp_input函數(shù)處理數(shù)據(jù)。 ? ?????? 到此,ip層的東西大致就說完了。最后,由于tcpip層的東西都說完了,所以此時(shí)我們順便看下,tcpip的整體實(shí)現(xiàn),這個(gè)主要是在src\api\tcpip.c文件中實(shí)現(xiàn)。我們知道發(fā)送過程是由socket直接調(diào)用的,所以這個(gè)文件中不涉及,說白了,這個(gè)文件主要是涉及到整個(gè)接收過程。這里實(shí)現(xiàn)的函數(shù)有tcpip_input,和tcpip_thread以及tcpip_init函數(shù)。 Tcpip_init函數(shù)很簡(jiǎn)單就是創(chuàng)建系統(tǒng)線程(sys_thread_newtcpip_thread Tcpip_thread函數(shù)的注釋如下: ?????? * 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. 它的整個(gè)過程就是一直從mbox中取出msg,對(duì)各種msg的一個(gè)處理過程。 Tcpip_input函數(shù),是在tcpip_thread中被調(diào)用的處理設(shè)備驅(qū)動(dòng)接收到的信息包,并調(diào)用 ip_input來進(jìn)一步處理。 ? 整個(gè)啟動(dòng)過程: 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創(chuàng)建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的實(shí)現(xiàn) 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; ? }

總結(jié)

以上是生活随笔為你收集整理的LWIP之IP层实现(转载)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。