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-2023 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.2.4
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  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  //The current descriptor is no longer valid. We will destroy it, and in
345  //the next two steps, we will determine whether or not it is necessary
346  //to create any new hole descriptors
347  if(prevHole != NULL)
348  {
349  prevHole->next = hole->next;
350  }
351  else
352  {
353  frag->firstHole = hole->next;
354  }
355 
356  //Is there still a hole at the beginning of the segment?
357  if(dataFirst > holeFirst)
358  {
359  //Create a new entry that describes this hole
360  hole = ipv4FindHole(frag, holeFirst);
361  hole->first = holeFirst;
362  hole->last = dataFirst;
363 
364  //Insert the newly created entry into the hole descriptor list
365  if(prevHole != NULL)
366  {
367  hole->next = prevHole->next;
368  prevHole->next = hole->first;
369  }
370  else
371  {
372  hole->next = frag->firstHole;
373  frag->firstHole = hole->first;
374  }
375 
376  //Always keep track of the previous hole
377  prevHole = hole;
378  }
379 
380  //Is there still a hole at the end of the segment?
381  if(dataLast < holeLast && (offset & IPV4_FLAG_MF) != 0)
382  {
383  //Create a new entry that describes this hole
384  hole = ipv4FindHole(frag, dataLast);
385  hole->first = dataLast;
386  hole->last = holeLast;
387 
388  //Insert the newly created entry into the hole descriptor list
389  if(prevHole != NULL)
390  {
391  hole->next = prevHole->next;
392  prevHole->next = hole->first;
393  }
394  else
395  {
396  hole->next = frag->firstHole;
397  frag->firstHole = hole->first;
398  }
399 
400  //Always keep track of the previous hole
401  prevHole = hole;
402  }
403  }
404  else
405  {
406  //The newly arrived fragment does not interact with the current hole
407  prevHole = hole;
408  }
409 
410  //Select the next hole descriptor from the list
411  hole = ipv4FindHole(frag, prevHole ? prevHole->next : frag->firstHole);
412  }
413 
414  //Copy data from the fragment to the reassembly buffer
415  netBufferWrite((NetBuffer *) &frag->buffer,
416  frag->headerLength + dataFirst, IPV4_DATA(packet), length);
417 
418  //Dump hole descriptor list
419  ipv4DumpHoleList(frag);
420 
421  //If the hole descriptor list is empty, the reassembly process is now
422  //complete
423  if(ipv4FindHole(frag, frag->firstHole) == NULL)
424  {
425  //Discard the extra hole descriptor that follows the reconstructed
426  //datagram
427  error = netBufferSetLength((NetBuffer *) &frag->buffer,
428  frag->headerLength + frag->dataLen);
429 
430  //Check status code
431  if(error)
432  {
433  //Number of failures detected by the IP reassembly algorithm
434  MIB2_IP_INC_COUNTER32(ipReasmFails, 1);
435  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
436  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
437  }
438  else
439  {
440  //Point to the IP header
441  Ipv4Header *datagram = netBufferAt((NetBuffer *) &frag->buffer, 0);
442 
443  //Fix IP header
444  datagram->totalLength = htons(frag->headerLength + frag->dataLen);
445  datagram->fragmentOffset = 0;
446  datagram->headerChecksum = 0;
447 
448  //Number of IP datagrams successfully reassembled
449  MIB2_IP_INC_COUNTER32(ipReasmOKs, 1);
450  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmOKs, 1);
451  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmOKs, 1);
452 
453  //Pass the original IPv4 datagram to the higher protocol layer
454  ipv4ProcessDatagram(interface, (NetBuffer *) &frag->buffer, 0,
455  ancillary);
456  }
457 
458  //Release previously allocated memory
459  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
460  }
461 }
462 
463 
464 /**
465  * @brief Fragment reassembly timeout handler
466  *
467  * This routine must be periodically called by the TCP/IP stack to
468  * handle IPv4 fragment reassembly timeout
469  *
470  * @param[in] interface Underlying network interface
471  **/
472 
473 void ipv4FragTick(NetInterface *interface)
474 {
475  error_t error;
476  uint_t i;
477  systime_t time;
478  Ipv4HoleDesc *hole;
479 
480  //Get current time
481  time = osGetSystemTime();
482 
483  //Loop through the reassembly queue
484  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
485  {
486  //Point to the current entry in the reassembly queue
487  Ipv4FragDesc *frag = &interface->ipv4Context.fragQueue[i];
488 
489  //Make sure the entry is currently in use
490  if(frag->buffer.chunkCount > 0)
491  {
492  //If the timer runs out, the partially-reassembled datagram must be
493  //discarded and ICMP Time Exceeded message sent to the source host
494  if((time - frag->timestamp) >= IPV4_FRAG_TIME_TO_LIVE)
495  {
496  //Debug message
497  TRACE_INFO("IPv4 fragment reassembly timeout...\r\n");
498  //Dump IP header contents for debugging purpose
500 
501  //Number of failures detected by the IP reassembly algorithm
502  MIB2_IP_INC_COUNTER32(ipReasmFails, 1);
503  IP_MIB_INC_COUNTER32(ipv4SystemStats.ipSystemStatsReasmFails, 1);
504  IP_MIB_INC_COUNTER32(ipv4IfStatsTable[interface->index].ipIfStatsReasmFails, 1);
505 
506  //Point to the first hole descriptor
507  hole = ipv4FindHole(frag, frag->firstHole);
508 
509  //Make sure the fragment zero has been received before sending an
510  //ICMP message
511  if(hole != NULL && hole->first > 0)
512  {
513  //Fix the size of the reconstructed datagram
514  error = netBufferSetLength((NetBuffer *) &frag->buffer,
515  frag->headerLength + hole->first);
516 
517  //Check status code
518  if(!error)
519  {
520  //Send an ICMP Time Exceeded message
523  (NetBuffer *) &frag->buffer, 0);
524  }
525  }
526 
527  //Drop the partially reconstructed datagram
528  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
529  }
530  }
531  }
532 }
533 
534 
535 /**
536  * @brief Search for a matching datagram in the reassembly queue
537  * @param[in] interface Underlying network interface
538  * @param[in] packet Incoming IPv4 packet
539  * @return Matching fragment descriptor
540  **/
541 
543  const Ipv4Header *packet)
544 {
545  error_t error;
546  uint_t i;
547  Ipv4Header *datagram;
548  Ipv4FragDesc *frag;
549  Ipv4HoleDesc *hole;
550 
551  //Search for a matching IP datagram being reassembled
552  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
553  {
554  //Point to the current entry in the reassembly queue
555  frag = &interface->ipv4Context.fragQueue[i];
556 
557  //Check whether the current entry is used?
558  if(frag->buffer.chunkCount > 0)
559  {
560  //Point to the corresponding datagram
561  datagram = netBufferAt((NetBuffer *) &frag->buffer, 0);
562 
563  //Check source and destination addresses
564  if(datagram->srcAddr != packet->srcAddr)
565  continue;
566  if(datagram->destAddr != packet->destAddr)
567  continue;
568 
569  //Compare identification and protocol fields
570  if(datagram->identification != packet->identification)
571  continue;
572  if(datagram->protocol != packet->protocol)
573  continue;
574 
575  //A matching entry has been found in the reassembly queue
576  return frag;
577  }
578  }
579 
580  //If the current packet does not match an existing entry in the reassembly
581  //queue, then create a new entry
582  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
583  {
584  //Point to the current entry in the reassembly queue
585  frag = &interface->ipv4Context.fragQueue[i];
586 
587  //The current entry is free?
588  if(!frag->buffer.chunkCount)
589  {
590  //Number of chunks that comprise the reassembly buffer
591  frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk);
592 
593  //Allocate sufficient memory to hold the IPv4 header and
594  //the first hole descriptor
595  error = netBufferSetLength((NetBuffer *) &frag->buffer,
597 
598  //Failed to allocate memory?
599  if(error)
600  {
601  //Clean up side effects
602  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
603  //Exit immediately
604  return NULL;
605  }
606 
607  //Initial length of the reconstructed datagram
608  frag->headerLength = packet->headerLength * 4;
609  frag->dataLen = 0;
610 
611  //Fix the length of the first chunk
612  frag->buffer.chunk[0].length = (uint16_t) frag->headerLength;
613  //Copy IPv4 header from the incoming fragment
614  netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->headerLength);
615 
616  //Save current time
617  frag->timestamp = osGetSystemTime();
618  //Create a new entry in the hole descriptor list
619  frag->firstHole = 0;
620 
621  //Point to first hole descriptor
622  hole = ipv4FindHole(frag, frag->firstHole);
623  //The entry describes the datagram as being completely missing
624  hole->first = 0;
625  hole->last = IPV4_INFINITY;
626  hole->next = IPV4_INFINITY;
627 
628  //Dump hole descriptor list
629  ipv4DumpHoleList(frag);
630 
631  //Return the matching fragment descriptor
632  return frag;
633  }
634  }
635 
636  //The reassembly queue is full
637  return NULL;
638 }
639 
640 
641 /**
642  * @brief Flush IPv4 reassembly queue
643  * @param[in] interface Underlying network interface
644  **/
645 
647 {
648  uint_t i;
649 
650  //Loop through the reassembly queue
651  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
652  {
653  //Drop any partially reconstructed datagram
654  netBufferSetLength((NetBuffer *) &interface->ipv4Context.fragQueue[i].buffer, 0);
655  }
656 }
657 
658 
659 /**
660  * @brief Retrieve hole descriptor
661  * @param[in] frag IPv4 fragment descriptor
662  * @param[in] offset Offset of the hole
663  * @return A pointer to the hole descriptor is returned if the specified
664  * offset is valid. Otherwise NULL is returned
665  **/
666 
667 Ipv4HoleDesc *ipv4FindHole(Ipv4FragDesc *frag, uint16_t offset)
668 {
669  //Return a pointer to the hole descriptor
670  return netBufferAt((NetBuffer *) &frag->buffer, frag->headerLength + offset);
671 }
672 
673 
674 /**
675  * @brief Dump hole descriptor list
676  * @param[in] frag IPv4 fragment descriptor
677  **/
678 
680 {
681 //Check debugging level
682 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
683  Ipv4HoleDesc *hole;
684 
685  //Debug message
686  TRACE_DEBUG("Hole descriptor list:\r\n");
687  //Select the first hole descriptor from the list
688  hole = ipv4FindHole(frag, frag->firstHole);
689 
690  //Loop through the hole descriptor list
691  while(hole != NULL)
692  {
693  //Display current hole
694  TRACE_DEBUG(" %" PRIu16 " - %" PRIu16 "\r\n", hole->first, hole->last);
695  //Select the next hole descriptor from the list
696  hole = ipv4FindHole(frag, hole->next);
697  }
698 #endif
699 }
700 
701 #endif
systime_t timestamp
Time at which the first fragment was received.
Definition: ipv4_frag.h:125
uint8_t length
Definition: coap_common.h:193
#define htons(value)
Definition: cpu_endian.h:413
MIB-II module.
systime_t ipv4FragTickCounter
Definition: ipv4_frag.c:57
ChunkDesc chunk[N(IPV4_MAX_FRAG_DATAGRAM_SIZE)+1]
Definition: ipv4_frag.h:115
uint8_t payload[]
Definition: sftp_common.h:216
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:724
#define Ipv4Header
Definition: ipv4.h:36
void ipv4FragTick(NetInterface *interface)
Fragment reassembly timeout handler.
Definition: ipv4_frag.c:473
@ IPV4_OFFSET_MASK
Definition: ipv4.h:211
void ipv4FlushFragQueue(NetInterface *interface)
Flush IPv4 reassembly queue.
Definition: ipv4_frag.c:646
#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:89
@ 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 ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Incoming IPv4 datagram processing.
Definition: ipv4.c:794
void ipv4DumpHoleList(Ipv4FragDesc *frag)
Dump hole descriptor list.
Definition: ipv4_frag.c:679
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:1616
#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:43
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:210
void ipv4ReassembleDatagram(NetInterface *interface, const Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
IPv4 datagram reassembly algorithm.
Definition: ipv4_frag.c:184
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:36
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
#define MIB2_IP_INC_COUNTER32(name, value)
Definition: mib2_module.h:164
#define IPV4_DATA(packet)
Definition: ipv4.h:101
#define NetTxAncillary
Definition: net_misc.h:36
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:95
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
error_t ipv4SendPacket(NetInterface *interface, Ipv4PseudoHeader *pseudoHeader, uint16_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv4 packet.
Definition: ipv4.c:1051
#define IPV4_FRAG_TIME_TO_LIVE
Definition: ipv4_frag.h:69
size_t headerLength
Length of the header.
Definition: ipv4_frag.h:126
uint32_t systime_t
System time.
#define ntohs(value)
Definition: cpu_endian.h:421
Fragmented packet descriptor.
Definition: ipv4_frag.h:124
#define IPV4_MAX_FRAG_DATAGRAMS
Definition: ipv4_frag.h:55
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint32_t time
__start_packed struct @0 Ipv4HoleDesc
Hole descriptor.
IPv4 fragmentation and reassembly.
IPv4 and IPv6 common routines.
IP MIB module.
Ipv4FragDesc * ipv4SearchFragQueue(NetInterface *interface, const Ipv4Header *packet)
Search for a matching datagram in the reassembly queue.
Definition: ipv4_frag.c:542
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
error_t ipv4FragmentDatagram(NetInterface *interface, 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
Ipv4HoleDesc * ipv4FindHole(Ipv4FragDesc *frag, uint16_t offset)
Retrieve hole descriptor.
Definition: ipv4_frag.c:667
#define IPV4_INFINITY
Definition: ipv4_frag.h:75
IPv4 (Internet Protocol Version 4)
uint8_t payloadLen
Definition: ipv6.h:339
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
uint16_t size
Definition: net_mem.h:80
Ipv4ReassemblyBuffer buffer
Buffer containing the reassembled datagram.
Definition: ipv4_frag.h:129
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:337
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define arraysize(a)
Definition: os_port.h:73
systime_t osGetSystemTime(void)
Retrieve system time.
@ ICMP_CODE_REASSEMBLY_TIME_EXCEEDED
Definition: icmp.h:91