87 #ifndef IP_REASS_CHECK_OVERLAP 88 #define IP_REASS_CHECK_OVERLAP 1 95 #ifndef IP_REASS_FREE_OLDEST 96 #define IP_REASS_FREE_OLDEST 1 99 #define IP_REASS_FLAG_LASTFRAG 0x01 109 #ifdef PACK_STRUCT_USE_INCLUDES 110 # include "arch/bpstruct.h" 113 struct ip_reass_helper {
117 } PACK_STRUCT_STRUCT;
119 #ifdef PACK_STRUCT_USE_INCLUDES 120 # include "arch/epstruct.h" 123 #define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ 124 (ip4_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ 125 ip4_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ 126 IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 129 static struct ip_reassdata *reassdatagrams;
130 static u16_t ip_reass_pbufcount;
133 static void ip_reass_dequeue_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev);
134 static int ip_reass_free_complete_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev);
145 struct ip_reassdata *r, *prev = NULL;
158 struct ip_reassdata *tmp;
164 ip_reass_free_complete_datagram(tmp, prev);
179 ip_reass_free_complete_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev)
181 u16_t pbufs_freed = 0;
184 struct ip_reass_helper *iprh;
186 LWIP_ASSERT(
"prev != ipr", prev != ipr);
188 LWIP_ASSERT(
"prev->next == ipr", prev->next == ipr);
191 MIB2_STATS_INC(mib2.ipreasmfails);
193 iprh = (
struct ip_reass_helper *)ipr->p->payload;
194 if (iprh->start == 0) {
198 ipr->p = iprh->next_pbuf;
200 SMEMCPY(p->
payload, &ipr->iphdr, IP_HLEN);
203 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
214 iprh = (
struct ip_reass_helper *)p->
payload;
219 LWIP_ASSERT(
"pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
224 ip_reass_dequeue_datagram(ipr, prev);
225 LWIP_ASSERT(
"ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
226 ip_reass_pbufcount -= pbufs_freed;
231 #if IP_REASS_FREE_OLDEST 242 ip_reass_remove_oldest_datagram(
struct ip_hdr *fraghdr,
int pbufs_needed)
247 struct ip_reassdata *r, *oldest, *prev, *oldest_prev;
248 int pbufs_freed = 0, pbufs_freed_current;
260 if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
263 if (oldest == NULL) {
266 }
else if (r->timer <= oldest->timer) {
272 if (r->next != NULL) {
277 if (oldest != NULL) {
278 pbufs_freed_current = ip_reass_free_complete_datagram(oldest, oldest_prev);
279 pbufs_freed += pbufs_freed_current;
281 }
while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
292 static struct ip_reassdata*
293 ip_reass_enqueue_new_datagram(
struct ip_hdr *fraghdr,
int clen)
295 struct ip_reassdata* ipr;
296 #if ! IP_REASS_FREE_OLDEST 301 ipr = (
struct ip_reassdata *)
memp_malloc(MEMP_REASSDATA);
303 #if IP_REASS_FREE_OLDEST 304 if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
305 ipr = (
struct ip_reassdata *)
memp_malloc(MEMP_REASSDATA);
310 IPFRAG_STATS_INC(ip_frag.memerr);
315 memset(ipr, 0,
sizeof(
struct ip_reassdata));
319 ipr->next = reassdatagrams;
320 reassdatagrams = ipr;
323 SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
332 ip_reass_dequeue_datagram(
struct ip_reassdata *ipr,
struct ip_reassdata *prev)
335 if (reassdatagrams == ipr) {
337 reassdatagrams = ipr->next;
340 LWIP_ASSERT(
"sanity check linked list", prev != NULL);
341 prev->next = ipr->next;
358 ip_reass_chain_frag_into_datagram_and_validate(
struct ip_reassdata *ipr,
struct pbuf *new_p)
360 struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
368 len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
369 offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
374 LWIP_ASSERT(
"sizeof(struct ip_reass_helper) <= IP_HLEN",
375 sizeof(
struct ip_reass_helper) <= IP_HLEN);
376 iprh = (
struct ip_reass_helper*)new_p->
payload;
377 iprh->next_pbuf = NULL;
378 iprh->start = offset;
379 iprh->end = offset + len;
383 for (q = ipr->p; q != NULL;) {
384 iprh_tmp = (
struct ip_reass_helper*)q->
payload;
385 if (iprh->start < iprh_tmp->start) {
388 if (iprh_prev != NULL) {
390 #if IP_REASS_CHECK_OVERLAP 391 if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
396 iprh_prev->next_pbuf = new_p;
402 }
else if (iprh->start == iprh_tmp->start) {
405 #if IP_REASS_CHECK_OVERLAP 406 }
else if (iprh->start < iprh_tmp->end) {
412 if (iprh_prev != NULL) {
413 if (iprh_prev->end != iprh_tmp->start) {
420 q = iprh_tmp->next_pbuf;
421 iprh_prev = iprh_tmp;
426 if (iprh_prev != NULL) {
429 #if IP_REASS_CHECK_OVERLAP 430 LWIP_ASSERT(
"check fragments don't overlap", iprh_prev->end <= iprh->start);
432 iprh_prev->next_pbuf = new_p;
433 if (iprh_prev->end != iprh->start) {
437 #if IP_REASS_CHECK_OVERLAP 438 LWIP_ASSERT(
"no previous fragment, this must be the first fragment!",
448 if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
453 if ((ipr->p == NULL) || (((
struct ip_reass_helper*)ipr->p->payload)->start != 0)) {
460 iprh = (
struct ip_reass_helper*)q->
payload;
461 if (iprh_prev->end != iprh->start) {
471 LWIP_ASSERT(
"sanity check", ipr->p != NULL);
472 LWIP_ASSERT(
"sanity check",
473 ((
struct ip_reass_helper*)ipr->p->payload) != iprh);
474 LWIP_ASSERT(
"validate_datagram:next_pbuf!=NULL",
475 iprh->next_pbuf == NULL);
476 LWIP_ASSERT(
"validate_datagram:datagram end!=datagram len",
477 iprh->end == ipr->datagram_len);
488 #if IP_REASS_CHECK_OVERLAP 503 ip4_reass(
struct pbuf *p)
507 struct ip_reassdata *ipr;
508 struct ip_reass_helper *iprh;
509 u16_t offset, len, clen;
511 IPFRAG_STATS_INC(ip_frag.recv);
512 MIB2_STATS_INC(mib2.ipreasmreqds);
516 if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
518 IPFRAG_STATS_INC(ip_frag.err);
522 offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
523 len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
528 #if IP_REASS_FREE_OLDEST 529 if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
536 IPFRAG_STATS_INC(ip_frag.memerr);
545 for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
549 if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
551 lwip_ntohs(IPH_ID(fraghdr))));
552 IPFRAG_STATS_INC(ip_frag.cachehit);
559 ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
565 if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
566 ((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
571 SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
576 ip_reass_pbufcount += clen;
582 if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
583 ipr->flags |= IP_REASS_FLAG_LASTFRAG;
584 ipr->datagram_len = offset + len;
586 (
"ip4_reass: last fragment seen, total len %"S16_F
"\n",
591 if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
592 struct ip_reassdata *ipr_prev;
595 ipr->datagram_len += IP_HLEN;
598 r = ((
struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
601 fraghdr = (
struct ip_hdr*)(ipr->p->payload);
602 SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
603 IPH_LEN_SET(fraghdr, lwip_htons(ipr->datagram_len));
604 IPH_OFFSET_SET(fraghdr, 0);
605 IPH_CHKSUM_SET(fraghdr, 0);
609 IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
617 iprh = (
struct ip_reass_helper*)r->
payload;
626 if (ipr == reassdatagrams) {
629 for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
630 if (ipr_prev->next == ipr) {
637 ip_reass_dequeue_datagram(ipr, ipr_prev);
642 MIB2_STATS_INC(mib2.ipreasmoks);
653 IPFRAG_STATS_INC(ip_frag.drop);
660 #if !LWIP_NETIF_TX_SINGLE_PBUF 662 static struct pbuf_custom_ref*
663 ip_frag_alloc_pbuf_custom_ref(
void)
665 return (
struct pbuf_custom_ref*)
memp_malloc(MEMP_FRAG_PBUF);
670 ip_frag_free_pbuf_custom_ref(
struct pbuf_custom_ref* p)
672 LWIP_ASSERT(
"p != NULL", p != NULL);
679 ipfrag_free_pbuf_custom(
struct pbuf *p)
681 struct pbuf_custom_ref *pcr = (
struct pbuf_custom_ref*)p;
682 LWIP_ASSERT(
"pcr != NULL", pcr != NULL);
683 LWIP_ASSERT(
"pcr == p", (
void*)pcr == (
void*)p);
684 if (pcr->original != NULL) {
687 ip_frag_free_pbuf_custom_ref(pcr);
704 ip4_frag(
struct pbuf *p,
struct netif *
netif,
const ip4_addr_t *dest)
707 #if !LWIP_NETIF_TX_SINGLE_PBUF 708 struct pbuf *newpbuf;
709 u16_t newpbuflen = 0;
712 struct ip_hdr *original_iphdr;
714 const u16_t nfb = (netif->
mtu - IP_HLEN) / 8;
715 u16_t left, fragsize;
718 u16_t poff = IP_HLEN;
722 iphdr = original_iphdr;
723 LWIP_ERROR(
"ip4_frag() does not support IP options", IPH_HL(iphdr) * 4 == IP_HLEN,
return ERR_VAL);
726 tmp = lwip_ntohs(IPH_OFFSET(iphdr));
727 ofo = tmp & IP_OFFMASK;
728 LWIP_ERROR(
"ip_frag(): MF already set", (tmp & IP_MF) == 0,
return ERR_VAL);
734 fragsize = LWIP_MIN(left, nfb * 8);
736 #if LWIP_NETIF_TX_SINGLE_PBUF 738 if (rambuf == NULL) {
741 LWIP_ASSERT(
"this needs a pbuf in one piece!",
750 SMEMCPY(rambuf->
payload, original_iphdr, IP_HLEN);
759 if (rambuf == NULL) {
762 LWIP_ASSERT(
"this needs a pbuf in one piece!",
763 (p->
len >= (IP_HLEN)));
764 SMEMCPY(rambuf->
payload, original_iphdr, IP_HLEN);
767 left_to_copy = fragsize;
768 while (left_to_copy) {
769 struct pbuf_custom_ref *pcr;
770 u16_t plen = p->
len - poff;
771 newpbuflen = LWIP_MIN(left_to_copy, plen);
778 pcr = ip_frag_alloc_pbuf_custom_ref();
785 (u8_t*)p->
payload + poff, newpbuflen);
786 if (newpbuf == NULL) {
787 ip_frag_free_pbuf_custom_ref(pcr);
793 pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
799 left_to_copy -= newpbuflen;
809 last = (left <= netif->
mtu - IP_HLEN);
812 tmp = (IP_OFFMASK & (ofo));
816 IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
817 IPH_LEN_SET(iphdr, lwip_htons(fragsize + IP_HLEN));
818 IPH_CHKSUM_SET(iphdr, 0);
820 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
821 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
828 netif->output(netif, rambuf, dest);
829 IPFRAG_STATS_INC(ip_frag.xmit);
842 MIB2_STATS_INC(mib2.ipfragoks);
845 MIB2_STATS_INC(mib2.ipfragfails);
u16_t pbuf_clen(const struct pbuf *p)
#define ip_current_input_netif()
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)
#define LWIP_DEBUGF(debug, message)
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)
#define LWIP_UNUSED_ARG(x)
u8_t pbuf_free(struct pbuf *p)
void * memp_malloc(memp_t type)