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