UbixOS V2  2.0
ip4_frag.c
Go to the documentation of this file.
1 
7 /*
8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  * this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  * this list of conditions and the following disclaimer in the documentation
18  * and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  * derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31  * OF SUCH DAMAGE.
32  *
33  * This file is part of the lwIP TCP/IP stack.
34  *
35  * Author: Jani Monoses <jani@iv.ro>
36  * Simon Goldschmidt
37  * original reassembly code by Adam Dunkels <adam@sics.se>
38  *
39  */
40 
41 #include "net/opt.h"
42 
43 #if LWIP_IPV4
44 
45 #include "net/ip4_frag.h"
46 #include "net/def.h"
47 #include "net/inet_chksum.h"
48 #include "net/netif.h"
49 #include "net/stats.h"
50 #include "net/icmp.h"
51 
52 #include <string.h>
53 
54 #if IP_REASSEMBLY
55 
68 #ifndef IP_REASS_CHECK_OVERLAP
69 #define IP_REASS_CHECK_OVERLAP 1
70 #endif /* IP_REASS_CHECK_OVERLAP */
71 
76 #ifndef IP_REASS_FREE_OLDEST
77 #define IP_REASS_FREE_OLDEST 1
78 #endif /* IP_REASS_FREE_OLDEST */
79 
80 #define IP_REASS_FLAG_LASTFRAG 0x01
81 
82 #define IP_REASS_VALIDATE_TELEGRAM_FINISHED 1
83 #define IP_REASS_VALIDATE_PBUF_QUEUED 0
84 #define IP_REASS_VALIDATE_PBUF_DROPPED -1
85 
94 #ifdef PACK_STRUCT_USE_INCLUDES
95 # include "arch/bpstruct.h"
96 #endif
98 struct ip_reass_helper {
99  PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
100  PACK_STRUCT_FIELD(u16_t start);
104 #ifdef PACK_STRUCT_USE_INCLUDES
105 # include "arch/epstruct.h"
106 #endif
107 
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
112 
113 /* global variables */
114 static struct ip_reassdata *reassdatagrams;
115 static u16_t ip_reass_pbufcount;
116 
117 /* function prototypes */
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);
120 
127 void
128 ip_reass_tmr(void)
129 {
130  struct ip_reassdata *r, *prev = NULL;
131 
132  r = reassdatagrams;
133  while (r != NULL) {
134  /* Decrement the timer. Once it reaches 0,
135  * clean up the incomplete fragment assembly */
136  if (r->timer > 0) {
137  r->timer--;
138  LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
139  prev = r;
140  r = r->next;
141  } else {
142  /* reassembly timed out */
143  struct ip_reassdata *tmp;
144  LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
145  tmp = r;
146  /* get the next pointer before freeing */
147  r = r->next;
148  /* free the helper struct and all enqueued pbufs */
149  ip_reass_free_complete_datagram(tmp, prev);
150  }
151  }
152 }
153 
163 static int
164 ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
165 {
166  u16_t pbufs_freed = 0;
167  u16_t clen;
168  struct pbuf *p;
169  struct ip_reass_helper *iprh;
170 
171  LWIP_ASSERT("prev != ipr", prev != ipr);
172  if (prev != NULL) {
173  LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
174  }
175 
176  MIB2_STATS_INC(mib2.ipreasmfails);
177 #if LWIP_ICMP
178  iprh = (struct ip_reass_helper *)ipr->p->payload;
179  if (iprh->start == 0) {
180  /* The first fragment was received, send ICMP time exceeded. */
181  /* First, de-queue the first pbuf from r->p. */
182  p = ipr->p;
183  ipr->p = iprh->next_pbuf;
184  /* Then, copy the original header into it. */
185  SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
186  icmp_time_exceeded(p, ICMP_TE_FRAG);
187  clen = pbuf_clen(p);
188  LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
189  pbufs_freed += clen;
190  pbuf_free(p);
191  }
192 #endif /* LWIP_ICMP */
193 
194  /* First, free all received pbufs. The individual pbufs need to be released
195  separately as they have not yet been chained */
196  p = ipr->p;
197  while (p != NULL) {
198  struct pbuf *pcur;
199  iprh = (struct ip_reass_helper *)p->payload;
200  pcur = p;
201  /* get the next pointer before freeing */
202  p = iprh->next_pbuf;
203  clen = pbuf_clen(pcur);
204  LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
205  pbufs_freed += clen;
206  pbuf_free(pcur);
207  }
208  /* Then, unchain the struct ip_reassdata from the list and free it. */
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;
212 
213  return pbufs_freed;
214 }
215 
216 #if IP_REASS_FREE_OLDEST
217 
226 static int
227 ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
228 {
229  /* @todo Can't we simply remove the last datagram in the
230  * linked list behind reassdatagrams?
231  */
232  struct ip_reassdata *r, *oldest, *prev, *oldest_prev;
233  int pbufs_freed = 0, pbufs_freed_current;
234  int other_datagrams;
235 
236  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
237  * but don't free the datagram that 'fraghdr' belongs to! */
238  do {
239  oldest = NULL;
240  prev = NULL;
241  oldest_prev = NULL;
242  other_datagrams = 0;
243  r = reassdatagrams;
244  while (r != NULL) {
245  if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
246  /* Not the same datagram as fraghdr */
247  other_datagrams++;
248  if (oldest == NULL) {
249  oldest = r;
250  oldest_prev = prev;
251  } else if (r->timer <= oldest->timer) {
252  /* older than the previous oldest */
253  oldest = r;
254  oldest_prev = prev;
255  }
256  }
257  if (r->next != NULL) {
258  prev = r;
259  }
260  r = r->next;
261  }
262  if (oldest != NULL) {
263  pbufs_freed_current = ip_reass_free_complete_datagram(oldest, oldest_prev);
264  pbufs_freed += pbufs_freed_current;
265  }
266  } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
267  return pbufs_freed;
268 }
269 #endif /* IP_REASS_FREE_OLDEST */
270 
277 static struct ip_reassdata*
278 ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
279 {
280  struct ip_reassdata* ipr;
281 #if ! IP_REASS_FREE_OLDEST
282  LWIP_UNUSED_ARG(clen);
283 #endif
284 
285  /* No matching previous fragment found, allocate a new reassdata struct */
286  ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
287  if (ipr == NULL) {
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);
291  }
292  if (ipr == NULL)
293 #endif /* IP_REASS_FREE_OLDEST */
294  {
295  IPFRAG_STATS_INC(ip_frag.memerr);
296  LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
297  return NULL;
298  }
299  }
300  memset(ipr, 0, sizeof(struct ip_reassdata));
301  ipr->timer = IP_REASS_MAXAGE;
302 
303  /* enqueue the new structure to the front of the list */
304  ipr->next = reassdatagrams;
305  reassdatagrams = ipr;
306  /* copy the ip header for later tests and input */
307  /* @todo: no ip options supported? */
308  SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
309  return ipr;
310 }
311 
316 static void
317 ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
318 {
319  /* dequeue the reass struct */
320  if (reassdatagrams == ipr) {
321  /* it was the first in the list */
322  reassdatagrams = ipr->next;
323  } else {
324  /* it wasn't the first, so it must have a valid 'prev' */
325  LWIP_ASSERT("sanity check linked list", prev != NULL);
326  prev->next = ipr->next;
327  }
328 
329  /* now we can free the ip_reassdata struct */
330  memp_free(MEMP_REASSDATA, ipr);
331 }
332 
343 static int
344 ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p, int is_last)
345 {
346  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
347  struct pbuf *q;
348  u16_t offset, len;
349  struct ip_hdr *fraghdr;
350  int valid = 1;
351 
352  /* Extract length and fragment offset from current fragment */
353  fraghdr = (struct ip_hdr*)new_p->payload;
354  len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
355  offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
356 
357  /* overwrite the fragment's ip header from the pbuf with our helper struct,
358  * and setup the embedded helper structure. */
359  /* make sure the struct ip_reass_helper fits into the IP header */
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;
366 
367  /* Iterate through until we either get to the end of the list (append),
368  * or we find one with a larger offset (insert). */
369  for (q = ipr->p; q != NULL;) {
370  iprh_tmp = (struct ip_reass_helper*)q->payload;
371  if (iprh->start < iprh_tmp->start) {
372  /* the new pbuf should be inserted before this */
373  iprh->next_pbuf = q;
374  if (iprh_prev != NULL) {
375  /* not the fragment with the lowest offset */
376 #if IP_REASS_CHECK_OVERLAP
377  if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
378  /* fragment overlaps with previous or following, throw away */
379  goto freepbuf;
380  }
381 #endif /* IP_REASS_CHECK_OVERLAP */
382  iprh_prev->next_pbuf = new_p;
383  if (iprh_prev->end != iprh->start) {
384  /* There is a fragment missing between the current
385  * and the previous fragment */
386  valid = 0;
387  }
388  } else {
389 #if IP_REASS_CHECK_OVERLAP
390  if (iprh->end > iprh_tmp->start) {
391  /* fragment overlaps with following, throw away */
392  goto freepbuf;
393  }
394 #endif /* IP_REASS_CHECK_OVERLAP */
395  /* fragment with the lowest offset */
396  ipr->p = new_p;
397  }
398  break;
399  } else if (iprh->start == iprh_tmp->start) {
400  /* received the same datagram twice: no need to keep the datagram */
401  goto freepbuf;
402 #if IP_REASS_CHECK_OVERLAP
403  } else if (iprh->start < iprh_tmp->end) {
404  /* overlap: no need to keep the new datagram */
405  goto freepbuf;
406 #endif /* IP_REASS_CHECK_OVERLAP */
407  } else {
408  /* Check if the fragments received so far have no holes. */
409  if (iprh_prev != NULL) {
410  if (iprh_prev->end != iprh_tmp->start) {
411  /* There is a fragment missing between the current
412  * and the previous fragment */
413  valid = 0;
414  }
415  }
416  }
417  q = iprh_tmp->next_pbuf;
418  iprh_prev = iprh_tmp;
419  }
420 
421  /* If q is NULL, then we made it to the end of the list. Determine what to do now */
422  if (q == NULL) {
423  if (iprh_prev != NULL) {
424  /* this is (for now), the fragment with the highest offset:
425  * chain it to the last fragment */
426 #if IP_REASS_CHECK_OVERLAP
427  LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
428 #endif /* IP_REASS_CHECK_OVERLAP */
429  iprh_prev->next_pbuf = new_p;
430  if (iprh_prev->end != iprh->start) {
431  valid = 0;
432  }
433  } else {
434 #if IP_REASS_CHECK_OVERLAP
435  LWIP_ASSERT("no previous fragment, this must be the first fragment!",
436  ipr->p == NULL);
437 #endif /* IP_REASS_CHECK_OVERLAP */
438  /* this is the first fragment we ever received for this ip datagram */
439  ipr->p = new_p;
440  }
441  }
442 
443  /* At this point, the validation part begins: */
444  /* If we already received the last fragment */
445  if (is_last || ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0)) {
446  /* and had no holes so far */
447  if (valid) {
448  /* then check if the rest of the fragments is here */
449  /* Check if the queue starts with the first datagram */
450  if ((ipr->p == NULL) || (((struct ip_reass_helper*)ipr->p->payload)->start != 0)) {
451  valid = 0;
452  } else {
453  /* and check that there are no holes after this datagram */
454  iprh_prev = iprh;
455  q = iprh->next_pbuf;
456  while (q != NULL) {
457  iprh = (struct ip_reass_helper*)q->payload;
458  if (iprh_prev->end != iprh->start) {
459  valid = 0;
460  break;
461  }
462  iprh_prev = iprh;
463  q = iprh->next_pbuf;
464  }
465  /* if still valid, all fragments are received
466  * (because to the MF==0 already arrived */
467  if (valid) {
468  LWIP_ASSERT("sanity check", ipr->p != NULL);
469  LWIP_ASSERT("sanity check",
470  ((struct ip_reass_helper*)ipr->p->payload) != iprh);
471  LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
472  iprh->next_pbuf == NULL);
473  }
474  }
475  }
476  /* If valid is 0 here, there are some fragments missing in the middle
477  * (since MF == 0 has already arrived). Such datagrams simply time out if
478  * no more fragments are received... */
479  return valid ? IP_REASS_VALIDATE_TELEGRAM_FINISHED : IP_REASS_VALIDATE_PBUF_QUEUED;
480  }
481  /* If we come here, not all fragments were received, yet! */
482  return IP_REASS_VALIDATE_PBUF_QUEUED; /* not yet valid! */
483 #if IP_REASS_CHECK_OVERLAP
484 freepbuf:
485  ip_reass_pbufcount -= pbuf_clen(new_p);
486  pbuf_free(new_p);
487  return IP_REASS_VALIDATE_PBUF_DROPPED;
488 #endif /* IP_REASS_CHECK_OVERLAP */
489 }
490 
497 struct pbuf *
498 ip4_reass(struct pbuf *p)
499 {
500  struct pbuf *r;
501  struct ip_hdr *fraghdr;
502  struct ip_reassdata *ipr;
503  struct ip_reass_helper *iprh;
504  u16_t offset, len, clen;
505  int valid;
506  int is_last;
507 
508  IPFRAG_STATS_INC(ip_frag.recv);
509  MIB2_STATS_INC(mib2.ipreasmreqds);
510 
511  fraghdr = (struct ip_hdr*)p->payload;
512 
513  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
514  LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: IP options currently not supported!\n"));
515  IPFRAG_STATS_INC(ip_frag.err);
516  goto nullreturn;
517  }
518 
519  offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
520  len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
521 
522  /* Check if we are allowed to enqueue more datagrams. */
523  clen = pbuf_clen(p);
524  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
525 #if IP_REASS_FREE_OLDEST
526  if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
527  ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
528 #endif /* IP_REASS_FREE_OLDEST */
529  {
530  /* No datagram could be freed and still too many pbufs enqueued */
531  LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
532  ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
533  IPFRAG_STATS_INC(ip_frag.memerr);
534  /* @todo: send ICMP time exceeded here? */
535  /* drop this pbuf */
536  goto nullreturn;
537  }
538  }
539 
540  /* Look for the datagram the fragment belongs to in the current datagram queue,
541  * remembering the previous in the queue for later dequeueing. */
542  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
543  /* Check if the incoming fragment matches the one currently present
544  in the reassembly buffer. If so, we proceed with copying the
545  fragment into the buffer. */
546  if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
547  LWIP_DEBUGF(IP_REASS_DEBUG, ("ip4_reass: matching previous fragment ID=%"X16_F"\n",
548  lwip_ntohs(IPH_ID(fraghdr))));
549  IPFRAG_STATS_INC(ip_frag.cachehit);
550  break;
551  }
552  }
553 
554  if (ipr == NULL) {
555  /* Enqueue a new datagram into the datagram queue */
556  ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
557  /* Bail if unable to enqueue */
558  if (ipr == NULL) {
559  goto nullreturn;
560  }
561  } else {
562  if (((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
563  ((lwip_ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
564  /* ipr->iphdr is not the header from the first fragment, but fraghdr is
565  * -> copy fraghdr into ipr->iphdr since we want to have the header
566  * of the first fragment (for ICMP time exceeded and later, for copying
567  * all options, if supported)*/
568  SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
569  }
570  }
571 
572  /* At this point, we have either created a new entry or pointing
573  * to an existing one */
574 
575  /* check for 'no more fragments', and update queue entry*/
576  is_last = (IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0;
577  if (is_last) {
578  u16_t datagram_len = (u16_t)(offset + len);
579  if ((datagram_len < offset) || (datagram_len > (0xFFFF - IP_HLEN))) {
580  /* u16_t overflow, cannot handle this */
581  goto nullreturn;
582  }
583  }
584  /* find the right place to insert this pbuf */
585  /* @todo: trim pbufs if fragments are overlapping */
586  valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p, is_last);
587  if (valid == IP_REASS_VALIDATE_PBUF_DROPPED) {
588  goto nullreturn;
589  }
590  /* if we come here, the pbuf has been enqueued */
591 
592  /* Track the current number of pbufs current 'in-flight', in order to limit
593  the number of fragments that may be enqueued at any one time
594  (overflow checked by testing against IP_REASS_MAX_PBUFS) */
595  ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount + clen);
596  if (is_last) {
597  u16_t datagram_len = (u16_t)(offset + len);
598  ipr->datagram_len = datagram_len;
599  ipr->flags |= IP_REASS_FLAG_LASTFRAG;
601  ("ip4_reass: last fragment seen, total len %"S16_F"\n",
602  ipr->datagram_len));
603  }
604 
605  if (valid == IP_REASS_VALIDATE_TELEGRAM_FINISHED) {
606  struct ip_reassdata *ipr_prev;
607  /* the totally last fragment (flag more fragments = 0) was received at least
608  * once AND all fragments are received */
609  ipr->datagram_len += IP_HLEN;
610 
611  /* save the second pbuf before copying the header over the pointer */
612  r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
613 
614  /* copy the original ip header back to the first pbuf */
615  fraghdr = (struct ip_hdr*)(ipr->p->payload);
616  SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
617  IPH_LEN_SET(fraghdr, lwip_htons(ipr->datagram_len));
618  IPH_OFFSET_SET(fraghdr, 0);
619  IPH_CHKSUM_SET(fraghdr, 0);
620  /* @todo: do we need to set/calculate the correct checksum? */
621 #if CHECKSUM_GEN_IP
622  IF__NETIF_CHECKSUM_ENABLED(ip_current_input_netif(), NETIF_CHECKSUM_GEN_IP) {
623  IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
624  }
625 #endif /* CHECKSUM_GEN_IP */
626 
627  p = ipr->p;
628 
629  /* chain together the pbufs contained within the reass_data list. */
630  while (r != NULL) {
631  iprh = (struct ip_reass_helper*)r->payload;
632 
633  /* hide the ip header for every succeeding fragment */
634  pbuf_header(r, -IP_HLEN);
635  pbuf_cat(p, r);
636  r = iprh->next_pbuf;
637  }
638 
639  /* find the previous entry in the linked list */
640  if (ipr == reassdatagrams) {
641  ipr_prev = NULL;
642  } else {
643  for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) {
644  if (ipr_prev->next == ipr) {
645  break;
646  }
647  }
648  }
649 
650  /* release the sources allocate for the fragment queue entry */
651  ip_reass_dequeue_datagram(ipr, ipr_prev);
652 
653  /* and adjust the number of pbufs currently queued for reassembly. */
654  ip_reass_pbufcount -= pbuf_clen(p);
655 
656  MIB2_STATS_INC(mib2.ipreasmoks);
657 
658  /* Return the pbuf chain */
659  return p;
660  }
661  /* the datagram is not (yet?) reassembled completely */
662  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
663  return NULL;
664 
665 nullreturn:
666  LWIP_DEBUGF(IP_REASS_DEBUG,("ip4_reass: nullreturn\n"));
667  IPFRAG_STATS_INC(ip_frag.drop);
668  pbuf_free(p);
669  return NULL;
670 }
671 #endif /* IP_REASSEMBLY */
672 
673 #if IP_FRAG
674 #if !LWIP_NETIF_TX_SINGLE_PBUF
675 
676 static struct pbuf_custom_ref*
677 ip_frag_alloc_pbuf_custom_ref(void)
678 {
679  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
680 }
681 
683 static void
684 ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
685 {
686  LWIP_ASSERT("p != NULL", p != NULL);
687  memp_free(MEMP_FRAG_PBUF, p);
688 }
689 
692 static void
693 ipfrag_free_pbuf_custom(struct pbuf *p)
694 {
695  struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
696  LWIP_ASSERT("pcr != NULL", pcr != NULL);
697  LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
698  if (pcr->original != NULL) {
699  pbuf_free(pcr->original);
700  }
701  ip_frag_free_pbuf_custom_ref(pcr);
702 }
703 #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
704 
717 err_t
718 ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
719 {
720  struct pbuf *rambuf;
721 #if !LWIP_NETIF_TX_SINGLE_PBUF
722  struct pbuf *newpbuf;
723  u16_t newpbuflen = 0;
724  u16_t left_to_copy;
725 #endif
726  struct ip_hdr *original_iphdr;
727  struct ip_hdr *iphdr;
728  const u16_t nfb = (netif->mtu - IP_HLEN) / 8;
729  u16_t left, fragsize;
730  u16_t ofo;
731  int last;
732  u16_t poff = IP_HLEN;
733  u16_t tmp;
734 
735  original_iphdr = (struct ip_hdr *)p->payload;
736  iphdr = original_iphdr;
737  LWIP_ERROR("ip4_frag() does not support IP options", IPH_HL(iphdr) * 4 == IP_HLEN, return ERR_VAL);
738 
739  /* Save original offset */
740  tmp = lwip_ntohs(IPH_OFFSET(iphdr));
741  ofo = tmp & IP_OFFMASK;
742  LWIP_ERROR("ip_frag(): MF already set", (tmp & IP_MF) == 0, return ERR_VAL);
743 
744  left = p->tot_len - IP_HLEN;
745 
746  while (left) {
747  /* Fill this fragment */
748  fragsize = LWIP_MIN(left, nfb * 8);
749 
750 #if LWIP_NETIF_TX_SINGLE_PBUF
751  rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM);
752  if (rambuf == NULL) {
753  goto memerr;
754  }
755  LWIP_ASSERT("this needs a pbuf in one piece!",
756  (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
757  poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff);
758  /* make room for the IP header */
759  if (pbuf_header(rambuf, IP_HLEN)) {
760  pbuf_free(rambuf);
761  goto memerr;
762  }
763  /* fill in the IP header */
764  SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
765  iphdr = (struct ip_hdr*)rambuf->payload;
766 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
767  /* When not using a static buffer, create a chain of pbufs.
768  * The first will be a PBUF_RAM holding the link and IP header.
769  * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
770  * but limited to the size of an mtu.
771  */
772  rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
773  if (rambuf == NULL) {
774  goto memerr;
775  }
776  LWIP_ASSERT("this needs a pbuf in one piece!",
777  (p->len >= (IP_HLEN)));
778  SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
779  iphdr = (struct ip_hdr *)rambuf->payload;
780 
781  left_to_copy = fragsize;
782  while (left_to_copy) {
783  struct pbuf_custom_ref *pcr;
784  u16_t plen = p->len - poff;
785  newpbuflen = LWIP_MIN(left_to_copy, plen);
786  /* Is this pbuf already empty? */
787  if (!newpbuflen) {
788  poff = 0;
789  p = p->next;
790  continue;
791  }
792  pcr = ip_frag_alloc_pbuf_custom_ref();
793  if (pcr == NULL) {
794  pbuf_free(rambuf);
795  goto memerr;
796  }
797  /* Mirror this pbuf, although we might not need all of it. */
798  newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc,
799  (u8_t*)p->payload + poff, newpbuflen);
800  if (newpbuf == NULL) {
801  ip_frag_free_pbuf_custom_ref(pcr);
802  pbuf_free(rambuf);
803  goto memerr;
804  }
805  pbuf_ref(p);
806  pcr->original = p;
807  pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
808 
809  /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
810  * so that it is removed when pbuf_dechain is later called on rambuf.
811  */
812  pbuf_cat(rambuf, newpbuf);
813  left_to_copy -= newpbuflen;
814  if (left_to_copy) {
815  poff = 0;
816  p = p->next;
817  }
818  }
819  poff += newpbuflen;
820 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
821 
822  /* Correct header */
823  last = (left <= netif->mtu - IP_HLEN);
824 
825  /* Set new offset and MF flag */
826  tmp = (IP_OFFMASK & (ofo));
827  if (!last) {
828  tmp = tmp | IP_MF;
829  }
830  IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
831  IPH_LEN_SET(iphdr, lwip_htons(fragsize + IP_HLEN));
832  IPH_CHKSUM_SET(iphdr, 0);
833 #if CHECKSUM_GEN_IP
834  IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
835  IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
836  }
837 #endif /* CHECKSUM_GEN_IP */
838 
839  /* No need for separate header pbuf - we allowed room for it in rambuf
840  * when allocated.
841  */
842  netif->output(netif, rambuf, dest);
843  IPFRAG_STATS_INC(ip_frag.xmit);
844 
845  /* Unfortunately we can't reuse rambuf - the hardware may still be
846  * using the buffer. Instead we free it (and the ensuing chain) and
847  * recreate it next time round the loop. If we're lucky the hardware
848  * will have already sent the packet, the free will really free, and
849  * there will be zero memory penalty.
850  */
851 
852  pbuf_free(rambuf);
853  left -= fragsize;
854  ofo += nfb;
855  }
856  MIB2_STATS_INC(mib2.ipfragoks);
857  return ERR_OK;
858 memerr:
859  MIB2_STATS_INC(mib2.ipfragfails);
860  return ERR_MEM;
861 }
862 #endif /* IP_FRAG */
863 
864 #endif /* LWIP_IPV4 */
S16_F
#define S16_F
Definition: arch.h:151
lwip_ntohs
#define lwip_ntohs(x)
Definition: def.h:76
opt.h
pbuf::len
u16_t len
Definition: pbuf.h:159
PBUF_LINK
Definition: pbuf.h:85
def.h
LWIP_ASSERT
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
PBUF_RAW
Definition: pbuf.h:94
u16_t
uint16_t u16_t
Definition: arch.h:124
PACK_STRUCT_FIELD
#define PACK_STRUCT_FIELD(x)
Definition: cc.h:6
string.h
PACK_STRUCT_STRUCT
#define PACK_STRUCT_STRUCT
Definition: cc.h:7
PBUF_IP
Definition: pbuf.h:80
ip4_frag.h
pbuf::tot_len
u16_t tot_len
Definition: pbuf.h:156
pbuf_clen
u16_t pbuf_clen(const struct pbuf *p)
Definition: pbuf.c:801
pbuf::next
struct pbuf * next
Definition: pbuf.h:144
pbuf_free
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:715
netif::mtu
u16_t mtu
Definition: netif.h:307
memp_malloc
void * memp_malloc(memp_t type)
Definition: memp.c:385
LWIP_MIN
#define LWIP_MIN(x, y)
Definition: def.h:55
X16_F
#define X16_F
Definition: arch.h:154
memp_free
void memp_free(memp_t type, void *mem)
Definition: memp.c:469
IP_HLEN
#define IP_HLEN
Definition: ip4.h:64
IF__NETIF_CHECKSUM_ENABLED
#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag)
Definition: netif.h:357
icmp.h
ip_hdr
Definition: ip4.h:71
stats.h
ERR_MEM
Definition: err.h:65
pbuf_copy_partial
u16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1016
IPH_HL
#define IPH_HL(hdr)
Definition: ip4.h:103
netif.h
LWIP_ERROR
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:135
IP_OFFMASK
#define IP_OFFMASK
Definition: ip4.h:85
pbuf_alloc
struct pbuf * pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)
Definition: pbuf.c:248
IP_REASS_MAXAGE
#define IP_REASS_MAXAGE
Definition: lwipopts.h:119
u8_t
uint8_t u8_t
Definition: arch.h:122
PACK_STRUCT_BEGIN
#define PACK_STRUCT_BEGIN
Definition: cc.h:8
netif
Definition: netif.h:233
IPFRAG_STATS_INC
#define IPFRAG_STATS_INC(x)
Definition: stats.h:368
MIB2_STATS_INC
#define MIB2_STATS_INC(x)
Definition: stats.h:467
LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:315
IPH_LEN_SET
#define IPH_LEN_SET(hdr, len)
Definition: ip4.h:115
IP_MF
#define IP_MF
Definition: ip4.h:84
IPH_ID
#define IPH_ID(hdr)
Definition: ip4.h:106
ip_current_input_netif
#define ip_current_input_netif()
Definition: ip.h:137
IP_REASS_DEBUG
#define IP_REASS_DEBUG
Definition: lwipopts.h:451
lwip_htons
u16_t lwip_htons(u16_t n)
Definition: def.c:75
PP_NTOHS
#define PP_NTOHS(x)
Definition: def.h:80
pbuf_ref
void pbuf_ref(struct pbuf *p)
Definition: pbuf.c:821
pbuf_cat
void pbuf_cat(struct pbuf *head, struct pbuf *tail)
Definition: pbuf.c:841
PBUF_RAM
Definition: pbuf.h:108
U16_F
#define U16_F
Definition: arch.h:148
ERR_OK
Definition: err.h:63
err_t
s8_t err_t
Definition: err.h:57
IPH_CHKSUM_SET
#define IPH_CHKSUM_SET(hdr, chksum)
Definition: ip4.h:120
IPH_OFFSET
#define IPH_OFFSET(hdr)
Definition: ip4.h:107
ICMP_TE_FRAG
Definition: icmp.h:75
inet_chksum
u16_t inet_chksum(const void *dataptr, u16_t len)
Definition: inet_chksum.c:555
memset
void * memset(void *dst, int c, size_t length)
IPH_LEN
#define IPH_LEN(hdr)
Definition: ip4.h:105
IP_REASS_MAX_PBUFS
#define IP_REASS_MAX_PBUFS
Definition: lwipopts.h:121
SMEMCPY
#define SMEMCPY(dst, src, len)
Definition: lwipopts.h:44
ERR_VAL
Definition: err.h:75
pbuf
Definition: pbuf.h:142
LWIP_DEBUGF
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:164
IPH_OFFSET_SET
#define IPH_OFFSET_SET(hdr, off)
Definition: ip4.h:117
inet_chksum.h
pbuf_header
u8_t pbuf_header(struct pbuf *p, s16_t header_size)
Definition: pbuf.c:665
PBUF_REF
Definition: pbuf.h:116
pbuf::payload
void * payload
Definition: pbuf.h:147
PACK_STRUCT_END
#define PACK_STRUCT_END
Definition: cc.h:9
NULL
#define NULL
Definition: fat_string.h:17