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.6
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, sizeof(Ipv6Header));
211  //Malformed IPv6 packet?
212  if(ipHeader == NULL)
213  return;
214 
215  //Point to the Fragment header
216  fragHeader = netBufferAt(ipPacket, fragHeaderOffset,
217  sizeof(Ipv6FragmentHeader));
218  //Malformed IPv6 packet?
219  if(fragHeader == NULL)
220  return;
221 
222  //Calculate the length of the fragment
223  length -= sizeof(Ipv6FragmentHeader);
224  //Convert the fragment offset from network byte order
225  offset = ntohs(fragHeader->fragmentOffset);
226 
227  //Every fragment except the last must contain a multiple of 8 bytes of data
228  if((offset & IPV6_FLAG_M) != 0 && (length % 8) != 0)
229  {
230  //Number of failures detected by the IP reassembly algorithm
231  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
232  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
233 
234  //Compute the offset of the Payload Length field within the packet
235  n = (uint8_t *) &ipHeader->payloadLen - (uint8_t *) ipHeader;
236 
237  //The fragment must be discarded and an ICMP Parameter Problem
238  //message should be sent to the source of the fragment, pointing
239  //to the Payload Length field of the fragment packet
241  ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
242 
243  //Drop the incoming fragment
244  return;
245  }
246 
247  //Calculate the index of the first byte
248  dataFirst = offset & IPV6_OFFSET_MASK;
249  //Calculate the index immediately following the last byte
250  dataLast = dataFirst + (uint16_t) length;
251 
252  //Check for potential integer overflow
253  if(dataLast < dataFirst)
254  {
255  //Number of failures detected by the IP reassembly algorithm
256  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
257  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
258 
259  //Drop the incoming fragment
260  return;
261  }
262 
263  //Search for a matching IP datagram being reassembled
264  frag = ipv6SearchFragQueue(interface, ipHeader, fragHeader);
265 
266  //No matching entry in the reassembly queue?
267  if(frag == NULL)
268  {
269  //Number of failures detected by the IP reassembly algorithm
270  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
271  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
272 
273  //Drop the incoming fragment
274  return;
275  }
276 
277  //The very first fragment requires special handling
278  if((offset & IPV6_OFFSET_MASK) == 0)
279  {
280  uint8_t *p;
281 
282  //Calculate the length of the unfragmentable part
283  frag->unfragPartLength = fragHeaderOffset - ipPacketOffset;
284 
285  //The size of the reconstructed datagram exceeds the maximum value?
287  {
288  //Number of failures detected by the IP reassembly algorithm
289  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
290  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
291 
292  //Retrieve the offset of the Fragment header within the packet
293  n = fragHeaderOffset - ipPacketOffset;
294  //Compute the exact offset of the Fragment Offset field
295  n += (uint8_t *) &fragHeader->fragmentOffset - (uint8_t *) fragHeader;
296 
297  //The fragment must be discarded and an ICMP Parameter Problem
298  //message should be sent to the source of the fragment, pointing
299  //to the Fragment Offset field of the fragment packet
301  ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
302 
303  //Drop the reconstructed datagram
304  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
305  //Exit immediately
306  return;
307  }
308 
309  //Make sure the unfragmentable part entirely fits in the first chunk
310  if(frag->unfragPartLength > frag->buffer.chunk[0].size)
311  {
312  //Number of failures detected by the IP reassembly algorithm
313  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
314  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
315 
316  //Drop the reconstructed datagram
317  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
318  //Exit immediately
319  return;
320  }
321 
322  //Fix the length of the first chunk
323  frag->buffer.chunk[0].length = (uint16_t) frag->unfragPartLength;
324 
325  //The unfragmentable part of the reassembled packet consists of all
326  //headers up to, but not including, the Fragment header of the first
327  //fragment packet
328  netBufferCopy((NetBuffer *) &frag->buffer, 0, ipPacket,
329  ipPacketOffset, frag->unfragPartLength);
330 
331  //Point to the Next Header field of the last header
332  p = netBufferAt((NetBuffer *) &frag->buffer,
333  nextHeaderOffset - ipPacketOffset, 0);
334 
335  //The Next Header field of the last header of the unfragmentable part is
336  //obtained from the Next Header field of the first fragment's Fragment
337  //header
338  *p = fragHeader->nextHeader;
339  }
340 
341  //It may be necessary to increase the size of the buffer
342  if(dataLast > frag->fragPartLength)
343  {
344  //The size of the reconstructed datagram exceeds the maximum value?
345  if((frag->unfragPartLength + dataLast) > IPV6_MAX_FRAG_DATAGRAM_SIZE)
346  {
347  //Number of failures detected by the IP reassembly algorithm
348  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
349  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
350 
351  //Retrieve the offset of the Fragment header within the packet
352  n = fragHeaderOffset - ipPacketOffset;
353  //Compute the exact offset of the Fragment Offset field
354  n += (uint8_t *) &fragHeader->fragmentOffset - (uint8_t *) fragHeader;
355 
356  //The fragment must be discarded and an ICMP Parameter Problem
357  //message should be sent to the source of the fragment, pointing
358  //to the Fragment Offset field of the fragment packet
360  ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
361 
362  //Drop the reconstructed datagram
363  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
364  //Exit immediately
365  return;
366  }
367 
368  //Adjust the size of the reconstructed datagram
369  error = netBufferSetLength((NetBuffer *) &frag->buffer,
370  frag->unfragPartLength + dataLast + sizeof(Ipv6HoleDesc));
371 
372  //Any error to report?
373  if(error)
374  {
375  //Number of failures detected by the IP reassembly algorithm
376  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
377  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
378 
379  //Drop the reconstructed datagram
380  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
381  //Exit immediately
382  return;
383  }
384 
385  //Actual length of the fragmentable part
386  frag->fragPartLength = dataLast;
387  }
388 
389  //Select the first hole descriptor from the list
390  hole = ipv6FindHole(frag, frag->firstHole);
391  //Keep track of the previous hole in the list
392  prevHole = NULL;
393 
394  //Iterate through the hole descriptors
395  while(hole != NULL)
396  {
397  //Save lower and upper boundaries for later use
398  uint16_t holeFirst = hole->first;
399  uint16_t holeLast = hole->last;
400 
401  //Check whether the newly arrived fragment interacts with this hole
402  //in some way
403  if(dataFirst < holeLast && dataLast > holeFirst)
404  {
405 #if (IPV6_OVERLAPPING_FRAG_SUPPORT == DISABLED)
406  //When reassembling an IPv6 datagram, if one or more its constituent
407  //fragments is determined to be an overlapping fragment, the entire
408  //datagram must be silently discarded (refer to RFC 5722, section 4)
409  if(dataFirst < holeFirst || dataLast > holeLast)
410  {
411  //Number of failures detected by the IP reassembly algorithm
412  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
413  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
414 
415  //Drop the reconstructed datagram
416  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
417  //Exit immediately
418  return;
419  }
420 #endif
421  //The current descriptor is no longer valid. We will destroy it, and in
422  //the next two steps, we will determine whether or not it is necessary
423  //to create any new hole descriptors
424  if(prevHole != NULL)
425  {
426  prevHole->next = hole->next;
427  }
428  else
429  {
430  frag->firstHole = hole->next;
431  }
432 
433  //Is there still a hole at the beginning of the segment?
434  if(dataFirst > holeFirst)
435  {
436  //Create a new entry that describes this hole
437  hole = ipv6FindHole(frag, holeFirst);
438  hole->first = holeFirst;
439  hole->last = dataFirst;
440 
441  //Insert the newly created entry into the hole descriptor list
442  if(prevHole != NULL)
443  {
444  hole->next = prevHole->next;
445  prevHole->next = hole->first;
446  }
447  else
448  {
449  hole->next = frag->firstHole;
450  frag->firstHole = hole->first;
451  }
452 
453  //Always keep track of the previous hole
454  prevHole = hole;
455  }
456 
457  //Is there still a hole at the end of the segment?
458  if(dataLast < holeLast && (offset & IPV6_FLAG_M) != 0)
459  {
460  //Create a new entry that describes this hole
461  hole = ipv6FindHole(frag, dataLast);
462  hole->first = dataLast;
463  hole->last = holeLast;
464 
465  //Insert the newly created entry into the hole descriptor list
466  if(prevHole != NULL)
467  {
468  hole->next = prevHole->next;
469  prevHole->next = hole->first;
470  }
471  else
472  {
473  hole->next = frag->firstHole;
474  frag->firstHole = hole->first;
475  }
476 
477  //Always keep track of the previous hole
478  prevHole = hole;
479  }
480  }
481  else
482  {
483  //The newly arrived fragment does not interact with the current hole
484  prevHole = hole;
485  }
486 
487  //Select the next hole descriptor from the list
488  hole = ipv6FindHole(frag, prevHole ? prevHole->next : frag->firstHole);
489  }
490 
491  //Copy data from the fragment to the reassembly buffer
492  netBufferCopy((NetBuffer *) &frag->buffer, frag->unfragPartLength + dataFirst,
493  ipPacket, fragHeaderOffset + sizeof(Ipv6FragmentHeader), length);
494 
495  //Dump hole descriptor list
496  ipv6DumpHoleList(frag);
497 
498  //If the hole descriptor list is empty, the reassembly process is now
499  //complete
500  if(ipv6FindHole(frag, frag->firstHole) == NULL)
501  {
502  //Discard the extra hole descriptor that follows the reconstructed
503  //datagram
504  error = netBufferSetLength((NetBuffer *) &frag->buffer,
505  frag->unfragPartLength + frag->fragPartLength);
506 
507  //Check status code
508  if(error)
509  {
510  //Number of failures detected by the IP reassembly algorithm
511  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
512  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
513  }
514  else
515  {
516  //Point to the IPv6 header
517  Ipv6Header *datagram = netBufferAt((NetBuffer *) &frag->buffer, 0, 0);
518 
519  //Fix the Payload Length field
520  datagram->payloadLen = htons(frag->unfragPartLength +
521  frag->fragPartLength - sizeof(Ipv6Header));
522 
523  //Number of IP datagrams successfully reassembled
524  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmOKs, 1);
525  IPV6_IF_STATS_INC_COUNTER32(reasmOKs, 1);
526 
527  //Pass the original IPv6 datagram to the higher protocol layer
528  ipv6ProcessPacket(interface, (NetBuffer *) &frag->buffer, 0,
529  ancillary);
530  }
531 
532  //Release previously allocated memory
533  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
534  }
535 }
536 
537 
538 /**
539  * @brief Fragment reassembly timeout handler
540  *
541  * This routine must be periodically called by the TCP/IP stack to
542  * handle IPv6 fragment reassembly timeout
543  *
544  * @param[in] interface Underlying network interface
545  **/
546 
547 void ipv6FragTick(NetInterface *interface)
548 {
549  error_t error;
550  uint_t i;
551  systime_t time;
552  Ipv6HoleDesc *hole;
553 
554  //Get current time
555  time = osGetSystemTime();
556 
557  //Loop through the reassembly queue
558  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
559  {
560  //Point to the current entry in the reassembly queue
561  Ipv6FragDesc *frag = &interface->ipv6Context.fragQueue[i];
562 
563  //Make sure the entry is currently in use
564  if(frag->buffer.chunkCount > 0)
565  {
566  //If the timer runs out, the partially-reassembled datagram must be
567  //discarded and ICMPv6 Time Exceeded message sent to the source host
568  if((time - frag->timestamp) >= IPV6_FRAG_TIME_TO_LIVE)
569  {
570  //Debug message
571  TRACE_INFO("IPv6 fragment reassembly timeout...\r\n");
572  //Dump IP header contents for debugging purpose
574 
575  //Number of failures detected by the IP reassembly algorithm
576  IPV6_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
577  IPV6_IF_STATS_INC_COUNTER32(reasmFails, 1);
578 
579  //Point to the first hole descriptor
580  hole = ipv6FindHole(frag, frag->firstHole);
581 
582  //Make sure the fragment zero has been received before sending an
583  //ICMPv6 message
584  if(hole != NULL && hole->first > 0)
585  {
586  //Fix the size of the reconstructed datagram
587  error = netBufferSetLength((NetBuffer *) &frag->buffer,
588  frag->unfragPartLength + hole->first);
589 
590  //Check status code
591  if(!error)
592  {
593  //Send an ICMPv6 Time Exceeded message
596  (NetBuffer *) &frag->buffer, 0);
597  }
598  }
599 
600  //Drop the partially reconstructed datagram
601  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
602  }
603  }
604  }
605 }
606 
607 
608 /**
609  * @brief Search for a matching datagram in the reassembly queue
610  * @param[in] interface Underlying network interface
611  * @param[in] packet Incoming IPv6 packet
612  * @param[in] header Pointer to the Fragment header
613  * @return Matching fragment descriptor
614  **/
615 
617  const Ipv6Header *packet, const Ipv6FragmentHeader *header)
618 {
619  error_t error;
620  uint_t i;
621  Ipv6Header *datagram;
622  Ipv6FragDesc *frag;
623  Ipv6HoleDesc *hole;
624 
625  //Search for a matching IP datagram being reassembled
626  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
627  {
628  //Point to the current entry in the reassembly queue
629  frag = &interface->ipv6Context.fragQueue[i];
630 
631  //Check whether the current entry is used?
632  if(frag->buffer.chunkCount > 0)
633  {
634  //Point to the corresponding datagram
635  datagram = netBufferAt((NetBuffer *) &frag->buffer, 0, 0);
636 
637  //Check source and destination addresses
638  if(!ipv6CompAddr(&datagram->srcAddr, &packet->srcAddr))
639  continue;
640  if(!ipv6CompAddr(&datagram->destAddr, &packet->destAddr))
641  continue;
642 
643  //Compare fragment identification fields
644  if(frag->identification != header->identification)
645  continue;
646 
647  //A matching entry has been found in the reassembly queue
648  return frag;
649  }
650  }
651 
652  //If the current packet does not match an existing entry
653  //in the reassembly queue, then create a new entry
654  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
655  {
656  //Point to the current entry in the reassembly queue
657  frag = &interface->ipv6Context.fragQueue[i];
658 
659  //Check whether the current entry is free
660  if(frag->buffer.chunkCount == 0)
661  {
662  //Number of chunks that comprise the reassembly buffer
663  frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk);
664 
665  //Allocate sufficient memory to hold the IPv6 header and the first
666  //hole descriptor
667  error = netBufferSetLength((NetBuffer *) &frag->buffer,
669 
670  //Failed to allocate memory?
671  if(error)
672  {
673  //Clean up side effects
674  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
675  //Exit immediately
676  return NULL;
677  }
678 
679  //Initial length of the reconstructed datagram
680  frag->unfragPartLength = sizeof(Ipv6Header);
681  frag->fragPartLength = 0;
682 
683  //Fix the length of the first chunk
684  frag->buffer.chunk[0].length = (uint16_t) frag->unfragPartLength;
685  //Copy IPv6 header from the incoming fragment
686  netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->unfragPartLength);
687 
688  //Save current time
689  frag->timestamp = osGetSystemTime();
690  //Record fragment identification field
691  frag->identification = header->identification;
692  //Create a new entry in the hole descriptor list
693  frag->firstHole = 0;
694 
695  //Point to first hole descriptor
696  hole = ipv6FindHole(frag, frag->firstHole);
697  //The entry describes the datagram as being completely missing
698  hole->first = 0;
699  hole->last = IPV6_INFINITY;
700  hole->next = IPV6_INFINITY;
701 
702  //Dump hole descriptor list
703  ipv6DumpHoleList(frag);
704 
705  //Return the matching fragment descriptor
706  return frag;
707  }
708  }
709 
710  //The reassembly queue is full
711  return NULL;
712 }
713 
714 
715 /**
716  * @brief Flush IPv6 reassembly queue
717  * @param[in] interface Underlying network interface
718  **/
719 
721 {
722  uint_t i;
723 
724  //Loop through the reassembly queue
725  for(i = 0; i < IPV6_MAX_FRAG_DATAGRAMS; i++)
726  {
727  //Drop any partially reconstructed datagram
728  netBufferSetLength((NetBuffer *) &interface->ipv6Context.fragQueue[i].buffer, 0);
729  }
730 }
731 
732 
733 /**
734  * @brief Retrieve hole descriptor
735  * @param[in] frag IPv6 fragment descriptor
736  * @param[in] offset Offset of the hole
737  * @return A pointer to the hole descriptor is returned if the
738  * specified offset is valid. Otherwise NULL is returned
739  **/
740 
741 Ipv6HoleDesc *ipv6FindHole(Ipv6FragDesc *frag, uint16_t offset)
742 {
743  //Return a pointer to the hole descriptor
744  return netBufferAt((NetBuffer *) &frag->buffer, frag->unfragPartLength + offset, 0);
745 }
746 
747 
748 /**
749  * @brief Dump hole descriptor list
750  * @param[in] frag IPv6 fragment descriptor
751  **/
752 
754 {
755 //Check debugging level
756 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
757  Ipv6HoleDesc *hole;
758 
759  //Debug message
760  TRACE_DEBUG("Hole descriptor list:\r\n");
761  //Select the first hole descriptor from the list
762  hole = ipv6FindHole(frag, frag->firstHole);
763 
764  //Loop through the hole descriptor list
765  while(hole != NULL)
766  {
767  //Display current hole
768  TRACE_DEBUG(" %" PRIu16 " - %" PRIu16 "\r\n", hole->first, hole->last);
769  //Select the next hole descriptor from the list
770  hole = ipv6FindHole(frag, hole->next);
771  }
772 #endif
773 }
774 
775 #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:1773
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:547
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:741
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:136
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:157
ChunkDesc chunk[N(IPV6_MAX_FRAG_DATAGRAM_SIZE)+1]
Definition: ipv6_frag.h:126
@ IPV6_OFFSET_MASK
Definition: ipv6.h:227
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:518
#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:44
void * address
Definition: net_mem.h:78
void ipv6DumpHeader(const Ipv6Header *ipHeader)
Dump IPv6 header for debugging purpose.
Definition: ipv6.c:2396
#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:720
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:616
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:124
IPv4 and IPv6 common routines.
uint8_t n
uint8_t payload[]
Definition: ipv6.h:308
void ipv6DumpHoleList(Ipv6FragDesc *frag)
Dump hole descriptor list.
Definition: ipv6_frag.c:753
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:230
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:40
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:303
#define IPV6_IF_STATS_INC_COUNTER32(name, value)
Definition: ipv6.h:159
@ 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:351
@ 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.