ipv4_frag.c
Go to the documentation of this file.
1 /**
2  * @file ipv4_frag.c
3  * @brief IPv4 fragmentation and reassembly
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Internet Protocol (IP) implements datagram fragmentation, so that
30  * packets may be formed that can pass through a link with a smaller maximum
31  * transmission unit (MTU) than the original datagram size. Refer to the
32  * following RFCs for complete details:
33  * - RFC 791: Internet Protocol specification
34  * - RFC 815: IP datagram reassembly algorithms
35  *
36  * @author Oryx Embedded SARL (www.oryx-embedded.com)
37  * @version 1.9.6
38  **/
39 
40 //Switch to the appropriate trace level
41 #define TRACE_LEVEL IPV4_TRACE_LEVEL
42 
43 //Dependencies
44 #include "core/net.h"
45 #include "core/ip.h"
46 #include "ipv4/ipv4.h"
47 #include "ipv4/ipv4_frag.h"
48 #include "ipv4/icmp.h"
49 #include "mibs/mib2_module.h"
50 #include "mibs/ip_mib_module.h"
51 #include "debug.h"
52 
53 //Check TCP/IP stack configuration
54 #if (IPV4_SUPPORT == ENABLED && IPV4_FRAG_SUPPORT == ENABLED)
55 
56 //Tick counter to handle periodic operations
58 
59 
60 /**
61  * @brief Fragment an IPv4 datagram into smaller packets
62  * @param[in] interface Underlying network interface
63  * @param[in] pseudoHeader IPv4 pseudo header
64  * @param[in] id Fragment identification
65  * @param[in] payload Multi-part buffer containing the payload
66  * @param[in] payloadOffset Offset to the first payload byte
67  * @param[in] flags Set of flags that influences the behavior of this function
68  * @return Error code
69  **/
70 
72  Ipv4PseudoHeader *pseudoHeader, uint16_t id, const NetBuffer *payload,
73  size_t payloadOffset, uint_t flags)
74 {
75  error_t error;
76  size_t offset;
77  size_t length;
78  size_t payloadLen;
79  size_t fragmentOffset;
80  size_t maxFragmentSize;
81  NetBuffer *fragment;
82 
83  //Number of IP datagrams that would require fragmentation in order to be transmitted
84  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutFragReqds, 1);
85  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsOutFragReqds, 1);
86 
87  //Retrieve the length of the payload
88  payloadLen = netBufferGetLength(payload) - payloadOffset;
89 
90  //Allocate a memory buffer to hold IP fragments
91  fragment = ipAllocBuffer(0, &fragmentOffset);
92  //Failed to allocate memory?
93  if(!fragment)
94  return ERROR_OUT_OF_MEMORY;
95 
96  //Determine the maximum payload size for fragmented packets
97  maxFragmentSize = interface->ipv4Context.linkMtu - sizeof(Ipv4Header);
98  //The size shall be a multiple of 8-byte blocks
99  maxFragmentSize -= (maxFragmentSize % 8);
100 
101  //Initialize error code
102  error = NO_ERROR;
103 
104  //Split the payload into multiple IP fragments
105  for(offset = 0; offset < payloadLen; offset += length)
106  {
107  //Flush the contents of the fragment
108  error = netBufferSetLength(fragment, fragmentOffset);
109  //Sanity check
110  if(error)
111  break;
112 
113  //Process the last fragment?
114  if((payloadLen - offset) <= maxFragmentSize)
115  {
116  //Size of the current fragment
117  length = payloadLen - offset;
118  //Copy fragment data
119  netBufferConcat(fragment, payload, payloadOffset + offset, length);
120 
121  //Do not set the MF flag for the last fragment
122  error = ipv4SendPacket(interface, pseudoHeader, id,
123  offset / 8, fragment, fragmentOffset, flags);
124  }
125  else
126  {
127  //Size of the current fragment (must be a multiple of 8-byte blocks)
128  length = maxFragmentSize;
129  //Copy fragment data
130  netBufferConcat(fragment, payload, payloadOffset + offset, length);
131 
132  //Fragmented packets must have the MF flag set
133  error = ipv4SendPacket(interface, pseudoHeader, id,
134  IPV4_FLAG_MF | (offset / 8), fragment, fragmentOffset, flags);
135  }
136 
137  //Failed to send current IP packet?
138  if(error)
139  break;
140 
141  //Number of IP datagram fragments that have been generated as a result
142  //of fragmentation at this entity
143  MIB2_INC_COUNTER32(ipGroup.ipFragCreates, 1);
144  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutFragCreates, 1);
145  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsOutFragCreates, 1);
146  }
147 
148  //Check status code
149  if(error)
150  {
151  //Number of IP datagrams that have been discarded because they needed
152  //to be fragmented at this entity but could not be
153  MIB2_INC_COUNTER32(ipGroup.ipFragFails, 1);
154  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutFragFails, 1);
155  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsOutFragFails, 1);
156  }
157  else
158  {
159  //Number of IP datagrams that have been successfully fragmented at this entity
160  MIB2_INC_COUNTER32(ipGroup.ipFragOKs, 1);
161  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsOutFragOKs, 1);
162  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsOutFragOKs, 1);
163  }
164 
165  //Free previously allocated memory
166  netBufferFree(fragment);
167  //Return status code
168  return error;
169 }
170 
171 
172 /**
173  * @brief IPv4 datagram reassembly algorithm
174  * @param[in] interface Underlying network interface
175  * @param[in] packet Pointer to the IPv4 fragmented packet
176  * @param[in] length Packet length including header and payload
177  **/
178 
180  const Ipv4Header *packet, size_t length)
181 {
182  error_t error;
183  uint16_t offset;
184  uint16_t dataFirst;
185  uint16_t dataLast;
186  Ipv4FragDesc *frag;
187  Ipv4HoleDesc *hole;
188  Ipv4HoleDesc *prevHole;
189 
190  //Number of IP fragments received which needed to be reassembled
191  MIB2_INC_COUNTER32(ipGroup.ipReasmReqds, 1);
192  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmReqds, 1);
193  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmReqds, 1);
194 
195  //Get the length of the payload
196  length -= packet->headerLength * 4;
197  //Convert the fragment offset from network byte order
198  offset = ntohs(packet->fragmentOffset);
199 
200  //Every fragment except the last must contain a multiple of 8 bytes of data
201  if((offset & IPV4_FLAG_MF) && (length % 8))
202  {
203  //Number of failures detected by the IP reassembly algorithm
204  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
205  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
206  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
207 
208  //Drop the incoming fragment
209  return;
210  }
211 
212  //Calculate the index of the first byte
213  dataFirst = (offset & IPV4_OFFSET_MASK) * 8;
214  //Calculate the index immediately following the last byte
215  dataLast = dataFirst + (uint16_t) length;
216 
217  //Search for a matching IP datagram being reassembled
218  frag = ipv4SearchFragQueue(interface, packet);
219 
220  //No matching entry in the reassembly queue?
221  if(frag == NULL)
222  {
223  //Number of failures detected by the IP reassembly algorithm
224  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
225  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
226  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
227 
228  //Drop the incoming fragment
229  return;
230  }
231 
232  //The very first fragment requires special handling
233  if(!(offset & IPV4_OFFSET_MASK))
234  {
235  //Calculate the length of the IP header including options
236  frag->headerLength = packet->headerLength * 4;
237 
238  //Enforce the size of the reconstructed datagram
239  if((frag->headerLength + frag->dataLen) > IPV4_MAX_FRAG_DATAGRAM_SIZE)
240  {
241  //Number of failures detected by the IP reassembly algorithm
242  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
243  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
244  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
245 
246  //Drop the reconstructed datagram
247  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
248  //Exit immediately
249  return;
250  }
251 
252  //Make sure the IP header entirely fits in the first chunk
253  if(frag->headerLength > frag->buffer.chunk[0].size)
254  {
255  //Number of failures detected by the IP reassembly algorithm
256  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
257  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
258  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
259 
260  //Drop the reconstructed datagram
261  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
262  //Exit immediately
263  return;
264  }
265 
266  //Fix the length of the first chunk
267  frag->buffer.chunk[0].length = (uint16_t) frag->headerLength;
268  //Always take the IP header from the first fragment
269  netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->headerLength);
270  }
271 
272  //It may be necessary to increase the size of the buffer...
273  if(dataLast > frag->dataLen)
274  {
275  //Enforce the size of the reconstructed datagram
276  if((frag->headerLength + dataLast) > IPV4_MAX_FRAG_DATAGRAM_SIZE)
277  {
278  //Number of failures detected by the IP reassembly algorithm
279  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
280  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
281  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
282 
283  //Drop the reconstructed datagram
284  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
285  //Exit immediately
286  return;
287  }
288 
289  //Adjust the size of the reconstructed datagram
290  error = netBufferSetLength((NetBuffer *) &frag->buffer,
291  frag->headerLength + dataLast + sizeof(Ipv4HoleDesc));
292 
293  //Any error to report?
294  if(error)
295  {
296  //Number of failures detected by the IP reassembly algorithm
297  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
298  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
299  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
300 
301  //Drop the reconstructed datagram
302  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
303  //Exit immediately
304  return;
305  }
306 
307  //Actual length of the payload
308  frag->dataLen = dataLast;
309  }
310 
311  //Select the first hole descriptor from the list
312  hole = ipv4FindHole(frag, frag->firstHole);
313  //Keep track of the previous hole in the list
314  prevHole = NULL;
315 
316  //Iterate through the hole descriptors
317  while(hole != NULL)
318  {
319  //Save lower and upper boundaries for later use
320  uint16_t holeFirst = hole->first;
321  uint16_t holeLast = hole->last;
322 
323  //Check whether the newly arrived fragment interacts with this hole
324  //in some way
325  if(dataFirst < holeLast && dataLast > holeFirst)
326  {
327  //The current descriptor is no longer valid. We will destroy it,
328  //and in the next two steps, we will determine whether or not it
329  //is necessary to create any new hole descriptors
330  if(prevHole != NULL)
331  prevHole->next = hole->next;
332  else
333  frag->firstHole = hole->next;
334 
335  //Is there still a hole at the beginning of the segment?
336  if(dataFirst > holeFirst)
337  {
338  //Create a new entry that describes this hole
339  hole = ipv4FindHole(frag, holeFirst);
340  hole->first = holeFirst;
341  hole->last = dataFirst;
342 
343  //Insert the newly created entry into the hole descriptor list
344  if(prevHole != NULL)
345  {
346  hole->next = prevHole->next;
347  prevHole->next = hole->first;
348  }
349  else
350  {
351  hole->next = frag->firstHole;
352  frag->firstHole = hole->first;
353  }
354 
355  //Always keep track of the previous hole
356  prevHole = hole;
357  }
358 
359  //Is there still a hole at the end of the segment?
360  if(dataLast < holeLast && (offset & IPV4_FLAG_MF))
361  {
362  //Create a new entry that describes this hole
363  hole = ipv4FindHole(frag, dataLast);
364  hole->first = dataLast;
365  hole->last = holeLast;
366 
367  //Insert the newly created entry into the hole descriptor list
368  if(prevHole != NULL)
369  {
370  hole->next = prevHole->next;
371  prevHole->next = hole->first;
372  }
373  else
374  {
375  hole->next = frag->firstHole;
376  frag->firstHole = hole->first;
377  }
378 
379  //Always keep track of the previous hole
380  prevHole = hole;
381  }
382  }
383  else
384  {
385  //The newly arrived fragment does not interact with the current hole
386  prevHole = hole;
387  }
388 
389  //Select the next hole descriptor from the list
390  hole = ipv4FindHole(frag, prevHole ? prevHole->next : frag->firstHole);
391  }
392 
393  //Copy data from the fragment to the reassembly buffer
394  netBufferWrite((NetBuffer *) &frag->buffer,
395  frag->headerLength + dataFirst, IPV4_DATA(packet), length);
396 
397  //Dump hole descriptor list
398  ipv4DumpHoleList(frag);
399 
400  //If the hole descriptor list is empty, the reassembly process is now complete
401  if(!ipv4FindHole(frag, frag->firstHole))
402  {
403  //Discard the extra hole descriptor that follows the reconstructed datagram
404  error = netBufferSetLength((NetBuffer *) &frag->buffer,
405  frag->headerLength + frag->dataLen);
406 
407  //Check status code
408  if(error)
409  {
410  //Number of failures detected by the IP reassembly algorithm
411  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
412  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
413  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
414  }
415  else
416  {
417  //Point to the IP header
418  Ipv4Header *datagram = netBufferAt((NetBuffer *) &frag->buffer, 0);
419 
420  //Fix IP header
421  datagram->totalLength = htons(frag->headerLength + frag->dataLen);
422  datagram->fragmentOffset = 0;
423  datagram->headerChecksum = 0;
424 
425  //Number of IP datagrams successfully reassembled
426  MIB2_INC_COUNTER32(ipGroup.ipReasmOKs, 1);
427  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmOKs, 1);
428  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmOKs, 1);
429 
430  //Pass the original IPv4 datagram to the higher protocol layer
431  ipv4ProcessDatagram(interface, (NetBuffer *) &frag->buffer);
432  }
433 
434  //Release previously allocated memory
435  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
436  }
437 }
438 
439 
440 /**
441  * @brief Fragment reassembly timeout handler
442  *
443  * This routine must be periodically called by the TCP/IP stack to
444  * handle IPv4 fragment reassembly timeout
445  *
446  * @param[in] interface Underlying network interface
447  **/
448 
449 void ipv4FragTick(NetInterface *interface)
450 {
451  error_t error;
452  uint_t i;
453  systime_t time;
454  Ipv4HoleDesc *hole;
455 
456  //Get current time
457  time = osGetSystemTime();
458 
459  //Loop through the reassembly queue
460  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
461  {
462  //Point to the current entry in the reassembly queue
463  Ipv4FragDesc *frag = &interface->ipv4Context.fragQueue[i];
464 
465  //Make sure the entry is currently in use
466  if(frag->buffer.chunkCount > 0)
467  {
468  //If the timer runs out, the partially-reassembled datagram must be
469  //discarded and ICMP Time Exceeded message sent to the source host
470  if((time - frag->timestamp) >= IPV4_FRAG_TIME_TO_LIVE)
471  {
472  //Debug message
473  TRACE_INFO("IPv4 fragment reassembly timeout...\r\n");
474  //Dump IP header contents for debugging purpose
476 
477  //Number of failures detected by the IP reassembly algorithm
478  MIB2_INC_COUNTER32(ipGroup.ipReasmFails, 1);
479  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
480  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
481 
482  //Point to the first hole descriptor
483  hole = ipv4FindHole(frag, frag->firstHole);
484 
485  //Make sure the fragment zero has been received
486  //before sending an ICMP message
487  if(hole != NULL && hole->first > 0)
488  {
489  //Fix the size of the reconstructed datagram
490  error = netBufferSetLength((NetBuffer *) &frag->buffer,
491  frag->headerLength + hole->first);
492 
493  //Check status code
494  if(!error)
495  {
496  //Send an ICMP Time Exceeded message
499  }
500  }
501 
502  //Drop the partially reconstructed datagram
503  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
504  }
505  }
506  }
507 }
508 
509 
510 /**
511  * @brief Search for a matching datagram in the reassembly queue
512  * @param[in] interface Underlying network interface
513  * @param[in] packet Incoming IPv4 packet
514  * @return Matching fragment descriptor
515  **/
516 
518  const Ipv4Header *packet)
519 {
520  error_t error;
521  uint_t i;
522  Ipv4Header *datagram;
523  Ipv4FragDesc *frag;
524  Ipv4HoleDesc *hole;
525 
526  //Search for a matching IP datagram being reassembled
527  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
528  {
529  //Point to the current entry in the reassembly queue
530  frag = &interface->ipv4Context.fragQueue[i];
531 
532  //Check whether the current entry is used?
533  if(frag->buffer.chunkCount > 0)
534  {
535  //Point to the corresponding datagram
536  datagram = netBufferAt((NetBuffer *) &frag->buffer, 0);
537 
538  //Check source and destination addresses
539  if(datagram->srcAddr != packet->srcAddr)
540  continue;
541  if(datagram->destAddr != packet->destAddr)
542  continue;
543  //Compare identification and protocol fields
544  if(datagram->identification != packet->identification)
545  continue;
546  if(datagram->protocol != packet->protocol)
547  continue;
548 
549  //A matching entry has been found in the reassembly queue
550  return frag;
551  }
552  }
553 
554  //If the current packet does not match an existing entry
555  //in the reassembly queue, then create a new entry
556  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
557  {
558  //Point to the current entry in the reassembly queue
559  frag = &interface->ipv4Context.fragQueue[i];
560 
561  //The current entry is free?
562  if(!frag->buffer.chunkCount)
563  {
564  //Number of chunks that comprise the reassembly buffer
565  frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk);
566 
567  //Allocate sufficient memory to hold the IPv4 header and
568  //the first hole descriptor
569  error = netBufferSetLength((NetBuffer *) &frag->buffer,
571 
572  //Failed to allocate memory?
573  if(error)
574  {
575  //Clean up side effects
576  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
577  //Exit immediately
578  return NULL;
579  }
580 
581  //Initial length of the reconstructed datagram
582  frag->headerLength = packet->headerLength * 4;
583  frag->dataLen = 0;
584 
585  //Fix the length of the first chunk
586  frag->buffer.chunk[0].length = (uint16_t) frag->headerLength;
587  //Copy IPv4 header from the incoming fragment
588  netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->headerLength);
589 
590  //Save current time
591  frag->timestamp = osGetSystemTime();
592  //Create a new entry in the hole descriptor list
593  frag->firstHole = 0;
594 
595  //Point to first hole descriptor
596  hole = ipv4FindHole(frag, frag->firstHole);
597  //The entry describes the datagram as being completely missing
598  hole->first = 0;
599  hole->last = IPV4_INFINITY;
600  hole->next = IPV4_INFINITY;
601 
602  //Dump hole descriptor list
603  ipv4DumpHoleList(frag);
604 
605  //Return the matching fragment descriptor
606  return frag;
607  }
608  }
609 
610  //The reassembly queue is full
611  return NULL;
612 }
613 
614 
615 /**
616  * @brief Flush IPv4 reassembly queue
617  * @param[in] interface Underlying network interface
618  **/
619 
621 {
622  uint_t i;
623 
624  //Loop through the reassembly queue
625  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
626  {
627  //Drop any partially reconstructed datagram
628  netBufferSetLength((NetBuffer *) &interface->ipv4Context.fragQueue[i].buffer, 0);
629  }
630 }
631 
632 
633 /**
634  * @brief Retrieve hole descriptor
635  * @param[in] frag IPv4 fragment descriptor
636  * @param[in] offset Offset of the hole
637  * @return A pointer to the hole descriptor is returned if the
638  * specified offset is valid. Otherwise NULL is returned
639  **/
640 
641 Ipv4HoleDesc *ipv4FindHole(Ipv4FragDesc *frag, uint16_t offset)
642 {
643  //Return a pointer to the hole descriptor
644  return netBufferAt((NetBuffer *) &frag->buffer, frag->headerLength + offset);
645 }
646 
647 
648 /**
649  * @brief Dump hole descriptor list
650  * @param[in] frag IPv4 fragment descriptor
651  **/
652 
654 {
655 //Check debugging level
656 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
657  Ipv4HoleDesc *hole;
658 
659  //Debug message
660  TRACE_DEBUG("Hole descriptor list:\r\n");
661  //Select the first hole descriptor from the list
662  hole = ipv4FindHole(frag, frag->firstHole);
663 
664  //Loop through the hole descriptor list
665  while(hole != NULL)
666  {
667  //Display current hole
668  TRACE_DEBUG(" %" PRIu16 " - %" PRIu16 "\r\n", hole->first, hole->last);
669  //Select the next hole descriptor from the list
670  hole = ipv4FindHole(frag, hole->next);
671  }
672 #endif
673 }
674 
675 #endif
systime_t timestamp
Time at which the first fragment was received.
Definition: ipv4_frag.h:125
#define htons(value)
Definition: cpu_endian.h:392
MIB-II module.
systime_t ipv4FragTickCounter
Definition: ipv4_frag.c:57
uint8_t length
Definition: dtls_misc.h:149
error_t ipv4FragmentDatagram(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t id, const NetBuffer *payload, size_t payloadOffset, uint_t flags)
Fragment an IPv4 datagram into smaller packets.
Definition: ipv4_frag.c:71
ChunkDesc chunk[N(IPV4_MAX_FRAG_DATAGRAM_SIZE)+1]
Definition: ipv4_frag.h:115
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:637
#define Ipv4Header
Definition: ipv4.h:36
void ipv4FragTick(NetInterface *interface)
Fragment reassembly timeout handler.
Definition: ipv4_frag.c:449
@ IPV4_OFFSET_MASK
Definition: ipv4.h:204
void ipv4FlushFragQueue(NetInterface *interface)
Flush IPv4 reassembly queue.
Definition: ipv4_frag.c:620
#define IP_MIB_INC_COUNTER32(name, value)
Definition: ip_mib_module.h:46
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ICMP_TYPE_TIME_EXCEEDED
Definition: icmp.h:58
#define IPV4_MAX_FRAG_DATAGRAM_SIZE
Definition: ipv4_frag.h:62
void ipv4DumpHoleList(Ipv4FragDesc *frag)
Dump hole descriptor list.
Definition: ipv4_frag.c:653
error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, uint_t flags)
Send an IPv4 packet.
Definition: ipv4.c:946
error_t netBufferConcat(NetBuffer *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Concatenate two multi-part buffers.
Definition: net_mem.c:442
void ipv4DumpHeader(const Ipv4Header *ipHeader)
Dump IPv4 header for debugging purpose.
Definition: ipv4.c:1490
#define NET_MEM_POOL_BUFFER_SIZE
Definition: net_mem.h:55
uint16_t length
Definition: net_mem.h:79
uint16_t firstHole
Index of the first hole.
Definition: ipv4_frag.h:128
ICMP (Internet Control Message Protocol)
error_t
Error codes.
Definition: error.h:42
size_t dataLen
Length of the payload.
Definition: ipv4_frag.h:127
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:413
void * address
Definition: net_mem.h:78
@ IPV4_FLAG_MF
Definition: ipv4.h:203
#define NetInterface
Definition: net.h:36
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
#define IPV4_DATA(packet)
Definition: ipv4.h:94
__start_packed struct @171 Ipv4HoleDesc
Hole descriptor.
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:94
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define IPV4_FRAG_TIME_TO_LIVE
Definition: ipv4_frag.h:69
size_t headerLength
Length of the header.
Definition: ipv4_frag.h:126
#define ntohs(value)
Definition: cpu_endian.h:398
Fragmented packet descriptor.
Definition: ipv4_frag.h:123
uint8_t flags
Definition: tcp.h:314
#define IPV4_MAX_FRAG_DATAGRAMS
Definition: ipv4_frag.h:55
#define TRACE_DEBUG(...)
Definition: debug.h:106
uint32_t time
IPv4 fragmentation and reassembly.
IPv4 and IPv6 common routines.
IP MIB module.
#define MIB2_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
Ipv4FragDesc * ipv4SearchFragQueue(NetInterface *interface, const Ipv4Header *packet)
Search for a matching datagram in the reassembly queue.
Definition: ipv4_frag.c:517
void ipv4ReassembleDatagram(NetInterface *interface, const Ipv4Header *packet, size_t length)
IPv4 datagram reassembly algorithm.
Definition: ipv4_frag.c:179
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:320
size_t netBufferWrite(NetBuffer *dest, size_t destOffset, const void *src, size_t length)
Write data to a multi-part buffer.
Definition: net_mem.c:619
Ipv4HoleDesc * ipv4FindHole(Ipv4FragDesc *frag, uint16_t offset)
Retrieve hole descriptor.
Definition: ipv4_frag.c:641
#define IPV4_INFINITY
Definition: ipv4_frag.h:75
IPv4 (Internet Protocol Version 4)
uint8_t payloadLen
Definition: ipv6.h:343
void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer)
Incoming IPv4 datagram processing.
Definition: ipv4.c:734
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
Ipv4ReassemblyBuffer buffer
Buffer containing the reassembled datagram.
Definition: ipv4_frag.h:129
uint32_t systime_t
Definition: compiler_port.h:46
error_t icmpSendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, uint8_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset)
Send an ICMP Error message.
Definition: icmp.c:264
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define arraysize(a)
Definition: os_port.h:70
systime_t osGetSystemTime(void)
Retrieve system time.
@ ICMP_CODE_REASSEMBLY_TIME_EXCEEDED
Definition: icmp.h:91