74 #if LWIP_IPV6 && LWIP_IPV6_REASS 80 #ifndef IP_REASS_CHECK_OVERLAP 81 #define IP_REASS_CHECK_OVERLAP 1 88 #ifndef IP_REASS_FREE_OLDEST 89 #define IP_REASS_FREE_OLDEST 1 92 #if IPV6_FRAG_COPYHEADER 93 #define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN)) 96 #define IP_REASS_FLAG_LASTFRAG 0x01 105 #ifdef PACK_STRUCT_USE_INCLUDES 106 # include "arch/bpstruct.h" 109 struct ip6_reass_helper {
113 } PACK_STRUCT_STRUCT;
115 #ifdef PACK_STRUCT_USE_INCLUDES 116 # include "arch/epstruct.h" 120 static struct ip6_reassdata *reassdatagrams;
121 static u16_t ip6_reass_pbufcount;
124 static void ip6_reass_free_complete_datagram(
struct ip6_reassdata *ipr);
125 #if IP_REASS_FREE_OLDEST 126 static void ip6_reass_remove_oldest_datagram(
struct ip6_reassdata *ipr,
int pbufs_needed);
132 struct ip6_reassdata *r, *tmp;
134 #if !IPV6_FRAG_COPYHEADER 135 LWIP_ASSERT(
"sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
136 sizeof(
struct ip6_reass_helper) <= IP6_FRAG_HLEN);
152 ip6_reass_free_complete_datagram(tmp);
165 ip6_reass_free_complete_datagram(
struct ip6_reassdata *ipr)
167 struct ip6_reassdata *prev;
168 u16_t pbufs_freed = 0;
171 struct ip6_reass_helper *iprh;
174 iprh = (
struct ip6_reass_helper *)ipr->p->payload;
175 if (iprh->start == 0) {
179 ipr->p = iprh->next_pbuf;
183 LWIP_ASSERT(
"ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
189 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
200 iprh = (
struct ip6_reass_helper *)p->
payload;
205 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
211 if (ipr == reassdatagrams) {
212 reassdatagrams = ipr->next;
214 prev = reassdatagrams;
215 while (prev != NULL) {
216 if (prev->next == ipr) {
222 prev->next = ipr->next;
228 LWIP_ASSERT(
"ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed);
229 ip6_reass_pbufcount -= pbufs_freed;
232 #if IP_REASS_FREE_OLDEST 242 ip6_reass_remove_oldest_datagram(
struct ip6_reassdata *ipr,
int pbufs_needed)
244 struct ip6_reassdata *r, *oldest;
249 r = oldest = reassdatagrams;
252 if (r->timer <= oldest->timer) {
263 if (oldest != NULL) {
264 ip6_reass_free_complete_datagram(oldest);
266 }
while (((ip6_reass_pbufcount + pbufs_needed) >
IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL));
278 ip6_reass(
struct pbuf *p)
280 struct ip6_reassdata *ipr, *ipr_prev;
281 struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
288 IP6_FRAG_STATS_INC(ip6_frag.recv);
290 if ((
const void*)ip6_current_header() != ((u8_t*)p->
payload) - IP6_HLEN) {
292 IP6_FRAG_STATS_INC(ip6_frag.proterr);
293 IP6_FRAG_STATS_INC(ip6_frag.drop);
301 offset = lwip_ntohs(frag_hdr->_fragment_offset);
306 len = lwip_ntohs(ip6_current_header()->_plen);
307 len -= (u16_t)(((u8_t*)p->
payload - (
const u8_t*)ip6_current_header()) - IP6_HLEN);
308 len -= IP6_FRAG_HLEN;
312 for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) {
316 if ((frag_hdr->_identification == ipr->identification) &&
317 ip6_addr_cmp(ip6_current_src_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->src)) &&
318 ip6_addr_cmp(ip6_current_dest_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->dest))) {
319 IP6_FRAG_STATS_INC(ip6_frag.cachehit);
327 ipr = (
struct ip6_reassdata *)
memp_malloc(MEMP_IP6_REASSDATA);
329 #if IP_REASS_FREE_OLDEST 331 ip6_reass_remove_oldest_datagram(ipr, clen);
332 ipr = (
struct ip6_reassdata *)
memp_malloc(MEMP_IP6_REASSDATA);
335 for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
336 if (ipr_prev->next == ipr) {
343 IP6_FRAG_STATS_INC(ip6_frag.memerr);
344 IP6_FRAG_STATS_INC(ip6_frag.drop);
349 memset(ipr, 0,
sizeof(
struct ip6_reassdata));
353 ipr->next = reassdatagrams;
354 reassdatagrams = ipr;
359 #if IPV6_FRAG_COPYHEADER 360 MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
363 ipr->iphdr = ip_data.current_ip6_header;
367 ipr->identification = frag_hdr->_identification;
370 ipr->nexth = frag_hdr->_nexth;
375 #if IP_REASS_FREE_OLDEST 376 ip6_reass_remove_oldest_datagram(ipr, clen);
379 for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
380 if (ipr_prev->next == ipr) {
389 IP6_FRAG_STATS_INC(ip6_frag.memerr);
390 IP6_FRAG_STATS_INC(ip6_frag.drop);
396 #if IPV6_FRAG_COPYHEADER 397 if (IPV6_FRAG_REQROOM > 0) {
402 LWIP_ASSERT(
"no room for struct ip6_reass_helper", hdrerr == 0);
405 LWIP_ASSERT(
"sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
406 sizeof(
struct ip6_reass_helper) <= IP6_FRAG_HLEN);
408 iprh = (
struct ip6_reass_helper *)p->
payload;
409 iprh->next_pbuf = NULL;
410 iprh->start = (offset & IP6_FRAG_OFFSET_MASK);
411 iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len;
416 for (q = ipr->p; q != NULL;) {
417 iprh_tmp = (
struct ip6_reass_helper*)q->
payload;
418 if (iprh->start < iprh_tmp->start) {
419 #if IP_REASS_CHECK_OVERLAP 420 if (iprh->end > iprh_tmp->start) {
422 IP6_FRAG_STATS_INC(ip6_frag.proterr);
423 IP6_FRAG_STATS_INC(ip6_frag.drop);
426 if (iprh_prev != NULL) {
427 if (iprh->start < iprh_prev->end) {
429 IP6_FRAG_STATS_INC(ip6_frag.proterr);
430 IP6_FRAG_STATS_INC(ip6_frag.drop);
437 if (iprh_prev != NULL) {
439 iprh_prev->next_pbuf = p;
445 }
else if (iprh->start == iprh_tmp->start) {
447 IP6_FRAG_STATS_INC(ip6_frag.drop);
449 #if IP_REASS_CHECK_OVERLAP 450 }
else if (iprh->start < iprh_tmp->end) {
452 IP6_FRAG_STATS_INC(ip6_frag.proterr);
453 IP6_FRAG_STATS_INC(ip6_frag.drop);
458 if (iprh_prev != NULL) {
459 if (iprh_prev->end != iprh_tmp->start) {
466 q = iprh_tmp->next_pbuf;
467 iprh_prev = iprh_tmp;
472 if (iprh_prev != NULL) {
475 #if IP_REASS_CHECK_OVERLAP 476 LWIP_ASSERT(
"check fragments don't overlap", iprh_prev->end <= iprh->start);
478 iprh_prev->next_pbuf = p;
479 if (iprh_prev->end != iprh->start) {
483 #if IP_REASS_CHECK_OVERLAP 484 LWIP_ASSERT(
"no previous fragment, this must be the first fragment!",
494 ip6_reass_pbufcount += clen;
497 if (iprh->start == 0) {
498 #if IPV6_FRAG_COPYHEADER 499 if (iprh->next_pbuf != NULL) {
500 MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
504 ipr->iphdr = ip_data.current_ip6_header;
509 if ((offset & IP6_FRAG_MORE_FLAG) == 0) {
510 ipr->datagram_len = iprh->end;
514 iprh_tmp = (
struct ip6_reass_helper*)ipr->p->payload;
515 if (iprh_tmp->start != 0) {
518 if (ipr->datagram_len == 0) {
525 while ((q != NULL) && valid) {
526 iprh = (
struct ip6_reass_helper*)q->
payload;
527 if (iprh_prev->end != iprh->start) {
540 iprh = (
struct ip6_reass_helper*) ipr->p->payload;
541 while (iprh != NULL) {
542 struct pbuf* next_pbuf = iprh->next_pbuf;
543 if (next_pbuf != NULL) {
545 iprh_tmp = (
struct ip6_reass_helper*)next_pbuf->
payload;
549 #if IPV6_FRAG_COPYHEADER 550 if (IPV6_FRAG_REQROOM > 0) {
552 u8_t hdrerr =
pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
554 LWIP_ASSERT(
"no room for struct ip6_reass_helper", hdrerr == 0);
566 #if IPV6_FRAG_COPYHEADER 567 if (IPV6_FRAG_REQROOM > 0) {
569 u8_t hdrerr =
pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
571 LWIP_ASSERT(
"no room for struct ip6_reass_helper", hdrerr == 0);
573 iphdr_ptr = (
struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN);
574 MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN);
576 iphdr_ptr = ipr->iphdr;
580 ipr->datagram_len += (u16_t)(((u8_t*)ipr->p->payload - (u8_t*)iphdr_ptr)
585 iphdr_ptr->_plen = lwip_htons(ipr->datagram_len);
593 frag_hdr->_nexth = ipr->nexth;
594 frag_hdr->reserved = 0;
595 frag_hdr->_fragment_offset = 0;
596 frag_hdr->_identification = 0;
599 if (reassdatagrams == ipr) {
601 reassdatagrams = ipr->next;
604 LWIP_ASSERT(
"sanity check linked list", ipr_prev != NULL);
605 ipr_prev->next = ipr->next;
615 LWIP_ASSERT(
"ip6_reass: moving p->payload to ip6 header failed\n", 0);
633 #if LWIP_IPV6 && LWIP_IPV6_FRAG 635 #if !LWIP_NETIF_TX_SINGLE_PBUF 637 static struct pbuf_custom_ref*
638 ip6_frag_alloc_pbuf_custom_ref(
void)
640 return (
struct pbuf_custom_ref*)
memp_malloc(MEMP_FRAG_PBUF);
645 ip6_frag_free_pbuf_custom_ref(
struct pbuf_custom_ref* p)
647 LWIP_ASSERT(
"p != NULL", p != NULL);
654 ip6_frag_free_pbuf_custom(
struct pbuf *p)
656 struct pbuf_custom_ref *pcr = (
struct pbuf_custom_ref*)p;
657 LWIP_ASSERT(
"pcr != NULL", pcr != NULL);
658 LWIP_ASSERT(
"pcr == p", (
void*)pcr == (
void*)p);
659 if (pcr->original != NULL) {
662 ip6_frag_free_pbuf_custom_ref(pcr);
679 ip6_frag(
struct pbuf *p,
struct netif *
netif,
const ip6_addr_t *dest)
681 struct ip6_hdr *original_ip6hdr;
685 #if !LWIP_NETIF_TX_SINGLE_PBUF 686 struct pbuf *newpbuf;
687 u16_t newpbuflen = 0;
690 static u32_t identification;
694 u16_t fragment_offset = 0;
696 u16_t poff = IP6_HLEN;
702 mtu = nd6_get_destination_mtu(dest, netif);
707 nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK;
710 last = (left <= nfb);
713 cop = last ? left : nfb;
715 #if LWIP_NETIF_TX_SINGLE_PBUF 717 if (rambuf == NULL) {
718 IP6_FRAG_STATS_INC(ip6_frag.memerr);
721 LWIP_ASSERT(
"this needs a pbuf in one piece!",
727 IP6_FRAG_STATS_INC(ip6_frag.memerr);
731 SMEMCPY(rambuf->
payload, original_ip6hdr, IP6_HLEN);
741 if (rambuf == NULL) {
742 IP6_FRAG_STATS_INC(ip6_frag.memerr);
745 LWIP_ASSERT(
"this needs a pbuf in one piece!",
746 (p->
len >= (IP6_HLEN)));
747 SMEMCPY(rambuf->
payload, original_ip6hdr, IP6_HLEN);
757 while (left_to_copy) {
758 struct pbuf_custom_ref *pcr;
759 newpbuflen = (left_to_copy < p->
len) ? left_to_copy : p->
len;
765 pcr = ip6_frag_alloc_pbuf_custom_ref();
768 IP6_FRAG_STATS_INC(ip6_frag.memerr);
773 if (newpbuf == NULL) {
774 ip6_frag_free_pbuf_custom_ref(pcr);
776 IP6_FRAG_STATS_INC(ip6_frag.memerr);
781 pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom;
787 left_to_copy -= newpbuflen;
796 frag_hdr->_nexth = original_ip6hdr->_nexth;
797 frag_hdr->reserved = 0;
798 frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
799 frag_hdr->_identification = lwip_htonl(identification);
801 IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
802 IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);
807 IP6_FRAG_STATS_INC(ip6_frag.xmit);
808 netif->output_ip6(netif, rambuf, dest);
819 fragment_offset += cop;
u16_t pbuf_clen(const struct pbuf *p)
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
void pbuf_ref(struct pbuf *p)
void memp_free(memp_t type, void *mem)
#define PACK_STRUCT_BEGIN
#define IP_REASS_MAX_PBUFS
void pbuf_cat(struct pbuf *h, struct pbuf *t)
#define PACK_STRUCT_FIELD(x)
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
u8_t pbuf_header_force(struct pbuf *p, s16_t header_size_increment)
#define LWIP_UNUSED_ARG(x)
u8_t pbuf_free(struct pbuf *p)
void * memp_malloc(memp_t type)