68#ifndef IP_REASS_CHECK_OVERLAP
69#define IP_REASS_CHECK_OVERLAP 1
76#ifndef IP_REASS_FREE_OLDEST
77#define IP_REASS_FREE_OLDEST 1
80#define IP_REASS_FLAG_LASTFRAG 0x01
82#define IP_REASS_VALIDATE_TELEGRAM_FINISHED 1
83#define IP_REASS_VALIDATE_PBUF_QUEUED 0
84#define IP_REASS_VALIDATE_PBUF_DROPPED -1
94#ifdef PACK_STRUCT_USE_INCLUDES
95# include "arch/bpstruct.h"
98struct ip_reass_helper {
104#ifdef PACK_STRUCT_USE_INCLUDES
105# include "arch/epstruct.h"
108#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
109 (ip4_addr_eq(&(iphdrA)->src, &(iphdrB)->src) && \
110 ip4_addr_eq(&(iphdrA)->dest, &(iphdrB)->dest) && \
111 IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
114static struct ip_reassdata *reassdatagrams;
115static u16_t ip_reass_pbufcount;
118static void ip_reass_dequeue_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev);
119static int ip_reass_free_complete_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev);
130 struct ip_reassdata *r, *prev = NULL;
138 LWIP_DEBUGF(
IP_REASS_DEBUG, (
"ip_reass_tmr: timer dec %"U16_F
"\n", (u16_t)r->timer));
143 struct ip_reassdata *tmp;
149 ip_reass_free_complete_datagram(tmp, prev);
164ip_reass_free_complete_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev)
166 u16_t pbufs_freed = 0;
169 struct ip_reass_helper *iprh;
171 LWIP_ASSERT(
"prev != ipr", prev != ipr);
173 LWIP_ASSERT(
"prev->next == ipr", prev->next == ipr);
176 MIB2_STATS_INC(mib2.ipreasmfails);
178 iprh = (
struct ip_reass_helper *)ipr->p->payload;
179 if (iprh->start == 0) {
183 ipr->p = iprh->next_pbuf;
185 SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
188 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
189 pbufs_freed = (u16_t)(pbufs_freed + clen);
199 iprh = (
struct ip_reass_helper *)p->payload;
203 clen = pbuf_clen(pcur);
204 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
205 pbufs_freed = (u16_t)(pbufs_freed + clen);
209 ip_reass_dequeue_datagram(ipr, prev);
210 LWIP_ASSERT(
"ip_reass_pbufcount >= pbufs_freed", ip_reass_pbufcount >= pbufs_freed);
211 ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount - pbufs_freed);
216#if IP_REASS_FREE_OLDEST
227ip_reass_remove_oldest_datagram(
struct ip_hdr *fraghdr,
int pbufs_needed)
232 struct ip_reassdata *r, *oldest, *prev, *oldest_prev;
233 int pbufs_freed = 0, pbufs_freed_current;
245 if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
248 if (oldest == NULL) {
251 }
else if (r->timer <= oldest->timer) {
257 if (r->next != NULL) {
262 if (oldest != NULL) {
263 pbufs_freed_current = ip_reass_free_complete_datagram(oldest, oldest_prev);
264 pbufs_freed += pbufs_freed_current;
266 }
while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
277static struct ip_reassdata *
278ip_reass_enqueue_new_datagram(
struct ip_hdr *fraghdr,
int clen)
280 struct ip_reassdata *ipr;
281#if ! IP_REASS_FREE_OLDEST
286 ipr = (
struct ip_reassdata *)
memp_malloc(MEMP_REASSDATA);
288#if IP_REASS_FREE_OLDEST
289 if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
290 ipr = (
struct ip_reassdata *)
memp_malloc(MEMP_REASSDATA);
295 IPFRAG_STATS_INC(ip_frag.memerr);
296 LWIP_DEBUGF(
IP_REASS_DEBUG, (
"Failed to alloc reassdata struct\n"));
300 memset(ipr, 0,
sizeof(
struct ip_reassdata));
304 ipr->next = reassdatagrams;
305 reassdatagrams = ipr;
308 SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
317ip_reass_dequeue_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev)
320 if (reassdatagrams == ipr) {
322 reassdatagrams = ipr->next;
325 LWIP_ASSERT(
"sanity check linked list", prev != NULL);
326 prev->next = ipr->next;
344ip_reass_chain_frag_into_datagram_and_validate(
struct ip_reassdata *ipr,
struct pbuf *new_p,
int is_last)
346 struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev = NULL;
355 len = lwip_ntohs(IPH_LEN(fraghdr));
356 hlen = IPH_HL_BYTES(fraghdr);
359 return IP_REASS_VALIDATE_PBUF_DROPPED;
361 len = (u16_t)(len - hlen);
362 offset = IPH_OFFSET_BYTES(fraghdr);
367 LWIP_ASSERT(
"sizeof(struct ip_reass_helper) <= IP_HLEN",
368 sizeof(
struct ip_reass_helper) <= IP_HLEN);
369 iprh = (
struct ip_reass_helper *)new_p->payload;
370 iprh->next_pbuf = NULL;
371 iprh->start = offset;
372 iprh->end = (u16_t)(offset + len);
373 if (iprh->end < offset) {
375 return IP_REASS_VALIDATE_PBUF_DROPPED;
380 for (q = ipr->p; q != NULL;) {
381 iprh_tmp = (
struct ip_reass_helper *)q->payload;
382 if (iprh->start < iprh_tmp->start) {
385 if (iprh_prev != NULL) {
387#if IP_REASS_CHECK_OVERLAP
388 if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
390 return IP_REASS_VALIDATE_PBUF_DROPPED;
393 iprh_prev->next_pbuf = new_p;
394 if (iprh_prev->end != iprh->start) {
400#if IP_REASS_CHECK_OVERLAP
401 if (iprh->end > iprh_tmp->start) {
403 return IP_REASS_VALIDATE_PBUF_DROPPED;
410 }
else if (iprh->start == iprh_tmp->start) {
412 return IP_REASS_VALIDATE_PBUF_DROPPED;
413#if IP_REASS_CHECK_OVERLAP
414 }
else if (iprh->start < iprh_tmp->end) {
416 return IP_REASS_VALIDATE_PBUF_DROPPED;
420 if (iprh_prev != NULL) {
421 if (iprh_prev->end != iprh_tmp->start) {
428 q = iprh_tmp->next_pbuf;
429 iprh_prev = iprh_tmp;
434 if (iprh_prev != NULL) {
437#if IP_REASS_CHECK_OVERLAP
438 LWIP_ASSERT(
"check fragments don't overlap", iprh_prev->end <= iprh->start);
440 iprh_prev->next_pbuf = new_p;
441 if (iprh_prev->end != iprh->start) {
445#if IP_REASS_CHECK_OVERLAP
446 LWIP_ASSERT(
"no previous fragment, this must be the first fragment!",
456 if (is_last || ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0)) {
461 if ((ipr->p == NULL) || (((
struct ip_reass_helper *)ipr->p->payload)->start != 0)) {
468 iprh = (
struct ip_reass_helper *)q->payload;
469 if (iprh_prev->end != iprh->start) {
479 LWIP_ASSERT(
"sanity check", ipr->p != NULL);
480 LWIP_ASSERT(
"sanity check",
481 ((
struct ip_reass_helper *)ipr->p->payload) != iprh);
482 LWIP_ASSERT(
"validate_datagram:next_pbuf!=NULL",
483 iprh->next_pbuf == NULL);
490 return valid ? IP_REASS_VALIDATE_TELEGRAM_FINISHED : IP_REASS_VALIDATE_PBUF_QUEUED;
493 return IP_REASS_VALIDATE_PBUF_QUEUED;
503ip4_reass(
struct pbuf *p)
507 struct ip_reassdata *ipr;
508 struct ip_reass_helper *iprh;
509 u16_t offset, len, clen;
514 IPFRAG_STATS_INC(ip_frag.recv);
515 MIB2_STATS_INC(mib2.ipreasmreqds);
517 fraghdr = (
struct ip_hdr *)p->payload;
519 if (IPH_HL_BYTES(fraghdr) != IP_HLEN) {
520 LWIP_DEBUGF(
IP_REASS_DEBUG, (
"ip4_reass: IP options currently not supported!\n"));
521 IPFRAG_STATS_INC(ip_frag.err);
525 offset = IPH_OFFSET_BYTES(fraghdr);
526 len = lwip_ntohs(IPH_LEN(fraghdr));
527 hlen = IPH_HL_BYTES(fraghdr);
532 len = (u16_t)(len - hlen);
537#if IP_REASS_FREE_OLDEST
538 if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
543 LWIP_DEBUGF(
IP_REASS_DEBUG, (
"ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
545 IPFRAG_STATS_INC(ip_frag.memerr);
554 for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
558 if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
559 LWIP_DEBUGF(
IP_REASS_DEBUG, (
"ip4_reass: matching previous fragment ID=%"X16_F
"\n",
560 lwip_ntohs(IPH_ID(fraghdr))));
561 IPFRAG_STATS_INC(ip_frag.cachehit);
568 ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
574 if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
575 ((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
580 SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
588 is_last = (IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0;
590 u16_t datagram_len = (u16_t)(offset + len);
591 if ((datagram_len < offset) || (datagram_len > (0xFFFF - IP_HLEN))) {
598 valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p, is_last);
599 if (valid == IP_REASS_VALIDATE_PBUF_DROPPED) {
607 ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount + clen);
609 u16_t datagram_len = (u16_t)(offset + len);
610 ipr->datagram_len = datagram_len;
611 ipr->flags |= IP_REASS_FLAG_LASTFRAG;
613 (
"ip4_reass: last fragment seen, total len %"S16_F
"\n",
617 if (valid == IP_REASS_VALIDATE_TELEGRAM_FINISHED) {
618 struct ip_reassdata *ipr_prev;
621 u16_t datagram_len = (u16_t)(ipr->datagram_len + IP_HLEN);
624 r = ((
struct ip_reass_helper *)ipr->p->payload)->next_pbuf;
627 fraghdr = (
struct ip_hdr *)(ipr->p->payload);
628 SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
629 IPH_LEN_SET(fraghdr, lwip_htons(datagram_len));
630 IPH_OFFSET_SET(fraghdr, 0);
631 IPH_CHKSUM_SET(fraghdr, 0);
635 IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
643 iprh = (
struct ip_reass_helper *)r->payload;
652 if (ipr == reassdatagrams) {
655 for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
656 if (ipr_prev->next == ipr) {
663 ip_reass_dequeue_datagram(ipr, ipr_prev);
667 LWIP_ASSERT(
"ip_reass_pbufcount >= clen", ip_reass_pbufcount >= clen);
668 ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount - clen);
670 MIB2_STATS_INC(mib2.ipreasmoks);
676 LWIP_DEBUGF(
IP_REASS_DEBUG, (
"ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
680 LWIP_ASSERT(
"ipr != NULL", ipr != NULL);
681 if (ipr->p == NULL) {
683 LWIP_ASSERT(
"not firstalthough just enqueued", ipr == reassdatagrams);
684 ip_reass_dequeue_datagram(ipr, NULL);
689 IPFRAG_STATS_INC(ip_frag.drop);
696#if !LWIP_NETIF_TX_SINGLE_PBUF
698static struct pbuf_custom_ref *
699ip_frag_alloc_pbuf_custom_ref(
void)
701 return (
struct pbuf_custom_ref *)
memp_malloc(MEMP_FRAG_PBUF);
706ip_frag_free_pbuf_custom_ref(
struct pbuf_custom_ref *p)
708 LWIP_ASSERT(
"p != NULL", p != NULL);
715ipfrag_free_pbuf_custom(
struct pbuf *p)
717 struct pbuf_custom_ref *pcr = (
struct pbuf_custom_ref *)p;
718 LWIP_ASSERT(
"pcr != NULL", pcr != NULL);
719 LWIP_ASSERT(
"pcr == p", (
void *)pcr == (
void *)p);
720 if (pcr->original != NULL) {
723 ip_frag_free_pbuf_custom_ref(pcr);
743#if !LWIP_NETIF_TX_SINGLE_PBUF
744 struct pbuf *newpbuf;
745 u16_t newpbuflen = 0;
748 struct ip_hdr *original_iphdr;
750 const u16_t nfb = (u16_t)((
netif->
mtu - IP_HLEN) / 8);
751 u16_t left, fragsize;
754 u16_t poff = IP_HLEN;
758 original_iphdr = (
struct ip_hdr *)p->payload;
759 iphdr = original_iphdr;
760 if (IPH_HL_BYTES(iphdr) != IP_HLEN) {
764 LWIP_ERROR(
"ip4_frag(): pbuf too short", p->len >= IP_HLEN,
return ERR_VAL);
767 tmp = lwip_ntohs(IPH_OFFSET(iphdr));
768 ofo = tmp & IP_OFFMASK;
770 mf_set = tmp & IP_MF;
772 left = (u16_t)(p->tot_len - IP_HLEN);
776 fragsize = LWIP_MIN(left, (u16_t)(nfb * 8));
778#if LWIP_NETIF_TX_SINGLE_PBUF
780 if (rambuf == NULL) {
783 LWIP_ASSERT(
"this needs a pbuf in one piece!",
801 if (rambuf == NULL) {
804 LWIP_ASSERT(
"this needs a pbuf in one piece!",
805 (rambuf->
len >= (IP_HLEN)));
809 left_to_copy = fragsize;
810 while (left_to_copy) {
811 struct pbuf_custom_ref *pcr;
812 u16_t plen = (u16_t)(p->len - poff);
813 LWIP_ASSERT(
"p->len >= poff", p->len >= poff);
814 newpbuflen = LWIP_MIN(left_to_copy, plen);
821 pcr = ip_frag_alloc_pbuf_custom_ref();
828 (u8_t *)p->payload + poff, newpbuflen);
829 if (newpbuf == NULL) {
830 ip_frag_free_pbuf_custom_ref(pcr);
836 pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
842 left_to_copy = (u16_t)(left_to_copy - newpbuflen);
848 poff = (u16_t)(poff + newpbuflen);
852 last = (left <=
netif->
mtu - IP_HLEN);
855 tmp = (IP_OFFMASK & (ofo));
856 if (!last || mf_set) {
860 IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
861 IPH_LEN_SET(iphdr, lwip_htons((u16_t)(fragsize + IP_HLEN)));
862 IPH_CHKSUM_SET(iphdr, 0);
864 IF__NETIF_CHECKSUM_ENABLED(
netif, NETIF_CHECKSUM_GEN_IP) {
865 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
873 IPFRAG_STATS_INC(ip_frag.xmit);
883 left = (u16_t)(left - fragsize);
884 ofo = (u16_t)(ofo + nfb);
886 MIB2_STATS_INC(mib2.ipfragoks);
889 MIB2_STATS_INC(mib2.ipfragfails);
#define LWIP_UNUSED_ARG(x)
#define PACK_STRUCT_FIELD(x)
#define IP_REASS_MAX_PBUFS
#define SMEMCPY(dst, src, len)
void pbuf_ref(struct pbuf *p)
void pbuf_cat(struct pbuf *head, struct pbuf *tail)
u8 pbuf_free(struct pbuf *p)
u16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset)
#define ip_current_input_netif()
void * memp_malloc(memp_t type)
void memp_free(memp_t type, void *mem)
u8_t pbuf_add_header(struct pbuf *p, size_t header_size_increment)
u8_t pbuf_remove_header(struct pbuf *p, size_t header_size)
struct ip4_addr ip4_addr_t