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