lwip之数据收发流程_1
生活随笔
收集整理的這篇文章主要介紹了
lwip之数据收发流程_1
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
lwip從邏輯上看也是分為4層:鏈路層、網(wǎng)絡(luò)層(IP、ARP、(ICMP、IGMP這兩個(gè)協(xié)議是網(wǎng)絡(luò)層的補(bǔ)充協(xié)議,并不嚴(yán)格屬于網(wǎng)絡(luò)層))、傳輸層(TCP、UDP)、應(yīng)用層,基本等同TCP/IP,只是各層之間可以進(jìn)行交叉存取,沒有嚴(yán)格劃分。
協(xié)議匯總:1. ARP協(xié)議:根據(jù)IP地址獲取物理地址MAC的一個(gè)TCP/IP協(xié)議
一個(gè)典型的lwip系統(tǒng)包含3個(gè)進(jìn)程:首先是上層應(yīng)用程序進(jìn)程,然后是lwip協(xié)議棧進(jìn)程,最后是底層硬件數(shù)據(jù)包接收進(jìn)程動(dòng)態(tài)內(nèi)存管理:采用ucos-ii內(nèi)存管理系統(tǒng),即申請(qǐng)一塊內(nèi)存,分割成整數(shù)個(gè)大小相同的內(nèi)存塊
一.?? ?鏈路層當(dāng)主機(jī)A要與主機(jī)B通信時(shí),ARP協(xié)議可以將主機(jī)B的IP地址解析成主機(jī)B的MAC地址,工作流程如下:?? ?第一步:主機(jī)A先檢查自己的ARP緩沖,看是否存在主機(jī)B匹配的MAC地址,如果沒有,就會(huì)向外廣播一個(gè)ARP請(qǐng)求包第二步:其他主機(jī)收到后,發(fā)現(xiàn)請(qǐng)求的IP地址與自己的IP地址不匹配,則丟棄ARP請(qǐng)求第三步:主機(jī)B確定ARP請(qǐng)求中的IP地址與自己的IP地址匹配,則將主機(jī)A的IP地址和MAC地址映射到本地ARP緩存中第四步:主機(jī)B將包含其MAC地址的ARP回復(fù)發(fā)回給主機(jī)A第五步:主機(jī)A收到從主機(jī)B發(fā)來的ARP回復(fù)時(shí),會(huì)將主機(jī)B的IP地址和MAC地址映射更新到本地ARP緩存中。主機(jī)B的MAC地址一旦確定,主機(jī)A就可以向主機(jī)B發(fā)送IP通信了連接鏈路層和網(wǎng)絡(luò)層的紐帶:以太網(wǎng)數(shù)據(jù)包接收進(jìn)程tcpip_threadstatic void tcpip_thread(void *arg){struct tcpip_msg *msg;?? ??? ?// 消息來自于網(wǎng)卡中斷while(1){// 該任務(wù)阻塞在這里接收要處理的消息,當(dāng)有數(shù)據(jù)包到來時(shí),網(wǎng)卡芯片中斷函數(shù)接收數(shù)據(jù),并post消息,中斷退出后,該任務(wù)獲取消息sys_timeouts_mbox_fetch(&mbox, (void **)&msg);?? ?// 判斷本條消息的類型,只關(guān)注數(shù)據(jù)包消息TCPIP_MSG_INPKTswitch (msg->type){case TCPIP_MSG_INPKT:?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 數(shù)據(jù)包消息if(msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET))ethernet_input(msg->msg.inp.p,msg->msg.inp.netif);?? ?// 如果支持ARP,先進(jìn)行ARP處理,再判斷是否遞交IP層,對(duì)于IP數(shù)據(jù)包,這里2個(gè)選擇最終都要調(diào)用ip_input進(jìn)入IP層elseip_input(msg->msg.inp.p, msg->msg.inp.netif);?? ??? ??? ?// 否則直接遞交IP層,ip_input為IP層主要函數(shù),解析見下文,這里直接調(diào)用ip_input存在問題,有誤,需要先以太網(wǎng)數(shù)據(jù)包指針,使掠過包頭,指向IP協(xié)議包頭memp_free(MEMP_TCPIP_MSG_INPKT, msg);?? ??? ??? ??? ??? ??? ?// 釋放消息內(nèi)存break;case TCPIP_MSG_TIMEOUT:?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 超時(shí)消息sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);memp_free(MEMP_TCPIP_MSG_API, msg);break;default:break;}}}err_t ethernet_input(struct pbuf *p,struct netif *netif){struct eth_hdr *ethhdr;?? ??? ??? ??? ??? ?// 以太網(wǎng)數(shù)據(jù)包頭結(jié)構(gòu)體u16_t type;s16_t ip_hdr_offset = SIZEOF_ETH_HDR;?? ?// 包頭固定值14字節(jié)ethhdr = (eth_hdr *)p->payload;type = htons(ethhdr->type);switch(type){case ETHTYPE_IP:?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// IP數(shù)據(jù)包etharp_ip_input(netif,p);?? ??? ??? ??? ??? ??? ??? ??? ??? ?// 使用收到的IP包更新ARP緩存表,詳見《lwip之ARP協(xié)議》pbuf_header(p, -ip_hdr_offset);?? ??? ??? ??? ??? ??? ??? ??? ?// 調(diào)整以太網(wǎng)數(shù)據(jù)包指針,使掠過包頭,指向IP協(xié)議包頭ip_input(p,netif);?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 提交IP層,ip_input為IP層主要函數(shù),解析見下文case ETHTYPE_ARP:?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// ARP數(shù)據(jù)包etharp_arp_input(netif,(struct eth_addr *)netif->hwaddr,p);?? ?// ARP數(shù)據(jù)包處理,第二個(gè)形參是本機(jī)MAC,詳見《lwip之ARP協(xié)議》break;default:break;}}注:消息結(jié)構(gòu)體struct tcpip_msg {enum tcpip_msg_type type;?? ??? ??? ??? ?// 本條消息的類型:TCPIP_MSG_INPKT - 數(shù)據(jù)包消息,TCPIP_MSG_TIMEOUT - 超時(shí)消息sys_sem_t *sem;?? ??? ??? ??? ??? ??? ??? ?// 事件控制塊ECBunion{struct api_msg *apimsg;struct netifapi_msg *netifapimsg;struct {struct pbuf *p;struct netif *netif;} inp;?? ??? ??? ??? ??? ??? ??? ??? ?// inp結(jié)構(gòu)體最重要,內(nèi)含數(shù)據(jù)包內(nèi)容結(jié)構(gòu)、網(wǎng)絡(luò)接口結(jié)構(gòu)struct {tcpip_callback_fn function;void *ctx;} cb;struct {u32_t msecs;sys_timeout_handler h;void *arg;} tmo;}msg;}----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------?? ?
二. 網(wǎng)絡(luò)層lwip使用一個(gè)ip_hdr的結(jié)構(gòu)體來描述IP協(xié)議包頭:struct ip_hdr{u16_t _v_hl_tos;?? ?// 包含4位版本號(hào)(IPv4 - 4,IPv6 - 6)、4位IP包頭長(zhǎng)(通常為5*4,即本結(jié)構(gòu)體大小)、8位服務(wù)類型u16_t _len;?? ??? ??? ?// 整個(gè)IP數(shù)據(jù)包長(zhǎng)度u16_t _id;?? ??? ??? ?// 16位標(biāo)識(shí)用于標(biāo)識(shí)IP層發(fā)出的每一份IP報(bào)文,自增u16_t _offset;?? ??? ?// 包含3位標(biāo)志和13位片偏移,IP數(shù)據(jù)包分片時(shí)使用u8_t _ttl;?? ??? ??? ?// TTL描述該IP數(shù)據(jù)包最多能被轉(zhuǎn)發(fā)的次數(shù),自減u8_t _proto;?? ??? ?// 協(xié)議字段用于描述該IP數(shù)據(jù)包的上層協(xié)議,0x01 - ICMP,0x02 - IGMP,0x06 - TCP,0x17 - UDPu16_t _chksum;?? ??? ?// 16位的IP首部校驗(yàn)和ip_addr_p_t src;?? ?// 源IPip_addr_p_t dest;?? ?// 目的IP}ip_input為IP層主干函數(shù),完成了IP層數(shù)據(jù)包處理(核心工作就是IP地址匹配;得到完整數(shù)據(jù)包),然后將合適的數(shù)據(jù)包提交給上層,這里的p->payload已經(jīng)越過了14字節(jié)包頭,指向了IP頭err_t ip_input(struct pbuf *p,struct netif *inp){struct ?? ?ip_hdr *iphdr;?? ?// 指向IP包頭的指針struct ?? ?netif *netif;?? ?// 指向netif硬件網(wǎng)絡(luò)接口設(shè)備描述符的指針u16_t?? ?iphdr_hlen;?? ??? ?// IP包頭的長(zhǎng)度,通常是固定20字節(jié)u16_t?? ?iphdr_len;?? ??? ?// 整個(gè)IP包長(zhǎng),包含IP包頭、上層協(xié)議頭、數(shù)據(jù)// 取出 IP數(shù)據(jù)包頭iphdr = (struct ip_hdr *)p->payload;// 檢查IP包頭中的版本號(hào)字段,IPv4 - 4,IPv6 - 6if(IPH_V(iphdr) != 4){pbuf_free(p);return ERR_OK;?? ?}// 提取IP包頭中的頭長(zhǎng)度字段,通常固定值20字節(jié)iphdr_hlen = IPH_HL(iphdr);iphdr_hlen *= 4;// 提取IP包頭中的IP包總長(zhǎng)度字段,確保小于遞交上來的pbuf包中的總長(zhǎng)度iphdr_len = ntohs(IPH_LEN(iphdr));if(iphdr_len > p->len || iphdr_len > p->tot_len){pbuf_free(p);return ERR_OK;?? ?}// 校驗(yàn)IP數(shù)據(jù)包頭if (inet_chksum(iphdr, iphdr_hlen) != 0){pbuf_free(p);return ERR_OK;?? ?}// 對(duì)IP數(shù)據(jù)報(bào)進(jìn)行截?cái)?#xff0c;得到完整無(wú)冗余IP數(shù)據(jù)包pbuf_realloc(p, iphdr_len);// 遍歷netif_list鏈表(系統(tǒng)存在2個(gè)網(wǎng)卡設(shè)備,意味著有2個(gè)netif分別用于描述它們,也意味著本機(jī)有2個(gè)IP地址,所以此時(shí)就需要遍歷),檢測(cè)IP數(shù)據(jù)包中的目的IP是否與本機(jī)相符,不符則丟棄或轉(zhuǎn)發(fā)ip_addr_copy(current_iphdr_dest, iphdr->dest);ip_addr_copy(current_iphdr_src, iphdr->src);int first = 1;netif = inp;do{// 通過netif->flag標(biāo)志位判斷該網(wǎng)卡設(shè)備是否配置且使能,同時(shí)判斷本機(jī)IP是否有效if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))){// 如果目的IP地址與本機(jī)IP地址匹配或者目的IP地址是廣播類型,意味著成功匹配,退出遍歷if(ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) || ip_addr_isbroadcast(¤t_iphdr_dest, netif))?? ?{break;?? ?}}if (first){first = 0;netif = netif_list;}else{netif = netif->next;}if (netif == inp){netif = netif->next;}}while(netif != NULL);//? 如果該數(shù)據(jù)包中的源IP地址是廣播IP,則直接丟棄if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) || (ip_addr_ismulticast(¤t_iphdr_src))){pbuf_free(p);return ERR_OK;}// 遍歷完成以后,如果依舊沒有找到匹配的netif結(jié)構(gòu)體,說明該數(shù)據(jù)包不是給本機(jī)的,轉(zhuǎn)發(fā)或丟棄(這里直接丟棄)if (netif == NULL){pbuf_free(p);return ERR_OK;}// 判斷該IP包是否是分片數(shù)據(jù)包// 如果是分片數(shù)據(jù)包,則需要將該分片包暫存,等接收完所有分片包后,統(tǒng)一將整個(gè)數(shù)據(jù)包提交給上層if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0){// 在這里重組接收到的分片包,如果還沒接收完整,p=NULLp = ip_reass(p);// 如果分片包還沒接收完整,本函數(shù)結(jié)束if (p == NULL){return ERR_OK;}// 如果分片包接收完整,這時(shí)的p已經(jīng)是一個(gè)完整的數(shù)據(jù)包結(jié)構(gòu)體了// 再?gòu)膒中獲取完整的IP包iphdr = (struct ip_hdr *)p->payload;?? ??? ??? ?}// 能到達(dá)這一步的數(shù)據(jù)包必然是未分片的或經(jīng)過分片重組完整后的數(shù)據(jù)包c(diǎn)urrent_netif = inp;current_header = iphdr;if (raw_input(p, inp) == 0){// 根據(jù)IP數(shù)據(jù)包頭中的協(xié)議字段判斷該數(shù)據(jù)包應(yīng)該被遞交給上層哪個(gè)協(xié)議switch (IPH_PROTO(iphdr)){case IP_PROTO_UDP:?? ?// UDP協(xié)議udp_input(p, inp);?? ?// 從這里進(jìn)入傳輸層,解析見下文break;?? ?case IP_PROTO_TCP:?? ?// TCP協(xié)議tcp_input(p, inp);?? ?// 從這里進(jìn)入傳輸層,解析見下文break;case IP_PROTO_ICMP:?? ?// ICMP協(xié)議icmp_input(p, inp);break;case IP_PROTO_IGMP:?? ?// IGMP協(xié)議igmp_input(p, inp, ¤t_iphdr_dest);break;default:?? ??? ??? ?// 如果都不是// 如果不是廣播數(shù)據(jù)包,返回一個(gè)協(xié)議不可達(dá)ICMP數(shù)據(jù)包給源主機(jī)if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) && !ip_addr_ismulticast(¤t_iphdr_dest)){p->payload = iphdr;icmp_dest_unreach(p, ICMP_DUR_PROTO);}?? ?pbuf_free(p);?? ??? ?}?? ?}current_netif = NULL;current_header = NULL;ip_addr_set_any(¤t_iphdr_src);ip_addr_set_any(¤t_iphdr_dest);}IP層的補(bǔ)充協(xié)議:ICMP、IGMP這時(shí)候主機(jī)A學(xué)到了主機(jī)B的MAC地址,就把這個(gè)MAC封裝到ICMP協(xié)議中向主機(jī)B發(fā)送,報(bào)文格式如下:包頭14字節(jié)?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?:因?yàn)镮CMP協(xié)議包屬于網(wǎng)絡(luò)層協(xié)議,所以幀類型是0x0800+?? ?ICMP協(xié)議頭(主要是二級(jí)協(xié)議類型、源IP、目的IP)?? ?:二級(jí)協(xié)議類型ICMP對(duì)應(yīng)值0x01+?? ?ICMP協(xié)議主體(主要是一個(gè)類別)?? ??? ??? ??? ??? ?:類別取值0x00 - 這是一條回應(yīng)信息?? ?0x03 - 目的不可達(dá)?? ?0x08 - 請(qǐng)求回應(yīng)信息---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
?
總結(jié)
以上是生活随笔為你收集整理的lwip之数据收发流程_1的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在Linux下写无线网卡的驱动
- 下一篇: lwip之数据收发流程_2