55 #if LWIP_IPV6 && LWIP_IPV6_REASS
61 #ifndef IP_REASS_CHECK_OVERLAP
62 #define IP_REASS_CHECK_OVERLAP 1
69 #ifndef IP_REASS_FREE_OLDEST
70 #define IP_REASS_FREE_OLDEST 1
73 #if IPV6_FRAG_COPYHEADER
74 #define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN))
77 #define IP_REASS_FLAG_LASTFRAG 0x01
86 #ifdef PACK_STRUCT_USE_INCLUDES
87 # include "arch/bpstruct.h"
90 struct ip6_reass_helper {
96 #ifdef PACK_STRUCT_USE_INCLUDES
97 # include "arch/epstruct.h"
101 static struct ip6_reassdata *reassdatagrams;
102 static u16_t ip6_reass_pbufcount;
105 static void ip6_reass_free_complete_datagram(
struct ip6_reassdata *ipr);
106 #if IP_REASS_FREE_OLDEST
107 static void ip6_reass_remove_oldest_datagram(
struct ip6_reassdata *ipr,
int pbufs_needed);
113 struct ip6_reassdata *r, *tmp;
115 #if !IPV6_FRAG_COPYHEADER
116 LWIP_ASSERT(
"sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
133 ip6_reass_free_complete_datagram(tmp);
146 ip6_reass_free_complete_datagram(
struct ip6_reassdata *ipr)
148 struct ip6_reassdata *prev;
149 u16_t pbufs_freed = 0;
152 struct ip6_reass_helper *iprh;
155 iprh = (
struct ip6_reass_helper *)ipr->p->payload;
156 if (iprh->start == 0) {
160 ipr->p = iprh->next_pbuf;
164 LWIP_ASSERT(
"ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
170 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
181 iprh = (
struct ip6_reass_helper *)p->
payload;
186 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
192 if (ipr == reassdatagrams) {
193 reassdatagrams = ipr->next;
195 prev = reassdatagrams;
196 while (prev !=
NULL) {
197 if (prev->next == ipr) {
203 prev->next = ipr->next;
209 LWIP_ASSERT(
"ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed);
210 ip6_reass_pbufcount -= pbufs_freed;
213 #if IP_REASS_FREE_OLDEST
223 ip6_reass_remove_oldest_datagram(
struct ip6_reassdata *ipr,
int pbufs_needed)
225 struct ip6_reassdata *r, *oldest;
230 r = oldest = reassdatagrams;
233 if (r->timer <= oldest->timer) {
244 if (oldest !=
NULL) {
245 ip6_reass_free_complete_datagram(oldest);
259 ip6_reass(
struct pbuf *p)
261 struct ip6_reassdata *ipr, *ipr_prev;
262 struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=
NULL;
282 offset =
lwip_ntohs(frag_hdr->_fragment_offset);
287 len =
lwip_ntohs(ip6_current_header()->_plen);
293 for (ipr = reassdatagrams, ipr_prev =
NULL; ipr !=
NULL; ipr = ipr->next) {
297 if ((frag_hdr->_identification == ipr->identification) &&
298 ip6_addr_cmp(ip6_current_src_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->src)) &&
299 ip6_addr_cmp(ip6_current_dest_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->dest))) {
308 ipr = (
struct ip6_reassdata *)
memp_malloc(MEMP_IP6_REASSDATA);
310 #if IP_REASS_FREE_OLDEST
312 ip6_reass_remove_oldest_datagram(ipr, clen);
313 ipr = (
struct ip6_reassdata *)
memp_malloc(MEMP_IP6_REASSDATA);
316 for (ipr_prev = reassdatagrams; ipr_prev !=
NULL; ipr_prev = ipr_prev->next) {
317 if (ipr_prev->next == ipr) {
330 memset(ipr, 0,
sizeof(
struct ip6_reassdata));
334 ipr->next = reassdatagrams;
335 reassdatagrams = ipr;
340 #if IPV6_FRAG_COPYHEADER
344 ipr->iphdr =
ip_data.current_ip6_header;
348 ipr->identification = frag_hdr->_identification;
351 ipr->nexth = frag_hdr->_nexth;
356 #if IP_REASS_FREE_OLDEST
357 ip6_reass_remove_oldest_datagram(ipr, clen);
360 for (ipr_prev = reassdatagrams; ipr_prev !=
NULL; ipr_prev = ipr_prev->next) {
361 if (ipr_prev->next == ipr) {
377 #if IPV6_FRAG_COPYHEADER
378 if (IPV6_FRAG_REQROOM > 0) {
383 LWIP_ASSERT(
"no room for struct ip6_reass_helper", hdrerr == 0);
386 LWIP_ASSERT(
"sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IPV6_FRAG_COPYHEADER to 1",
389 iprh = (
struct ip6_reass_helper *)p->
payload;
390 iprh->next_pbuf =
NULL;
397 for (q = ipr->p; q !=
NULL;) {
398 iprh_tmp = (
struct ip6_reass_helper*)q->
payload;
399 if (iprh->start < iprh_tmp->start) {
400 #if IP_REASS_CHECK_OVERLAP
401 if (iprh->end > iprh_tmp->start) {
407 if (iprh_prev !=
NULL) {
408 if (iprh->start < iprh_prev->end) {
418 if (iprh_prev !=
NULL) {
420 iprh_prev->next_pbuf = p;
426 }
else if (iprh->start == iprh_tmp->start) {
430 #if IP_REASS_CHECK_OVERLAP
431 }
else if (iprh->start < iprh_tmp->end) {
439 if (iprh_prev !=
NULL) {
440 if (iprh_prev->end != iprh_tmp->start) {
447 q = iprh_tmp->next_pbuf;
448 iprh_prev = iprh_tmp;
453 if (iprh_prev !=
NULL) {
456 #if IP_REASS_CHECK_OVERLAP
457 LWIP_ASSERT(
"check fragments don't overlap", iprh_prev->end <= iprh->start);
459 iprh_prev->next_pbuf = p;
460 if (iprh_prev->end != iprh->start) {
464 #if IP_REASS_CHECK_OVERLAP
465 LWIP_ASSERT(
"no previous fragment, this must be the first fragment!",
475 ip6_reass_pbufcount += clen;
478 if (iprh->start == 0) {
479 #if IPV6_FRAG_COPYHEADER
480 if (iprh->next_pbuf !=
NULL) {
485 ipr->iphdr =
ip_data.current_ip6_header;
491 ipr->datagram_len = iprh->end;
495 iprh_tmp = (
struct ip6_reass_helper*)ipr->p->payload;
496 if (iprh_tmp->start != 0) {
499 if (ipr->datagram_len == 0) {
506 while ((q !=
NULL) && valid) {
507 iprh = (
struct ip6_reass_helper*)q->
payload;
508 if (iprh_prev->end != iprh->start) {
521 iprh = (
struct ip6_reass_helper*) ipr->p->payload;
522 while (iprh !=
NULL) {
523 struct pbuf* next_pbuf = iprh->next_pbuf;
524 if (next_pbuf !=
NULL) {
526 iprh_tmp = (
struct ip6_reass_helper*)next_pbuf->
payload;
530 #if IPV6_FRAG_COPYHEADER
531 if (IPV6_FRAG_REQROOM > 0) {
535 LWIP_ASSERT(
"no room for struct ip6_reass_helper", hdrerr == 0);
547 #if IPV6_FRAG_COPYHEADER
548 if (IPV6_FRAG_REQROOM > 0) {
552 LWIP_ASSERT(
"no room for struct ip6_reass_helper", hdrerr == 0);
557 iphdr_ptr = ipr->iphdr;
561 ipr->datagram_len += (
u16_t)(((
u8_t*)ipr->p->payload - (
u8_t*)iphdr_ptr)
566 iphdr_ptr->_plen =
lwip_htons(ipr->datagram_len);
574 frag_hdr->_nexth = ipr->nexth;
575 frag_hdr->reserved = 0;
576 frag_hdr->_fragment_offset = 0;
577 frag_hdr->_identification = 0;
580 if (reassdatagrams == ipr) {
582 reassdatagrams = ipr->next;
586 ipr_prev->next = ipr->next;
596 LWIP_ASSERT(
"ip6_reass: moving p->payload to ip6 header failed\n", 0);
614 #if LWIP_IPV6 && LWIP_IPV6_FRAG
616 #if !LWIP_NETIF_TX_SINGLE_PBUF
618 static struct pbuf_custom_ref*
619 ip6_frag_alloc_pbuf_custom_ref(
void)
621 return (
struct pbuf_custom_ref*)
memp_malloc(MEMP_FRAG_PBUF);
626 ip6_frag_free_pbuf_custom_ref(
struct pbuf_custom_ref* p)
635 ip6_frag_free_pbuf_custom(
struct pbuf *p)
637 struct pbuf_custom_ref *pcr = (
struct pbuf_custom_ref*)p;
640 if (pcr->original !=
NULL) {
643 ip6_frag_free_pbuf_custom_ref(pcr);
660 ip6_frag(
struct pbuf *p,
struct netif *
netif,
const ip6_addr_t *dest)
662 struct ip6_hdr *original_ip6hdr;
666 #if !LWIP_NETIF_TX_SINGLE_PBUF
667 struct pbuf *newpbuf;
668 u16_t newpbuflen = 0;
671 static u32_t identification;
675 u16_t fragment_offset = 0;
683 mtu = nd6_get_destination_mtu(dest,
netif);
691 last = (left <= nfb);
694 cop = last ? left : nfb;
696 #if LWIP_NETIF_TX_SINGLE_PBUF
698 if (rambuf ==
NULL) {
722 if (rambuf ==
NULL) {
738 while (left_to_copy) {
739 struct pbuf_custom_ref *pcr;
740 newpbuflen = (left_to_copy < p->
len) ? left_to_copy : p->
len;
746 pcr = ip6_frag_alloc_pbuf_custom_ref();
754 if (newpbuf ==
NULL) {
755 ip6_frag_free_pbuf_custom_ref(pcr);
762 pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom;
768 left_to_copy -= newpbuflen;
777 frag_hdr->_nexth = original_ip6hdr->_nexth;
778 frag_hdr->reserved = 0;
780 frag_hdr->_identification =
lwip_htonl(identification);
800 fragment_offset += cop;