乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      lwip之IP(二)

       立志德美 2019-07-17

      1、ip數(shù)據(jù)包輸出

      (1)輸出ip報文
      err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
                u8_t ttl, u8_t tos, u8_t proto)
      {
        struct netif *netif;
      
      //查找合適的網(wǎng)卡接口,即ip地址在同一網(wǎng)段內(nèi)
        if ((netif = ip_route(dest)) == NULL) {
          return ERR_RTE;
        }
      
        return ip_output_if(p, src, dest, ttl, tos, proto, netif);
      }
      
      
      //填充IP報文頭部字節(jié),并判斷是否需要分片,最后發(fā)送至鏈路層
      err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
                   u8_t ttl, u8_t tos,
                   u8_t proto, struct netif *netif)
      {
      
        struct ip_hdr *iphdr;
        ip_addr_t dest_addr;
      
      
        if (dest != IP_HDRINCL) {
          u16_t ip_hlen = IP_HLEN;
      
          if (pbuf_header(p, IP_HLEN)) {
            return ERR_BUF;
          }
      
          iphdr = (struct ip_hdr *)p->payload;
      
          IPH_TTL_SET(iphdr, ttl);
          IPH_PROTO_SET(iphdr, proto);
          ip_addr_copy(iphdr->dest, *dest);
          IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
          IPH_TOS_SET(iphdr, tos);
          IPH_LEN_SET(iphdr, htons(p->tot_len));
          IPH_OFFSET_SET(iphdr, 0);
          IPH_ID_SET(iphdr, htons(ip_id));
      
          ++ip_id;
      
          if (ip_addr_isany(src)) {
            ip_addr_copy(iphdr->src, netif->ip_addr);
          } else {
            ip_addr_copy(iphdr->src, *src);
          }
      
          IPH_CHKSUM_SET(iphdr, 0);
          IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
      
        } else {
          /* IP header already included in p */
          iphdr = (struct ip_hdr *)p->payload;
          ip_addr_copy(dest_addr, iphdr->dest);
          dest = &dest_addr;
        }
      
      #if IP_FRAG
       //判斷是否分片
        if (netif->mtu && (p->tot_len > netif->mtu)) {
          return ip_frag(p, netif, dest);
        }
      #endif /* IP_FRAG */
        return netif->output(netif, p, dest);
      }
      
      (2)ip報文分片機制

      分片條件:

       if (netif->mtu && (p->tot_len > netif->mtu)) {
          return ip_frag(p, netif, dest);
        }

      分片函數(shù)ip_frag

      //靜態(tài)分片數(shù)組定義
      static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
      
      
      err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
      {
        struct pbuf *rambuf;
        struct pbuf *header;
        struct ip_hdr *iphdr;
        u16_t nfb;
        u16_t left, cop;
        u16_t mtu = netif->mtu;
        u16_t ofo, omf;
        u16_t last;
        u16_t poff = IP_HLEN;
        u16_t tmp;
      
      //pbuf類型為PBUF_REF
        rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
        if (rambuf == NULL) {
          return ERR_MEM;
        }
        rambuf->tot_len = rambuf->len = mtu;
        rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
      
        iphdr = (struct ip_hdr *)rambuf->payload;
        SMEMCPY(iphdr, p->payload, IP_HLEN);
      
        tmp = ntohs(IPH_OFFSET(iphdr));
        ofo = tmp & IP_OFFMASK;
        omf = tmp & IP_MF;
      
        left = p->tot_len - IP_HLEN;
        nfb = (mtu - IP_HLEN) / 8;
      
        while (left) {
          last = (left <= mtu - IP_HLEN);
      
          tmp = omf | (IP_OFFMASK & (ofo));
          if (!last) {
            tmp = tmp | IP_MF;
          }
      
          /* Fill this fragment */
          cop = last ? left : nfb * 8;
      
      
          poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
      
          /* Correct header */
          IPH_OFFSET_SET(iphdr, htons(tmp));
          IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
          IPH_CHKSUM_SET(iphdr, 0);
          IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
      
          if (last) {
            pbuf_realloc(rambuf, left + IP_HLEN);
          }
      
      //申請一個PBUF_RAM型的pbuf,以便以太網(wǎng)幀頭部預(yù)留空間
          header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
          if (header != NULL) {
            pbuf_chain(header, rambuf); //連接兩個pbuf
            netif->output(netif, header, dest);
            pbuf_free(header);
          } else {
            pbuf_free(rambuf);
            return ERR_MEM;
          }
      
          left -= cop;
          ofo += nfb;
        }
        pbuf_free(rambuf);
        return ERR_OK;
      }

      2、ip報文輸入

      (1)ip_input()

      該函數(shù)的作用是首先判別ip地址是否給本地網(wǎng)口,其次判別該ip報文是否為分片報文,最后將該報文傳輸至上次協(xié)議。

      err_t ip_input(struct pbuf *p, struct netif *inp)
      {
        struct ip_hdr *iphdr;
        struct netif *netif;
        u16_t iphdr_hlen;
        u16_t iphdr_len;
      
      //檢查IP報文的合法性
        iphdr = (struct ip_hdr *)p->payload;
        if (IPH_V(iphdr) != 4) {
          pbuf_free(p);
          return ERR_OK;
        }
      
        iphdr_hlen = IPH_HL(iphdr);  
        iphdr_hlen *= 4;         //ip報文的首部長度
        iphdr_len = ntohs(IPH_LEN(iphdr));  //ip報文的總長度
      
      //檢查pbuf的長度是否小于IP報文的長度,pbuf鏈表第一個buf長度是否大于ip首部長度
        if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
          pbuf_free(p);
          return ERR_OK;
        }
      //檢查ip報文校驗和
        if (inet_chksum(iphdr, iphdr_hlen) != 0) {
          return ERR_OK;
        }
      
        //刪除多余的填充字節(jié)
        pbuf_realloc(p, iphdr_len);
      
        ip_addr_copy(current_iphdr_dest, iphdr->dest);
        ip_addr_copy(current_iphdr_src, iphdr->src);
      
        {
        //檢查網(wǎng)絡(luò)接口ip是否與ip地址ip相同
          int first = 1;
          netif = inp;
          do {
            if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
      
              if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||
                  ip_addr_isbroadcast(&current_iphdr_dest, netif)) {
                break;
              }
            }
            if (first) {
              first = 0;
              netif = netif_list;
            } else {
              netif = netif->next;
            }
            if (netif == inp) {
              netif = netif->next;
            }
          } while(netif != NULL);
        }
      
      //檢查ip地址是否為多播包和廣播包,若是則丟棄
        {  if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||
               (ip_addr_ismulticast(&current_iphdr_src))) {
            pbuf_free(p);
            return ERR_OK;
          }
        }
      
      //ip地址與本地網(wǎng)絡(luò)接口ip不相同,則轉(zhuǎn)發(fā)出去
        if (netif == NULL) {
      
          if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
            ip_forward(p, iphdr, inp);  //轉(zhuǎn)發(fā)數(shù)據(jù)包
          } else
          {
            snmp_inc_ipinaddrerrors();
            snmp_inc_ipindiscards();
          }
          pbuf_free(p);
          return ERR_OK;
        }
        //檢查IP報文的偏移量是否為0,不為0則是分片報文
        if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
          p = ip_reass(p);     //重裝分片ip報文
          if (p == NULL) {
            return ERR_OK;
          }
      
          iphdr = (struct ip_hdr *)p->payload;
        }
      
      
        current_netif = inp;
        current_header = iphdr;
      
        //根據(jù)上層協(xié)議不同,傳輸報文至上層協(xié)議
          switch (IPH_PROTO(iphdr)) {
      #if LWIP_UDP
          case IP_PROTO_UDP:
            udp_input(p, inp);
            break;
      #endif /* LWIP_UDP */
      #if LWIP_TCP
          case IP_PROTO_TCP:
            snmp_inc_ipindelivers();
            tcp_input(p, inp);
            break;
      #endif /* LWIP_TCP */
      #if LWIP_ICMP
          case IP_PROTO_ICMP:
            snmp_inc_ipindelivers();
            icmp_input(p, inp);
            break;
      #endif /* LWIP_ICMP */
      #if LWIP_IGMP
          case IP_PROTO_IGMP:
            igmp_input(p, inp, &current_iphdr_dest);
            break;
      #endif /* LWIP_IGMP */
          default:
      #if LWIP_ICMP
            /* send ICMP destination protocol unreachable unless is was a broadcast */
            if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&
                !ip_addr_ismulticast(&current_iphdr_dest)) {
              p->payload = iphdr;
              icmp_dest_unreach(p, ICMP_DUR_PROTO);
            }
      #endif /* LWIP_ICMP */
            pbuf_free(p);
      
          }
        }
      
        current_netif = NULL;
        current_header = NULL;
        ip_addr_set_any(&current_iphdr_src);
        ip_addr_set_any(&current_iphdr_dest);
      
        return ERR_OK;
      }
      (2)ip_reass函數(shù)

      1、結(jié)構(gòu)體聲明

      struct ip_reassdata {
        struct ip_reassdata *next;
        struct pbuf *p;  //該數(shù)據(jù)報的數(shù)據(jù)鏈表
        struct ip_hdr iphdr; //該數(shù)據(jù)報的ip首部
        u16_t datagram_len; //已收到數(shù)據(jù)報的長度
        u8_t flags;  //是否收到最后一個分片
        u8_t timer;  //設(shè)置超時間隔
      };
      
      //ip報文pbuf連接幫助結(jié)構(gòu)體
      PACK_STRUCT_BEGIN
      struct ip_reass_helper {
        PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
        PACK_STRUCT_FIELD(u16_t start);
        PACK_STRUCT_FIELD(u16_t end);
      } PACK_STRUCT_STRUCT;
      PACK_STRUCT_END
      

      2、ip_reass

      struct pbuf *ip_reass(struct pbuf *p)
      {
        struct pbuf *r;
        struct ip_hdr *fraghdr;
        struct ip_reassdata *ipr;
        struct ip_reass_helper *iprh;
        u16_t offset, len;
        u8_t clen;
        struct ip_reassdata *ipr_prev = NULL;
      
        fraghdr = (struct ip_hdr*)p->payload;
      
        if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
          goto nullreturn;
        }
      
        //確定ip報文的偏移字節(jié),分片ip報文的數(shù)據(jù)長度
        offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
        len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
      
        /* Check if we are allowed to enqueue more datagrams. */
        clen = pbuf_clen(p);
        if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
      #if IP_REASS_FREE_OLDEST
          if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
              ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
      #endif /* IP_REASS_FREE_OLDEST */
          {
            goto nullreturn;
          }
        }
      
       //查找ip_reassdata重裝數(shù)據(jù)包鏈表,檢查該報文屬于哪個ip_reassdata
        for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
           if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
            break;
          }
          ipr_prev = ipr;
        }
      
        if (ipr == NULL) {
       //若ip_reassdata鏈表中無此報文的重裝結(jié)構(gòu)體,則新建一個ip_reassdata結(jié)構(gòu)體
          ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
          if(ipr == NULL) {
            goto nullreturn;
          }
        } else {
        //此分片報文為ip_reassdata結(jié)構(gòu)的第一個pbuf,則復(fù)制ip報文頭部到找到ipr
          if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && 
            ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
            SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
          }
        }
      
        //檢查分片ip報文為ip_reassdata的最后一個pbuf,即IP_MF = 0
        if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
          ipr->flags |= IP_REASS_FLAG_LASTFRAG;
          ipr->datagram_len = offset + len;//若為最后一個報文,確定整個ip報文的的數(shù)據(jù)長度
         }
      
      
        //分片ip報文插入與檢查
        if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
          ipr->datagram_len += IP_HLEN;
      
          處理除第一個pbuf以外的pbuf頭部
          r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
      
          /* copy the original ip header back to the first pbuf */
          fraghdr = (struct ip_hdr*)(ipr->p->payload);
          SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
          IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
          IPH_OFFSET_SET(fraghdr, 0);
          IPH_CHKSUM_SET(fraghdr, 0);
          IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
      
          p = ipr->p;
      
          /* chain together the pbufs contained within the reass_data list. */
          while(r != NULL) {
            iprh = (struct ip_reass_helper*)r->payload;
      
            /* hide the ip header for every succeding fragment */
            pbuf_header(r, -IP_HLEN);
            pbuf_cat(p, r);
            r = iprh->next_pbuf;
          }
      
          //刪除已經(jīng)打包好ip報文的ip_reassdata
          ip_reass_dequeue_datagram(ipr, ipr_prev);
      
      //更改全局變量的pbuf個數(shù)
          ip_reass_pbufcount -= pbuf_clen(p);
      
      //返回打包好的pbuf
          return p;
        }
      
        return NULL;
      
      nullreturn:
        pbuf_free(p);
        return NULL;
      }
      

      3、分片插入
      正對ip_reassdata鏈表上的某一個ip_reassdata 進行pbuf數(shù)據(jù)的插入排序和驗證ip_reassdata是否均接收到。

      static int ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
      {
        struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
        struct pbuf *q;
        u16_t offset,len;
        struct ip_hdr *fraghdr;
        int valid = 1;
      
        fraghdr = (struct ip_hdr*)new_p->payload; 
        len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
        offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
      
        iprh = (struct ip_reass_helper*)new_p->payload;
        iprh->next_pbuf = NULL;
        iprh->start = offset;
        iprh->end = offset + len;
      
       //輪詢整個ipr->p鏈表,并進行插入操作
        for (q = ipr->p; q != NULL;) {
          iprh_tmp = (struct ip_reass_helper*)q->payload;
          if (iprh->start < iprh_tmp->start) {
            iprh->next_pbuf = q;
            if (iprh_prev != NULL) {
              iprh_prev->next_pbuf = new_p;
            } else {
              /* fragment with the lowest offset */
              ipr->p = new_p;
            }
            break;
          } else if(iprh->start == iprh_tmp->start) {
            goto freepbuf;
          } else {
            if (iprh_prev != NULL) {
              if (iprh_prev->end != iprh_tmp->start) {
                valid = 0;
              }
            }
          }
          q = iprh_tmp->next_pbuf;
          iprh_prev = iprh_tmp;
        }
      
      
        if (q == NULL) {
          if (iprh_prev != NULL) {
              iprh_prev->next_pbuf = new_p;
            if (iprh_prev->end != iprh->start) {
              valid = 0;
            }
          } else {
            ipr->p = new_p;
          }
        }
      
        if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
          if (valid) {
            if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
              valid = 0;
            } else {
              /* and check that there are no wholes after this datagram */
              iprh_prev = iprh;
              q = iprh->next_pbuf;
              while (q != NULL) {
                iprh = (struct ip_reass_helper*)q->payload;
                if (iprh_prev->end != iprh->start) {
                  valid = 0;
                  break;
                }
                iprh_prev = iprh;
                q = iprh->next_pbuf;
              }
                  }
          }
      
          return valid;
        }
          return 0; /* not yet valid! */
      }

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多