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