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"
98 struct 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_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
110 ip4_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
111 IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
114 static struct ip_reassdata *reassdatagrams;
115 static u16_t ip_reass_pbufcount;
118 static void ip_reass_dequeue_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev);
119 static int ip_reass_free_complete_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev);
130 struct ip_reassdata *r, *prev =
NULL;
143 struct ip_reassdata *tmp;
149 ip_reass_free_complete_datagram(tmp, prev);
164 ip_reass_free_complete_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev)
166 u16_t pbufs_freed = 0;
169 struct ip_reass_helper *iprh;
173 LWIP_ASSERT(
"prev->next == ipr", prev->next == ipr);
178 iprh = (
struct ip_reass_helper *)ipr->p->payload;
179 if (iprh->start == 0) {
183 ipr->p = iprh->next_pbuf;
188 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
199 iprh = (
struct ip_reass_helper *)p->
payload;
204 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
209 ip_reass_dequeue_datagram(ipr, prev);
210 LWIP_ASSERT(
"ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
211 ip_reass_pbufcount -= pbufs_freed;
216 #if IP_REASS_FREE_OLDEST
227 ip_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));
277 static struct ip_reassdata*
278 ip_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);
300 memset(ipr, 0,
sizeof(
struct ip_reassdata));
304 ipr->next = reassdatagrams;
305 reassdatagrams = ipr;
317 ip_reass_dequeue_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev)
320 if (reassdatagrams == ipr) {
322 reassdatagrams = ipr->next;
326 prev->next = ipr->next;
344 ip_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;
360 LWIP_ASSERT(
"sizeof(struct ip_reass_helper) <= IP_HLEN",
361 sizeof(
struct ip_reass_helper) <=
IP_HLEN);
362 iprh = (
struct ip_reass_helper*)new_p->
payload;
363 iprh->next_pbuf =
NULL;
364 iprh->start = offset;
365 iprh->end = offset + len;
369 for (q = ipr->p; q !=
NULL;) {
370 iprh_tmp = (
struct ip_reass_helper*)q->
payload;
371 if (iprh->start < iprh_tmp->start) {
374 if (iprh_prev !=
NULL) {
376 #if IP_REASS_CHECK_OVERLAP
377 if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
382 iprh_prev->next_pbuf = new_p;
383 if (iprh_prev->end != iprh->start) {
389 #if IP_REASS_CHECK_OVERLAP
390 if (iprh->end > iprh_tmp->start) {
399 }
else if (iprh->start == iprh_tmp->start) {
402 #if IP_REASS_CHECK_OVERLAP
403 }
else if (iprh->start < iprh_tmp->end) {
409 if (iprh_prev !=
NULL) {
410 if (iprh_prev->end != iprh_tmp->start) {
417 q = iprh_tmp->next_pbuf;
418 iprh_prev = iprh_tmp;
423 if (iprh_prev !=
NULL) {
426 #if IP_REASS_CHECK_OVERLAP
427 LWIP_ASSERT(
"check fragments don't overlap", iprh_prev->end <= iprh->start);
429 iprh_prev->next_pbuf = new_p;
430 if (iprh_prev->end != iprh->start) {
434 #if IP_REASS_CHECK_OVERLAP
435 LWIP_ASSERT(
"no previous fragment, this must be the first fragment!",
445 if (is_last || ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0)) {
450 if ((ipr->p ==
NULL) || (((
struct ip_reass_helper*)ipr->p->payload)->start != 0)) {
457 iprh = (
struct ip_reass_helper*)q->
payload;
458 if (iprh_prev->end != iprh->start) {
470 ((
struct ip_reass_helper*)ipr->p->payload) != iprh);
472 iprh->next_pbuf ==
NULL);
479 return valid ? IP_REASS_VALIDATE_TELEGRAM_FINISHED : IP_REASS_VALIDATE_PBUF_QUEUED;
482 return IP_REASS_VALIDATE_PBUF_QUEUED;
483 #if IP_REASS_CHECK_OVERLAP
487 return IP_REASS_VALIDATE_PBUF_DROPPED;
498 ip4_reass(
struct pbuf *p)
502 struct ip_reassdata *ipr;
503 struct ip_reass_helper *iprh;
504 u16_t offset, len, clen;
525 #if IP_REASS_FREE_OLDEST
526 if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
542 for (ipr = reassdatagrams; ipr !=
NULL; ipr = ipr->next) {
546 if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
556 ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
579 if ((datagram_len < offset) || (datagram_len > (0xFFFF -
IP_HLEN))) {
586 valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p, is_last);
587 if (valid == IP_REASS_VALIDATE_PBUF_DROPPED) {
595 ip_reass_pbufcount = (
u16_t)(ip_reass_pbufcount + clen);
598 ipr->datagram_len = datagram_len;
599 ipr->flags |= IP_REASS_FLAG_LASTFRAG;
601 (
"ip4_reass: last fragment seen, total len %"S16_F"\n",
605 if (valid == IP_REASS_VALIDATE_TELEGRAM_FINISHED) {
606 struct ip_reassdata *ipr_prev;
612 r = ((
struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
615 fraghdr = (
struct ip_hdr*)(ipr->p->payload);
631 iprh = (
struct ip_reass_helper*)r->
payload;
640 if (ipr == reassdatagrams) {
643 for (ipr_prev = reassdatagrams; ipr_prev !=
NULL; ipr_prev = ipr_prev->next) {
644 if (ipr_prev->next == ipr) {
651 ip_reass_dequeue_datagram(ipr, ipr_prev);
674 #if !LWIP_NETIF_TX_SINGLE_PBUF
676 static struct pbuf_custom_ref*
677 ip_frag_alloc_pbuf_custom_ref(
void)
679 return (
struct pbuf_custom_ref*)
memp_malloc(MEMP_FRAG_PBUF);
684 ip_frag_free_pbuf_custom_ref(
struct pbuf_custom_ref* p)
693 ipfrag_free_pbuf_custom(
struct pbuf *p)
695 struct pbuf_custom_ref *pcr = (
struct pbuf_custom_ref*)p;
698 if (pcr->original !=
NULL) {
701 ip_frag_free_pbuf_custom_ref(pcr);
718 ip4_frag(
struct pbuf *p,
struct netif *
netif,
const ip4_addr_t *dest)
721 #if !LWIP_NETIF_TX_SINGLE_PBUF
722 struct pbuf *newpbuf;
723 u16_t newpbuflen = 0;
726 struct ip_hdr *original_iphdr;
729 u16_t left, fragsize;
736 iphdr = original_iphdr;
750 #if LWIP_NETIF_TX_SINGLE_PBUF
752 if (rambuf ==
NULL) {
773 if (rambuf ==
NULL) {
781 left_to_copy = fragsize;
782 while (left_to_copy) {
783 struct pbuf_custom_ref *pcr;
785 newpbuflen =
LWIP_MIN(left_to_copy, plen);
792 pcr = ip_frag_alloc_pbuf_custom_ref();
800 if (newpbuf ==
NULL) {
801 ip_frag_free_pbuf_custom_ref(pcr);
807 pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
813 left_to_copy -= newpbuflen;