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

📄 ip_frag.c

📁 lwip-1.4.0
💻 C
📖 第 1 页 / 共 2 页
字号:
          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 ((IPH_OFFSET(fraghdr) & PP_NTOHS(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)];#else /* IP_FRAG_USES_STATIC_BUF */#if !LWIP_NETIF_TX_SINGLE_PBUF/** Allocate a new struct pbuf_custom_ref */static struct pbuf_custom_ref*ip_frag_alloc_pbuf_custom_ref(void){  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);}/** Free a struct pbuf_custom_ref */static voidip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p){  LWIP_ASSERT("p != NULL", p != NULL);  memp_free(MEMP_FRAG_PBUF, p);}/** Free-callback function to free a 'struct pbuf_custom_ref', called by * pbuf_free. */static voidipfrag_free_pbuf_custom(struct pbuf *p){  struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;  LWIP_ASSERT("pcr != NULL", pcr != NULL);  LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);  if (pcr->original != NULL) {    pbuf_free(pcr->original);  }  ip_frag_free_pbuf_custom_ref(pcr);}#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */#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, ip_addr_t *dest){  struct pbuf *rambuf;#if IP_FRAG_USES_STATIC_BUF  struct pbuf *header;#else#if !LWIP_NETIF_TX_SINGLE_PBUF  struct pbuf *newpbuf;#endif  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 && !LWIP_NETIF_TX_SINGLE_PBUF  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 = (struct ip_hdr *)rambuf->payload;  SMEMCPY(iphdr, p->payload, IP_HLEN);#else /* IP_FRAG_USES_STATIC_BUF */  original_iphdr = (struct ip_hdr *)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 */#if LWIP_NETIF_TX_SINGLE_PBUF    rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);    if (rambuf == NULL) {      return ERR_MEM;    }    LWIP_ASSERT("this needs a pbuf in one piece!",      (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));    poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);    /* make room for the IP header */    if(pbuf_header(rambuf, IP_HLEN)) {      pbuf_free(rambuf);      return ERR_MEM;    }    /* fill in the IP header */    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);    iphdr = rambuf->payload;#else /* LWIP_NETIF_TX_SINGLE_PBUF */    /* 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 = (struct ip_hdr *)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) {      struct pbuf_custom_ref *pcr;      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;      /* Is this pbuf already empty? */      if (!newpbuflen) {        p = p->next;        continue;      }      pcr = ip_frag_alloc_pbuf_custom_ref();      if (pcr == NULL) {        pbuf_free(rambuf);        return ERR_MEM;      }      /* Mirror this pbuf, although we might not need all of it. */      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);      if (newpbuf == NULL) {        ip_frag_free_pbuf_custom_ref(pcr);        pbuf_free(rambuf);        return ERR_MEM;      }      pbuf_ref(p);      pcr->original = p;      pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;      /* 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 /* LWIP_NETIF_TX_SINGLE_PBUF */#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 + -