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