⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip_frag.c

📁 freescale k40/k60 freertos-lwip例程
💻 C
📖 第 1 页 / 共 2 页
字号:
      iprh_prev->next_pbuf = new_p;      if (iprh_prev->end != iprh->start) {        valid = 0;      }    } else {#if IP_REASS_CHECK_OVERLAP      LWIP_ASSERT("no previous fragment, this must be the first fragment!",        ipr->p == NULL);#endif /* IP_REASS_CHECK_OVERLAP */      /* this is the first fragment we ever received for this ip datagram */      ipr->p = new_p;    }  }  /* At this point, the validation part begins: */  /* If we already received the last fragment */  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {    /* and had no wholes so far */    if (valid) {      /* then check if the rest of the fragments is here */      /* Check if the queue starts with the first datagram */      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;        }        /* if still valid, all fragments are received         * (because to the MF==0 already arrived */        if (valid) {          LWIP_ASSERT("sanity check", ipr->p != NULL);          LWIP_ASSERT("sanity check",            ((struct ip_reass_helper*)ipr->p->payload) != iprh);          LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",            iprh->next_pbuf == NULL);          LWIP_ASSERT("validate_datagram:datagram end!=datagram len",            iprh->end == ipr->datagram_len);        }      }    }    /* If valid is 0 here, there are some fragments missing in the middle     * (since MF == 0 has already arrived). Such datagrams simply time out if     * no more fragments are received... */    return valid;  }  /* If we come here, not all fragments were received, yet! */  return 0; /* not yet valid! */#if IP_REASS_CHECK_OVERLAPfreepbuf:  ip_reass_pbufcount -= pbuf_clen(new_p);  pbuf_free(new_p);  return 0;#endif /* IP_REASS_CHECK_OVERLAP */}/** * Reassembles incoming IP fragments into an IP datagram. * * @param p points to a pbuf chain of the fragment * @return NULL if reassembly is incomplete, ? otherwise */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;  IPFRAG_STATS_INC(ip_frag.recv);  snmp_inc_ipreasmreqds();  fraghdr = (struct ip_hdr*)p->payload;  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {    LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));    IPFRAG_STATS_INC(ip_frag.err);    goto nullreturn;  }  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 */    {      /* No datagram could be freed and still too many pbufs enqueued */      LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));      IPFRAG_STATS_INC(ip_frag.memerr);      /* @todo: send ICMP time exceeded here? */      /* drop this pbuf */      goto nullreturn;    }  }  /* Look for the datagram the fragment belongs to in the current datagram queue,   * remembering the previous in the queue for later dequeueing. */  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {    /* Check if the incoming fragment matches the one currently present       in the reassembly buffer. If so, we proceed with copying the       fragment into the buffer. */    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",        ntohs(IPH_ID(fraghdr))));      IPFRAG_STATS_INC(ip_frag.cachehit);      break;    }    ipr_prev = ipr;  }  if (ipr == NULL) {  /* Enqueue a new datagram into the datagram queue */    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);    /* Bail if unable to enqueue */    if(ipr == NULL) {      goto nullreturn;    }  } else {    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&       ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {      /* ipr->iphdr is not the header from the first fragment, but fraghdr is       * -> copy fraghdr into ipr->iphdr since we want to have the header       * of the first fragment (for ICMP time exceeded and later, for copying       * all options, if supported)*/      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);    }  }  /* Track the current number of pbufs current 'in-flight', in order to limit   the number of fragments that may be enqueued at any one time */  ip_reass_pbufcount += clen;  /* At this point, we have either created a new entry or pointing    * to an existing one */  /* check for 'no more fragments', and update queue entry*/  if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {    ipr->flags |= IP_REASS_FLAG_LASTFRAG;    ipr->datagram_len = offset + len;    LWIP_DEBUGF(IP_REASS_DEBUG,     ("ip_reass: last fragment seen, total len %"S16_F"\n",      ipr->datagram_len));  }  /* find the right place to insert this pbuf */  /* @todo: trim pbufs if fragments are overlapping */  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {    /* the totally last fragment (flag more fragments = 0) was received at least     * once AND all fragments are received */    ipr->datagram_len += IP_HLEN;    /* save the second pbuf before copying the header over the pointer */    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);    /* @todo: do we need to set calculate the correct checksum? */    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;    }    /* release the sources allocate for the fragment queue entry */    ip_reass_dequeue_datagram(ipr, ipr_prev);    /* and adjust the number of pbufs currently queued for reassembly. */    ip_reass_pbufcount -= pbuf_clen(p);    /* Return the pbuf chain */    return p;  }  /* the datagram is not (yet?) reassembled completely */  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));  return NULL;nullreturn:  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));  IPFRAG_STATS_INC(ip_frag.drop);  pbuf_free(p);  return NULL;}#endif /* IP_REASSEMBLY */#if IP_FRAG#if IP_FRAG_USES_STATIC_BUFstatic u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];#endif /* IP_FRAG_USES_STATIC_BUF *//** * Fragment an IP datagram if too large for the netif. * * Chop the datagram in MTU sized chunks and send them in order * by using a fixed size static memory buffer (PBUF_REF) or * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). * * @param p ip packet to send * @param netif the netif on which to send * @param dest destination ip address to which to send * * @return ERR_OK if sent successfully, err_t otherwise */err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest){  struct pbuf *rambuf;#if IP_FRAG_USES_STATIC_BUF  struct pbuf *header;#else  struct pbuf *newpbuf;  struct ip_hdr *original_iphdr;#endif  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;#if !IP_FRAG_USES_STATIC_BUF  u16_t newpbuflen = 0;  u16_t left_to_copy;#endif  /* Get a RAM based MTU sized pbuf */#if IP_FRAG_USES_STATIC_BUF  /* When using a static buffer, we use a PBUF_REF, which we will   * use to reference the packet (without link header).   * Layer and length is irrelevant.   */  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);  if (rambuf == NULL) {    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));    return ERR_MEM;  }  rambuf->tot_len = rambuf->len = mtu;  rambuf->payload = LWIP_MEM_ALIGN((void *)buf);  /* Copy the IP header in it */  iphdr = rambuf->payload;  SMEMCPY(iphdr, p->payload, IP_HLEN);#else /* IP_FRAG_USES_STATIC_BUF */  original_iphdr = p->payload;  iphdr = original_iphdr;#endif /* IP_FRAG_USES_STATIC_BUF */  /* Save original offset */  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);    /* Set new offset and MF flag */    tmp = omf | (IP_OFFMASK & (ofo));    if (!last)      tmp = tmp | IP_MF;    /* Fill this fragment */    cop = last ? left : nfb * 8;#if IP_FRAG_USES_STATIC_BUF    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);#else /* IP_FRAG_USES_STATIC_BUF */    /* When not using a static buffer, create a chain of pbufs.     * The first will be a PBUF_RAM holding the link and IP header.     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,     * but limited to the size of an mtu.     */    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);    if (rambuf == NULL) {      return ERR_MEM;    }    LWIP_ASSERT("this needs a pbuf in one piece!",                (p->len >= (IP_HLEN)));    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);    iphdr = rambuf->payload;    /* Can just adjust p directly for needed offset. */    p->payload = (u8_t *)p->payload + poff;    p->len -= poff;    left_to_copy = cop;    while (left_to_copy) {      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;      /* Is this pbuf already empty? */      if (!newpbuflen) {        p = p->next;        continue;      }      newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);      if (newpbuf == NULL) {        pbuf_free(rambuf);        return ERR_MEM;      }      /* Mirror this pbuf, although we might not need all of it. */      newpbuf->payload = p->payload;      newpbuf->len = newpbuf->tot_len = newpbuflen;      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain       * so that it is removed when pbuf_dechain is later called on rambuf.       */      pbuf_cat(rambuf, newpbuf);      left_to_copy -= newpbuflen;      if (left_to_copy)        p = p->next;    }    poff = newpbuflen;#endif /* IP_FRAG_USES_STATIC_BUF */    /* 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 IP_FRAG_USES_STATIC_BUF    if (last)      pbuf_realloc(rambuf, left + IP_HLEN);    /* This part is ugly: we alloc a RAM based pbuf for      * the link level header for each chunk and then      * free it.A PBUF_ROM style pbuf for which pbuf_header     * worked would make things simpler.     */    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);    if (header != NULL) {      pbuf_chain(header, rambuf);      netif->output(netif, header, dest);      IPFRAG_STATS_INC(ip_frag.xmit);      snmp_inc_ipfragcreates();      pbuf_free(header);    } else {      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));      pbuf_free(rambuf);      return ERR_MEM;    }#else /* IP_FRAG_USES_STATIC_BUF */    /* No need for separate header pbuf - we allowed room for it in rambuf     * when allocated.     */    netif->output(netif, rambuf, dest);    IPFRAG_STATS_INC(ip_frag.xmit);    /* Unfortunately we can't reuse rambuf - the hardware may still be     * using the buffer. Instead we free it (and the ensuing chain) and     * recreate it next time round the loop. If we're lucky the hardware     * will have already sent the packet, the free will really free, and     * there will be zero memory penalty.     */        pbuf_free(rambuf);#endif /* IP_FRAG_USES_STATIC_BUF */    left -= cop;    ofo += nfb;  }#if IP_FRAG_USES_STATIC_BUF  pbuf_free(rambuf);#endif /* IP_FRAG_USES_STATIC_BUF */  snmp_inc_ipfragoks();  return ERR_OK;}#endif /* IP_FRAG */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -