ipv6_frag.c
Go to the documentation of this file.
1 /**
2  * @file ipv6_frag.c
3  * @brief IPv6 fragmentation and reassembly
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL IPV6_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/ip.h"
37 #include "ipv6/ipv6.h"
38 #include "ipv6/ipv6_frag.h"
39 #include "ipv6/icmpv6.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (IPV6_SUPPORT == ENABLED && IPV6_FRAG_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Fragment IPv6 datagram into smaller packets
48  * @param[in] interface Underlying network interface
49  * @param[in] pseudoHeader IPv6 pseudo header
50  * @param[in] payload Multi-part buffer containing the payload
51  * @param[in] payloadOffset Offset to the first payload byte
52  * @param[in] pathMtu PMTU value
53  * @param[in] ancillary Additional options passed to the stack along with
54  * the packet
55  * @return Error code
56  **/
57 
59  const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *payload,
60  size_t payloadOffset, size_t pathMtu, NetTxAncillary *ancillary)
61 {
62  error_t error;
63  uint32_t id;
64  size_t offset;
65  size_t length;
66  size_t payloadLen;
67  size_t fragmentOffset;
68  size_t maxFragmentSize;
69  NetBuffer *fragment;
70 
71  //Number of IP datagrams that would require fragmentation in order to be transmitted
72  IPV6_SYSTEM_STATS_INC_COUNTER32(outFragReqds, 1);
73  IPV6_IF_STATS_INC_COUNTER32(outFragReqds, 1);
74 
75  //Retrieve the length of the payload
76  payloadLen = netBufferGetLength(payload) - payloadOffset;
77 
78  //Allocate a memory buffer to hold IP fragments
79  fragment = ipAllocBuffer(0, &fragmentOffset);
80  //Failed to allocate memory?
81  if(!fragment)
82  return ERROR_OUT_OF_MEMORY;
83 
84  //Identification field is used to identify fragments of an original IP datagram
85  id = interface->ipv6Context.identification++;
86 
87  //The node should never set its PMTU estimate below the IPv6 minimum link MTU
88  pathMtu = MAX(pathMtu, IPV6_DEFAULT_MTU);
89 
90  //Determine the maximum payload size for fragmented packets
91  maxFragmentSize = pathMtu - sizeof(Ipv6Header) - sizeof(Ipv6FragmentHeader);
92  //The size shall be a multiple of 8-byte blocks
93  maxFragmentSize -= (maxFragmentSize % 8);
94 
95  //Initialize error code
96  error = NO_ERROR;
97 
98  //Split the payload into multiple IP fragments
99  for(offset = 0; offset < payloadLen; offset += length)
100  {
101  //Flush the contents of the fragment
102  error = netBufferSetLength(fragment, fragmentOffset);
103  //Sanity check
104  if(error)
105  break;
106 
107  //Process the last fragment?
108  if((payloadLen - offset) <= maxFragmentSize)
109  {
110  //Size of the current fragment
111  length = payloadLen - offset;
112  //Copy fragment data
113  netBufferConcat(fragment, payload, payloadOffset + offset, length);
114 
115  //Do not set the MF flag for the last fragment
116  error = ipv6SendPacket(interface, pseudoHeader, id, offset, fragment,
117  fragmentOffset, ancillary);
118  }
119  else
120  {
121  //Size of the current fragment (must be a multiple of 8-byte blocks)
122  length = maxFragmentSize;
123  //Copy fragment data
124  netBufferConcat(fragment, payload, payloadOffset + offset, length);
125 
126  //Fragmented packets must have the M flag set
127  error = ipv6SendPacket(interface, pseudoHeader, id, IPV6_FLAG_M |
128  offset, fragment, fragmentOffset, ancillary);
129  }
130 
131  //Failed to send current IP fragment?
132  if(error)
133  break;
134 
135  //Number of IP datagram fragments that have been generated as a result
136  //of fragmentation at this entity
137  IPV6_SYSTEM_STATS_INC_COUNTER32(outFragCreates, 1);
138  IPV6_IF_STATS_INC_COUNTER32(outFragCreates, 1);
139  }
140 
141  //Check status code
142  if(error)
143  {
144  //Number of IP datagrams that have been discarded because they needed
145  //to be fragmented at this entity but could not be
146  IPV6_SYSTEM_STATS_INC_COUNTER32(outFragFails, 1);
147  IPV6_IF_STATS_INC_COUNTER32(outFragFails, 1);
148  }
149  else
150  {
151  //Number of IP datagrams that have been successfully fragmented at this
152  //entity
153  IPV6_SYSTEM_STATS_INC_COUNTER32(outFragOKs, 1);
154  IPV6_IF_STATS_INC_COUNTER32(outFragOKs, 1);
155  }
156 
157  //Free previously allocated memory
158  netBufferFree(fragment);
159  //Return status code
160  return error;
161 }
162 
163 
164 /**
165  * @brief Parse Fragment header and reassemble original datagram
166  * @param[in] interface Underlying network interface
167  * @param[in] ipPacket Multi-part buffer containing the incoming IPv6 packet
168  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
169  * @param[in] fragHeaderOffset Offset to the Fragment header
170  * @param[in] nextHeaderOffset Offset to the Next Header field of the previous header
171  * @param[in] ancillary Additional options passed to the stack along with
172  * the packet
173  **/
174 
176  size_t ipPacketOffset, size_t fragHeaderOffset, size_t nextHeaderOffset,
177  NetRxAncillary *ancillary)
178 {
179  error_t error;
180  size_t n;
181  size_t length;
182  uint16_t offset;
183  uint16_t dataFirst;
184  uint16_t dataLast;
185  Ipv6FragDesc *frag;
186  Ipv6HoleDesc *hole;
187  Ipv6HoleDesc *prevHole;
188  Ipv6Header *ipHeader;
189  Ipv6FragmentHeader *fragHeader;
190 
191  //Number of IP fragments received which needed to be reassembled
192  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmReqds, 1);
193  IPV6_IF_STATS_INC_COUNTER32(reasmReqds, 1);
194 
195  //Remaining bytes to process in the payload
196  length = netBufferGetLength(ipPacket) - fragHeaderOffset;
197 
198  //Ensure the fragment header is valid
199  if(length < sizeof(Ipv6FragmentHeader))
200  {
201  //Number of failures detected by the IP reassembly algorithm
202  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
203  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
204 
205  //Drop the incoming fragment
206  return;
207  }
208 
209  //Point to the IPv6 header
210  ipHeader = netBufferAt(ipPacket, ipPacketOffset, 0);
211  //Sanity check
212  if(ipHeader == NULL)
213  return;
214 
215  //Point to the Fragment header
216  fragHeader = netBufferAt(ipPacket, fragHeaderOffset, 0);
217  //Sanity check
218  if(fragHeader == NULL)
219  return;
220 
221  //Calculate the length of the fragment
222  length -= sizeof(Ipv6FragmentHeader);
223  //Convert the fragment offset from network byte order
224  offset = ntohs(fragHeader->fragmentOffset);
225 
226  //Every fragment except the last must contain a multiple of 8 bytes of data
227  if((offset & IPV6_FLAG_M) != 0 && (length % 8) != 0)
228  {
229  //Number of failures detected by the IP reassembly algorithm
230  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
231  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
232 
233  //Compute the offset of the Payload Length field within the packet
234  n = (uint8_t *) &ipHeader->payloadLen - (uint8_t *) ipHeader;
235 
236  //The fragment must be discarded and an ICMP Parameter Problem
237  //message should be sent to the source of the fragment, pointing
238  //to the Payload Length field of the fragment packet
240  ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
241 
242  //Drop the incoming fragment
243  return;
244  }
245 
246  //Calculate the index of the first byte
247  dataFirst = offset & IPV6_OFFSET_MASK;
248  //Calculate the index immediately following the last byte
249  dataLast = dataFirst + (uint16_t) length;
250 
251  //Check for potential integer overflow
252  if(dataLast < dataFirst)
253  {
254  //Number of failures detected by the IP reassembly algorithm
255  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
256  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
257 
258  //Drop the incoming fragment
259  return;
260  }
261 
262  //Search for a matching IP datagram being reassembled
263  frag = ipv6SearchFragQueue(interface, ipHeader, fragHeader);
264 
265  //No matching entry in the reassembly queue?
266  if(frag == NULL)
267  {
268  //Number of failures detected by the IP reassembly algorithm
269  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
270  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
271 
272  //Drop the incoming fragment
273  return;
274  }
275 
276  //The very first fragment requires special handling
277  if((offset & IPV6_OFFSET_MASK) == 0)
278  {
279  uint8_t *p;
280 
281  //Calculate the length of the unfragmentable part
282  frag->unfragPartLength = fragHeaderOffset - ipPacketOffset;
283 
284  //The size of the reconstructed datagram exceeds the maximum value?
286  {
287  //Number of failures detected by the IP reassembly algorithm
288  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
289  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
290 
291  //Retrieve the offset of the Fragment header within the packet
292  n = fragHeaderOffset - ipPacketOffset;
293  //Compute the exact offset of the Fragment Offset field
294  n += (uint8_t *) &fragHeader->fragmentOffset - (uint8_t *) fragHeader;
295 
296  //The fragment must be discarded and an ICMP Parameter Problem
297  //message should be sent to the source of the fragment, pointing
298  //to the Fragment Offset field of the fragment packet
300  ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
301 
302  //Drop the reconstructed datagram
303  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
304  //Exit immediately
305  return;
306  }
307 
308  //Make sure the unfragmentable part entirely fits in the first chunk
309  if(frag->unfragPartLength > frag->buffer.chunk[0].size)
310  {
311  //Number of failures detected by the IP reassembly algorithm
312  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
313  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
314 
315  //Drop the reconstructed datagram
316  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
317  //Exit immediately
318  return;
319  }
320 
321  //Fix the length of the first chunk
322  frag->buffer.chunk[0].length = (uint16_t) frag->unfragPartLength;
323 
324  //The unfragmentable part of the reassembled packet consists of all
325  //headers up to, but not including, the Fragment header of the first
326  //fragment packet
327  netBufferCopy((NetBuffer *) &frag->buffer, 0, ipPacket,
328  ipPacketOffset, frag->unfragPartLength);
329 
330  //Point to the Next Header field of the last header
331  p = netBufferAt((NetBuffer *) &frag->buffer,
332  nextHeaderOffset - ipPacketOffset, 0);
333 
334  //The Next Header field of the last header of the unfragmentable part is
335  //obtained from the Next Header field of the first fragment's Fragment
336  //header
337  *p = fragHeader->nextHeader;
338  }
339 
340  //It may be necessary to increase the size of the buffer
341  if(dataLast > frag->fragPartLength)
342  {
343  //The size of the reconstructed datagram exceeds the maximum value?
344  if((frag->unfragPartLength + dataLast) > IPV6_MAX_FRAG_DATAGRAM_SIZE)
345  {
346  //Number of failures detected by the IP reassembly algorithm
347  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
348  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
349 
350  //Retrieve the offset of the Fragment header within the packet
351  n = fragHeaderOffset - ipPacketOffset;
352  //Compute the exact offset of the Fragment Offset field
353  n += (uint8_t *) &fragHeader->fragmentOffset - (uint8_t *) fragHeader;
354 
355  //The fragment must be discarded and an ICMP Parameter Problem
356  //message should be sent to the source of the fragment, pointing
357  //to the Fragment Offset field of the fragment packet
359  ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
360 
361  //Drop the reconstructed datagram
362  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
363  //Exit immediately
364  return;
365  }
366 
367  //Adjust the size of the reconstructed datagram
368  error = netBufferSetLength((NetBuffer *) &frag->buffer,
369  frag->unfragPartLength + dataLast + sizeof(Ipv6HoleDesc));
370 
371  //Any error to report?
372  if(error)
373  {
374  //Number of failures detected by the IP reassembly algorithm
375  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
376  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
377 
378  //Drop the reconstructed datagram
379  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
380  //Exit immediately
381  return;
382  }
383 
384  //Actual length of the fragmentable part
385  frag->fragPartLength = dataLast;
386  }
387 
388  //Select the first hole descriptor from the list
389  hole = ipv6FindHole(frag, frag->firstHole);
390  //Keep track of the previous hole in the list
391  prevHole = NULL;
392 
393  //Iterate through the hole descriptors
394  while(hole != NULL)
395  {
396  //Save lower and upper boundaries for later use
397  uint16_t holeFirst = hole->first;
398  uint16_t holeLast = hole->last;
399 
400  //Check whether the newly arrived fragment interacts with this hole
401  //in some way
402  if(dataFirst < holeLast && dataLast > holeFirst)
403  {
404 #if (IPV6_OVERLAPPING_FRAG_SUPPORT == DISABLED)
405  //When reassembling an IPv6 datagram, if one or more its constituent
406  //fragments is determined to be an overlapping fragment, the entire
407  //datagram must be silently discarded (refer to RFC 5722, section 4)
408  if(dataFirst < holeFirst || dataLast > holeLast)
409  {
410  //Number of failures detected by the IP reassembly algorithm
411  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
412  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
413 
414  //Drop the reconstructed datagram
415  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
416  //Exit immediately
417  return;
418  }
419 #endif
420  //The current descriptor is no longer valid. We will destroy it, and in
421  //the next two steps, we will determine whether or not it is necessary
422  //to create any new hole descriptors
423  if(prevHole != NULL)
424  {
425  prevHole->next = hole->next;
426  }
427  else
428  {
429  frag->firstHole = hole->next;
430  }
431 
432  //Is there still a hole at the beginning of the segment?
433  if(dataFirst > holeFirst)
434  {
435  //Create a new entry that describes this hole
436  hole = ipv6FindHole(frag, holeFirst);
437  hole->first = holeFirst;
438  hole->last = dataFirst;
439 
440  //Insert the newly created entry into the hole descriptor list
441  if(prevHole != NULL)
442  {
443  hole->next = prevHole->next;
444  prevHole->next = hole->first;
445  }
446  else
447  {
448  hole->next = frag->firstHole;
449  frag->firstHole = hole->first;
450  }
451 
452  //Always keep track of the previous hole
453  prevHole = hole;
454  }
455 
456  //Is there still a hole at the end of the segment?
457  if(dataLast < holeLast && (offset & IPV6_FLAG_M) != 0)
458  {
459  //Create a new entry that describes this hole
460  hole = ipv6FindHole(frag, dataLast);
461  hole->first = dataLast;
462  hole->last = holeLast;
463 
464  //Insert the newly created entry into the hole descriptor list
465  if(prevHole != NULL)
466  {
467  hole->next = prevHole->next;
468  prevHole->next = hole->first;
469  }
470  else
471  {
472  hole->next = frag->firstHole;
473  frag->firstHole = hole->first;
474  }
475 
476  //Always keep track of the previous hole
477  prevHole = hole;
478  }
479  }
480  else
481  {
482  //The newly arrived fragment does not interact with the current hole
483  prevHole = hole;
484  }
485 
486  //Select the next hole descriptor from the list
487  hole = ipv6FindHole(frag, prevHole ? prevHole->next : frag->firstHole);
488  }
489 
490  //Copy data from the fragment to the reassembly buffer
491  netBufferCopy((NetBuffer *) &frag->buffer, frag->unfragPartLength + dataFirst,
492  ipPacket, fragHeaderOffset + sizeof(Ipv6FragmentHeader), length);
493 
494  //Dump hole descriptor list
495  ipv6DumpHoleList(frag);
496 
497  //If the hole descriptor list is empty, the reassembly process is now
498  //complete
499  if(ipv6FindHole(frag, frag->firstHole) == NULL)
500  {
501  //Discard the extra hole descriptor that follows the reconstructed
502  //datagram
503  error = netBufferSetLength((NetBuffer *) &frag->buffer,
504  frag->unfragPartLength + frag->fragPartLength);
505 
506  //Check status code
507  if(error)
508  {
509  //Number of failures detected by the IP reassembly algorithm
510  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
511  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
512  }
513  else
514  {
515  //Point to the IPv6 header
516  Ipv6Header *datagram = netBufferAt((NetBuffer *) &frag->buffer, 0, 0);
517 
518  //Fix the Payload Length field
519  datagram->payloadLen = htons(frag->unfragPartLength +
520  frag->fragPartLength - sizeof(Ipv6Header));
521 
522  //Number of IP datagrams successfully reassembled
523  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmOKs, 1);
524  IPV6_IF_STATS_INC_COUNTER32(reasmOKs, 1);
525 
526  //Pass the original IPv6 datagram to the higher protocol layer
527  ipv6ProcessPacket(interface, (NetBuffer *) &frag->buffer, 0,
528  ancillary);
529  }
530 
531  //Release previously allocated memory
532  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
533  }
534 }
535 
536 
537 /**
538  * @brief Fragment reassembly timeout handler
539  *
540  * This routine must be periodically called by the TCP/IP stack to
541  * handle IPv6 fragment reassembly timeout
542  *
543  * @param[in] interface Underlying network interface
544  **/
545 
546 void ipv6FragTick(NetInterface *interface)
547 {
548  error_t error;
549  uint_t i;
550  systime_t time;
551  Ipv6HoleDesc *hole;
552 
553  //Get current time
554  time = osGetSystemTime();
555 
556  //Loop through the reassembly queue
557  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
558  {
559  //Point to the current entry in the reassembly queue
560  Ipv6FragDesc *frag = &interface->ipv6Context.fragQueue[i];
561 
562  //Make sure the entry is currently in use
563  if(frag->buffer.chunkCount > 0)
564  {
565  //If the timer runs out, the partially-reassembled datagram must be
566  //discarded and ICMPv6 Time Exceeded message sent to the source host
567  if((time - frag->timestamp) >= IPV6_FRAG_TIME_TO_LIVE)
568  {
569  //Debug message
570  TRACE_INFO("IPv6 fragment reassembly timeout...\r\n");
571  //Dump IP header contents for debugging purpose
573 
574  //Number of failures detected by the IP reassembly algorithm
575  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
576  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
577 
578  //Point to the first hole descriptor
579  hole = ipv6FindHole(frag, frag->firstHole);
580 
581  //Make sure the fragment zero has been received before sending an
582  //ICMPv6 message
583  if(hole != NULL && hole->first > 0)
584  {
585  //Fix the size of the reconstructed datagram
586  error = netBufferSetLength((NetBuffer *) &frag->buffer,
587  frag->unfragPartLength + hole->first);
588 
589  //Check status code
590  if(!error)
591  {
592  //Send an ICMPv6 Time Exceeded message
595  (NetBuffer *) &frag->buffer, 0);
596  }
597  }
598 
599  //Drop the partially reconstructed datagram
600  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
601  }
602  }
603  }
604 }
605 
606 
607 /**
608  * @brief Search for a matching datagram in the reassembly queue
609  * @param[in] interface Underlying network interface
610  * @param[in] packet Incoming IPv6 packet
611  * @param[in] header Pointer to the Fragment header
612  * @return Matching fragment descriptor
613  **/
614 
616  const Ipv6Header *packet, const Ipv6FragmentHeader *header)
617 {
618  error_t error;
619  uint_t i;
620  Ipv6Header *datagram;
621  Ipv6FragDesc *frag;
622  Ipv6HoleDesc *hole;
623 
624  //Search for a matching IP datagram being reassembled
625  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
626  {
627  //Point to the current entry in the reassembly queue
628  frag = &interface->ipv6Context.fragQueue[i];
629 
630  //Check whether the current entry is used?
631  if(frag->buffer.chunkCount > 0)
632  {
633  //Point to the corresponding datagram
634  datagram = netBufferAt((NetBuffer *) &frag->buffer, 0, 0);
635 
636  //Check source and destination addresses
637  if(!ipv6CompAddr(&datagram->srcAddr, &packet->srcAddr))
638  continue;
639  if(!ipv6CompAddr(&datagram->destAddr, &packet->destAddr))
640  continue;
641 
642  //Compare fragment identification fields
643  if(frag->identification != header->identification)
644  continue;
645 
646  //A matching entry has been found in the reassembly queue
647  return frag;
648  }
649  }
650 
651  //If the current packet does not match an existing entry
652  //in the reassembly queue, then create a new entry
653  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
654  {
655  //Point to the current entry in the reassembly queue
656  frag = &interface->ipv6Context.fragQueue[i];
657 
658  //Check whether the current entry is free
659  if(frag->buffer.chunkCount == 0)
660  {
661  //Number of chunks that comprise the reassembly buffer
662  frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk);
663 
664  //Allocate sufficient memory to hold the IPv6 header and the first
665  //hole descriptor
666  error = netBufferSetLength((NetBuffer *) &frag->buffer,
668 
669  //Failed to allocate memory?
670  if(error)
671  {
672  //Clean up side effects
673  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
674  //Exit immediately
675  return NULL;
676  }
677 
678  //Initial length of the reconstructed datagram
679  frag->unfragPartLength = sizeof(Ipv6Header);
680  frag->fragPartLength = 0;
681 
682  //Fix the length of the first chunk
683  frag->buffer.chunk[0].length = (uint16_t) frag->unfragPartLength;
684  //Copy IPv6 header from the incoming fragment
685  netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->unfragPartLength);
686 
687  //Save current time
688  frag->timestamp = osGetSystemTime();
689  //Record fragment identification field
690  frag->identification = header->identification;
691  //Create a new entry in the hole descriptor list
692  frag->firstHole = 0;
693 
694  //Point to first hole descriptor
695  hole = ipv6FindHole(frag, frag->firstHole);
696  //The entry describes the datagram as being completely missing
697  hole->first = 0;
698  hole->last = IPV6_INFINITY;
699  hole->next = IPV6_INFINITY;
700 
701  //Dump hole descriptor list
702  ipv6DumpHoleList(frag);
703 
704  //Return the matching fragment descriptor
705  return frag;
706  }
707  }
708 
709  //The reassembly queue is full
710  return NULL;
711 }
712 
713 
714 /**
715  * @brief Flush IPv6 reassembly queue
716  * @param[in] interface Underlying network interface
717  **/
718 
720 {
721  uint_t i;
722 
723  //Loop through the reassembly queue
724  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
725  {
726  //Drop any partially reconstructed datagram
727  netBufferSetLength((NetBuffer *) &interface->ipv6Context.fragQueue[i].buffer, 0);
728  }
729 }
730 
731 
732 /**
733  * @brief Retrieve hole descriptor
734  * @param[in] frag IPv6 fragment descriptor
735  * @param[in] offset Offset of the hole
736  * @return A pointer to the hole descriptor is returned if the
737  * specified offset is valid. Otherwise NULL is returned
738  **/
739 
740 Ipv6HoleDesc *ipv6FindHole(Ipv6FragDesc *frag, uint16_t offset)
741 {
742  //Return a pointer to the hole descriptor
743  return netBufferAt((NetBuffer *) &frag->buffer, frag->unfragPartLength + offset, 0);
744 }
745 
746 
747 /**
748  * @brief Dump hole descriptor list
749  * @param[in] frag IPv6 fragment descriptor
750  **/
751 
753 {
754 //Check debugging level
755 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
756  Ipv6HoleDesc *hole;
757 
758  //Debug message
759  TRACE_DEBUG("Hole descriptor list:\r\n");
760  //Select the first hole descriptor from the list
761  hole = ipv6FindHole(frag, frag->firstHole);
762 
763  //Loop through the hole descriptor list
764  while(hole != NULL)
765  {
766  //Display current hole
767  TRACE_DEBUG(" %" PRIu16 " - %" PRIu16 "\r\n", hole->first, hole->last);
768  //Select the next hole descriptor from the list
769  hole = ipv6FindHole(frag, hole->next);
770  }
771 #endif
772 }
773 
774 #endif
#define htons(value)
Definition: cpu_endian.h:413
IPv6 (Internet Protocol Version 6)
#define IPV6_INFINITY
Definition: ipv6_frag.h:82
error_t ipv6SendPacket(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, uint32_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv6 packet.
Definition: ipv6.c:1792
systime_t timestamp
Time at which the first fragment was received.
Definition: ipv6_frag.h:136
void ipv6FragTick(NetInterface *interface)
Fragment reassembly timeout handler.
Definition: ipv6_frag.c:546
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:716
Ipv6HoleDesc * ipv6FindHole(Ipv6FragDesc *frag, uint16_t offset)
Retrieve hole descriptor.
Definition: ipv6_frag.c:740
size_t unfragPartLength
Length of the unfragmentable part.
Definition: ipv6_frag.h:138
size_t fragPartLength
Length of the fragmentable part.
Definition: ipv6_frag.h:139
error_t ipv6FragmentDatagram(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *payload, size_t payloadOffset, size_t pathMtu, NetTxAncillary *ancillary)
Fragment IPv6 datagram into smaller packets.
Definition: ipv6_frag.c:58
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define Ipv6Header
Definition: ipv6.h:36
@ ICMPV6_CODE_INVALID_HEADER_FIELD
Definition: icmpv6.h:119
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:134
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset, NetRxAncillary *ancillary)
Incoming IPv6 packet processing.
Definition: ipv6.c:983
#define IPV6_FRAG_TIME_TO_LIVE
Definition: ipv6_frag.h:76
#define IPV6_SYSTEM_STATS_INC_COUNTER32(name, value)
Definition: ipv6.h:155
ChunkDesc chunk[N(IPV6_MAX_FRAG_DATAGRAM_SIZE)+1]
Definition: ipv6_frag.h:126
@ IPV6_OFFSET_MASK
Definition: ipv6.h:225
uint8_t ipPacket[]
Definition: ndp.h:431
error_t netBufferConcat(NetBuffer *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Concatenate two multi-part buffers.
Definition: net_mem.c:460
error_t icmpv6SendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, uint32_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset)
Send an ICMPv6 Error message.
Definition: icmpv6.c:521
#define NET_MEM_POOL_BUFFER_SIZE
Definition: net_mem.h:55
uint16_t length
Definition: net_mem.h:79
ICMPv6 (Internet Control Message Protocol Version 6)
uint16_t firstHole
Index of the first hole.
Definition: ipv6_frag.h:140
error_t
Error codes.
Definition: error.h:43
@ ICMPV6_CODE_REASSEMBLY_TIME_EXCEEDED
Definition: icmpv6.h:110
#define Ipv6PseudoHeader
Definition: ipv6.h:42
void * address
Definition: net_mem.h:78
void ipv6DumpHeader(const Ipv6Header *ipHeader)
Dump IPv6 header for debugging purpose.
Definition: ipv6.c:2415
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
void ipv6FlushFragQueue(NetInterface *interface)
Flush IPv6 reassembly queue.
Definition: ipv6_frag.c:719
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
#define IPV6_MAX_FRAG_DATAGRAM_SIZE
Definition: ipv6_frag.h:69
#define NetTxAncillary
Definition: net_misc.h:36
Ipv6HoleDesc
Definition: ipv6_frag.h:107
Fragmented packet descriptor.
Definition: ipv6_frag.h:135
error_t netBufferCopy(NetBuffer *dest, size_t destOffset, const NetBuffer *src, size_t srcOffset, size_t length)
Copy data between multi-part buffers.
Definition: net_mem.c:522
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
Ipv6FragDesc * ipv6SearchFragQueue(NetInterface *interface, const Ipv6Header *packet, const Ipv6FragmentHeader *header)
Search for a matching datagram in the reassembly queue.
Definition: ipv6_frag.c:615
uint32_t systime_t
System time.
#define ntohs(value)
Definition: cpu_endian.h:421
IPv6 fragmentation and reassembly.
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define MAX(a, b)
Definition: os_port.h:67
uint32_t time
#define IPV6_DEFAULT_MTU
Definition: ipv6.h:122
IPv4 and IPv6 common routines.
uint8_t n
uint8_t payload[]
Definition: ipv6.h:306
void ipv6DumpHoleList(Ipv6FragDesc *frag)
Dump hole descriptor list.
Definition: ipv6_frag.c:752
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
@ IPV6_FLAG_M
Definition: ipv6.h:228
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:637
#define Ipv6FragmentHeader
Definition: ipv6.h:39
Ipv6ReassemblyBuffer buffer
Buffer containing the reassembled datagram.
Definition: ipv6_frag.h:141
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
void ipv6ParseFragmentHeader(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t fragHeaderOffset, size_t nextHeaderOffset, NetRxAncillary *ancillary)
Parse Fragment header and reassemble original datagram.
Definition: ipv6_frag.c:175
uint16_t payloadLen
Definition: ipv6.h:301
#define IPV6_IF_STATS_INC_COUNTER32(name, value)
Definition: ipv6.h:157
@ ICMPV6_TYPE_PARAM_PROBLEM
Definition: icmpv6.h:74
unsigned int uint_t
Definition: compiler_port.h:57
#define IPV6_MAX_FRAG_DATAGRAMS
Definition: ipv6_frag.h:62
TCP/IP stack core.
uint16_t size
Definition: net_mem.h:80
uint16_t fragmentOffset
Definition: ipv4.h:349
@ NO_ERROR
Success.
Definition: error.h:44
@ ICMPV6_TYPE_TIME_EXCEEDED
Definition: icmpv6.h:73
Debugging facilities.
uint32_t identification
Fragment identification field.
Definition: ipv6_frag.h:137
#define arraysize(a)
Definition: os_port.h:71
systime_t osGetSystemTime(void)
Retrieve system time.