ipv4_frag.c
Go to the documentation of this file.
1 /**
2  * @file ipv4_frag.c
3  * @brief IPv4 fragmentation and reassembly
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Internet Protocol (IP) implements datagram fragmentation, so that
30  * packets may be formed that can pass through a link with a smaller maximum
31  * transmission unit (MTU) than the original datagram size. Refer to the
32  * following RFCs for complete details:
33  * - RFC 791: Internet Protocol specification
34  * - RFC 815: IP datagram reassembly algorithms
35  *
36  * @author Oryx Embedded SARL (www.oryx-embedded.com)
37  * @version 2.6.0
38  **/
39 
40 //Switch to the appropriate trace level
41 #define TRACE_LEVEL IPV4_TRACE_LEVEL
42 
43 //Dependencies
44 #include "core/net.h"
45 #include "core/ip.h"
46 #include "ipv4/ipv4.h"
47 #include "ipv4/ipv4_frag.h"
48 #include "ipv4/icmp.h"
49 #include "debug.h"
50 
51 //Check TCP/IP stack configuration
52 #if (IPV4_SUPPORT == ENABLED && IPV4_FRAG_SUPPORT == ENABLED)
53 
54 
55 /**
56  * @brief Fragment an IPv4 datagram into smaller packets
57  * @param[in] interface Underlying network interface
58  * @param[in] pseudoHeader IPv4 pseudo header
59  * @param[in] id Fragment identification
60  * @param[in] payload Multi-part buffer containing the payload
61  * @param[in] payloadOffset Offset to the first payload byte
62  * @param[in] ancillary Additional options passed to the stack along with
63  * the packet
64  * @return Error code
65  **/
66 
68  const Ipv4PseudoHeader *pseudoHeader, uint16_t id, const NetBuffer *payload,
69  size_t payloadOffset, NetTxAncillary *ancillary)
70 {
71  error_t error;
72  size_t offset;
73  size_t length;
74  size_t payloadLen;
75  size_t fragmentOffset;
76  size_t maxFragmentSize;
77  NetBuffer *fragment;
78 
79  //Number of IP datagrams that would require fragmentation in order to be
80  //transmitted
81  IPV4_SYSTEM_STATS_INC_COUNTER32(outFragReqds, 1);
82  IPV4_IF_STATS_INC_COUNTER32(outFragReqds, 1);
83 
84  //Retrieve the length of the payload
85  payloadLen = netBufferGetLength(payload) - payloadOffset;
86 
87  //Allocate a memory buffer to hold IP fragments
88  fragment = ipAllocBuffer(0, &fragmentOffset);
89  //Failed to allocate memory?
90  if(!fragment)
91  return ERROR_OUT_OF_MEMORY;
92 
93  //Determine the maximum payload size for fragmented packets
94  maxFragmentSize = interface->ipv4Context.linkMtu - sizeof(Ipv4Header);
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 = ipv4SendPacket(interface, pseudoHeader, id, offset / 8,
120  fragment, fragmentOffset, ancillary);
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 MF flag set
130  error = ipv4SendPacket(interface, pseudoHeader, id, IPV4_FLAG_MF |
131  (offset / 8), fragment, fragmentOffset, ancillary);
132  }
133 
134  //Failed to send current IP packet?
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  IPV4_SYSTEM_STATS_INC_COUNTER32(outFragCreates, 1);
141  IPV4_IF_STATS_INC_COUNTER32(outFragCreates, 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  IPV4_SYSTEM_STATS_INC_COUNTER32(outFragFails, 1);
150  IPV4_IF_STATS_INC_COUNTER32(outFragFails, 1);
151  }
152  else
153  {
154  //Number of IP datagrams that have been successfully fragmented at this
155  //entity
156  IPV4_SYSTEM_STATS_INC_COUNTER32(outFragOKs, 1);
157  IPV4_IF_STATS_INC_COUNTER32(outFragOKs, 1);
158  }
159 
160  //Free previously allocated memory
161  netBufferFree(fragment);
162  //Return status code
163  return error;
164 }
165 
166 
167 /**
168  * @brief IPv4 datagram reassembly algorithm
169  * @param[in] interface Underlying network interface
170  * @param[in] packet Pointer to the IPv4 fragmented packet
171  * @param[in] length Packet length including header and payload
172  * @param[in] ancillary Additional options passed to the stack along with
173  * the packet
174  **/
175 
176 void ipv4ReassembleDatagram(NetInterface *interface, const Ipv4Header *packet,
177  size_t length, NetRxAncillary *ancillary)
178 {
179  error_t error;
180  uint16_t offset;
181  uint16_t dataFirst;
182  uint16_t dataLast;
183  Ipv4FragDesc *frag;
184  Ipv4HoleDesc *hole;
185  Ipv4HoleDesc *prevHole;
186 
187  //Number of IP fragments received which needed to be reassembled
188  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmReqds, 1);
189  IPV4_IF_STATS_INC_COUNTER32(reasmReqds, 1);
190 
191  //Get the length of the payload
192  length -= packet->headerLength * 4;
193  //Convert the fragment offset from network byte order
194  offset = ntohs(packet->fragmentOffset);
195 
196  //Every fragment except the last must contain a multiple of 8 bytes of data
197  if((offset & IPV4_FLAG_MF) != 0 && (length % 8) != 0)
198  {
199  //Number of failures detected by the IP reassembly algorithm
200  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
201  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
202 
203  //Drop the incoming fragment
204  return;
205  }
206 
207  //Calculate the index of the first byte
208  dataFirst = (offset & IPV4_OFFSET_MASK) * 8;
209  //Calculate the index immediately following the last byte
210  dataLast = dataFirst + (uint16_t) length;
211 
212  //Check for potential integer overflow
213  if(dataLast < dataFirst)
214  {
215  //Number of failures detected by the IP reassembly algorithm
216  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
217  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
218 
219  //Drop the incoming fragment
220  return;
221  }
222 
223  //Search for a matching IP datagram being reassembled
224  frag = ipv4SearchFragQueue(interface, packet);
225 
226  //No matching entry in the reassembly queue?
227  if(frag == NULL)
228  {
229  //Number of failures detected by the IP reassembly algorithm
230  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
231  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
232 
233  //Drop the incoming fragment
234  return;
235  }
236 
237  //The very first fragment requires special handling
238  if((offset & IPV4_OFFSET_MASK) == 0)
239  {
240  //Calculate the length of the IP header including options
241  frag->headerLength = packet->headerLength * 4;
242 
243  //Enforce the size of the reconstructed datagram
244  if((frag->headerLength + frag->dataLen) > IPV4_MAX_FRAG_DATAGRAM_SIZE)
245  {
246  //Number of failures detected by the IP reassembly algorithm
247  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
248  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
249 
250  //Drop the reconstructed datagram
251  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
252  //Exit immediately
253  return;
254  }
255 
256  //Make sure the IP header entirely fits in the first chunk
257  if(frag->headerLength > frag->buffer.chunk[0].size)
258  {
259  //Number of failures detected by the IP reassembly algorithm
260  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
261  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
262 
263  //Drop the reconstructed datagram
264  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
265  //Exit immediately
266  return;
267  }
268 
269  //Fix the length of the first chunk
270  frag->buffer.chunk[0].length = (uint16_t) frag->headerLength;
271  //Always take the IP header from the first fragment
272  netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->headerLength);
273  }
274 
275  //It may be necessary to increase the size of the buffer
276  if(dataLast > frag->dataLen)
277  {
278  //Enforce the size of the reconstructed datagram
279  if((frag->headerLength + dataLast) > IPV4_MAX_FRAG_DATAGRAM_SIZE)
280  {
281  //Number of failures detected by the IP reassembly algorithm
282  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
283  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
284 
285  //Drop the reconstructed datagram
286  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
287  //Exit immediately
288  return;
289  }
290 
291  //Adjust the size of the reconstructed datagram
292  error = netBufferSetLength((NetBuffer *) &frag->buffer,
293  frag->headerLength + dataLast + sizeof(Ipv4HoleDesc));
294 
295  //Any error to report?
296  if(error)
297  {
298  //Number of failures detected by the IP reassembly algorithm
299  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
300  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
301 
302  //Drop the reconstructed datagram
303  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
304  //Exit immediately
305  return;
306  }
307 
308  //Actual length of the payload
309  frag->dataLen = dataLast;
310  }
311 
312  //Select the first hole descriptor from the list
313  hole = ipv4FindHole(frag, frag->firstHole);
314  //Keep track of the previous hole in the list
315  prevHole = NULL;
316 
317  //Iterate through the hole descriptors
318  while(hole != NULL)
319  {
320  //Save lower and upper boundaries for later use
321  uint16_t holeFirst = hole->first;
322  uint16_t holeLast = hole->last;
323 
324  //Check whether the newly arrived fragment interacts with this hole in
325  //some way
326  if(dataFirst < holeLast && dataLast > holeFirst)
327  {
328 #if (IPV4_OVERLAPPING_FRAG_SUPPORT == DISABLED)
329  //Prevent overlapping fragment attacks (refer to RFC 8900, section 3.7)
330  if(dataFirst < holeFirst || dataLast > holeLast)
331  {
332  //Number of failures detected by the IP reassembly algorithm
333  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
334  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
335 
336  //Drop the reconstructed datagram
337  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
338  //Exit immediately
339  return;
340  }
341 #endif
342  //The current descriptor is no longer valid. We will destroy it, and in
343  //the next two steps, we will determine whether or not it is necessary
344  //to create any new hole descriptors
345  if(prevHole != NULL)
346  {
347  prevHole->next = hole->next;
348  }
349  else
350  {
351  frag->firstHole = hole->next;
352  }
353 
354  //Is there still a hole at the beginning of the segment?
355  if(dataFirst > holeFirst)
356  {
357  //Create a new entry that describes this hole
358  hole = ipv4FindHole(frag, holeFirst);
359  hole->first = holeFirst;
360  hole->last = dataFirst;
361 
362  //Insert the newly created entry into the hole descriptor list
363  if(prevHole != NULL)
364  {
365  hole->next = prevHole->next;
366  prevHole->next = hole->first;
367  }
368  else
369  {
370  hole->next = frag->firstHole;
371  frag->firstHole = hole->first;
372  }
373 
374  //Always keep track of the previous hole
375  prevHole = hole;
376  }
377 
378  //Is there still a hole at the end of the segment?
379  if(dataLast < holeLast && (offset & IPV4_FLAG_MF) != 0)
380  {
381  //Create a new entry that describes this hole
382  hole = ipv4FindHole(frag, dataLast);
383  hole->first = dataLast;
384  hole->last = holeLast;
385 
386  //Insert the newly created entry into the hole descriptor list
387  if(prevHole != NULL)
388  {
389  hole->next = prevHole->next;
390  prevHole->next = hole->first;
391  }
392  else
393  {
394  hole->next = frag->firstHole;
395  frag->firstHole = hole->first;
396  }
397 
398  //Always keep track of the previous hole
399  prevHole = hole;
400  }
401  }
402  else
403  {
404  //The newly arrived fragment does not interact with the current hole
405  prevHole = hole;
406  }
407 
408  //Select the next hole descriptor from the list
409  hole = ipv4FindHole(frag, prevHole ? prevHole->next : frag->firstHole);
410  }
411 
412  //Copy data from the fragment to the reassembly buffer
413  netBufferWrite((NetBuffer *) &frag->buffer,
414  frag->headerLength + dataFirst, IPV4_DATA(packet), length);
415 
416  //Dump hole descriptor list
417  ipv4DumpHoleList(frag);
418 
419  //If the hole descriptor list is empty, the reassembly process is now
420  //complete
421  if(ipv4FindHole(frag, frag->firstHole) == NULL)
422  {
423  //Discard the extra hole descriptor that follows the reconstructed
424  //datagram
425  error = netBufferSetLength((NetBuffer *) &frag->buffer,
426  frag->headerLength + frag->dataLen);
427 
428  //Check status code
429  if(error)
430  {
431  //Number of failures detected by the IP reassembly algorithm
432  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
433  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
434  }
435  else
436  {
437  //Point to the IP header
438  Ipv4Header *datagram = netBufferAt((NetBuffer *) &frag->buffer, 0, 0);
439 
440  //Fix IP header
441  datagram->totalLength = htons(frag->headerLength + frag->dataLen);
442  datagram->fragmentOffset = 0;
443  datagram->headerChecksum = 0;
444 
445  //Number of IP datagrams successfully reassembled
446  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmOKs, 1);
447  IPV4_IF_STATS_INC_COUNTER32(reasmOKs, 1);
448 
449  //Pass the original IPv4 datagram to the higher protocol layer
450  ipv4ProcessDatagram(interface, (NetBuffer *) &frag->buffer, 0,
451  ancillary);
452  }
453 
454  //Release previously allocated memory
455  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
456  }
457 }
458 
459 
460 /**
461  * @brief Fragment reassembly timeout handler
462  *
463  * This routine must be periodically called by the TCP/IP stack to
464  * handle IPv4 fragment reassembly timeout
465  *
466  * @param[in] interface Underlying network interface
467  **/
468 
469 void ipv4FragTick(NetInterface *interface)
470 {
471  error_t error;
472  uint_t i;
473  systime_t time;
474  Ipv4HoleDesc *hole;
475 
476  //Get current time
477  time = osGetSystemTime();
478 
479  //Loop through the reassembly queue
480  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
481  {
482  //Point to the current entry in the reassembly queue
483  Ipv4FragDesc *frag = &interface->ipv4Context.fragQueue[i];
484 
485  //Make sure the entry is currently in use
486  if(frag->buffer.chunkCount > 0)
487  {
488  //If the timer runs out, the partially-reassembled datagram must be
489  //discarded and ICMP Time Exceeded message sent to the source host
490  if((time - frag->timestamp) >= IPV4_FRAG_TIME_TO_LIVE)
491  {
492  //Debug message
493  TRACE_INFO("IPv4 fragment reassembly timeout...\r\n");
494  //Dump IP header contents for debugging purpose
496 
497  //Number of failures detected by the IP reassembly algorithm
498  IPV4_SYSTEM_STATS_INC_COUNTER32(reasmFails, 1);
499  IPV4_IF_STATS_INC_COUNTER32(reasmFails, 1);
500 
501  //Point to the first hole descriptor
502  hole = ipv4FindHole(frag, frag->firstHole);
503 
504  //Make sure the fragment zero has been received before sending an
505  //ICMP message
506  if(hole != NULL && hole->first > 0)
507  {
508  //Fix the size of the reconstructed datagram
509  error = netBufferSetLength((NetBuffer *) &frag->buffer,
510  frag->headerLength + hole->first);
511 
512  //Check status code
513  if(!error)
514  {
515  //Send an ICMP Time Exceeded message
518  (NetBuffer *) &frag->buffer, 0);
519  }
520  }
521 
522  //Drop the partially reconstructed datagram
523  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
524  }
525  }
526  }
527 }
528 
529 
530 /**
531  * @brief Search for a matching datagram in the reassembly queue
532  * @param[in] interface Underlying network interface
533  * @param[in] packet Incoming IPv4 packet
534  * @return Matching fragment descriptor
535  **/
536 
538  const Ipv4Header *packet)
539 {
540  error_t error;
541  uint_t i;
542  Ipv4Header *datagram;
543  Ipv4FragDesc *frag;
544  Ipv4HoleDesc *hole;
545 
546  //Search for a matching IP datagram being reassembled
547  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
548  {
549  //Point to the current entry in the reassembly queue
550  frag = &interface->ipv4Context.fragQueue[i];
551 
552  //Check whether the current entry is used?
553  if(frag->buffer.chunkCount > 0)
554  {
555  //Point to the corresponding datagram
556  datagram = netBufferAt((NetBuffer *) &frag->buffer, 0, 0);
557 
558  //Check source and destination addresses
559  if(datagram->srcAddr != packet->srcAddr)
560  continue;
561  if(datagram->destAddr != packet->destAddr)
562  continue;
563 
564  //Compare identification and protocol fields
565  if(datagram->identification != packet->identification)
566  continue;
567  if(datagram->protocol != packet->protocol)
568  continue;
569 
570  //A matching entry has been found in the reassembly queue
571  return frag;
572  }
573  }
574 
575  //If the current packet does not match an existing entry in the reassembly
576  //queue, then create a new entry
577  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
578  {
579  //Point to the current entry in the reassembly queue
580  frag = &interface->ipv4Context.fragQueue[i];
581 
582  //Check whether the current entry is free
583  if(frag->buffer.chunkCount == 0)
584  {
585  //Number of chunks that comprise the reassembly buffer
586  frag->buffer.maxChunkCount = arraysize(frag->buffer.chunk);
587 
588  //Allocate sufficient memory to hold the IPv4 header and the first
589  //hole descriptor
590  error = netBufferSetLength((NetBuffer *) &frag->buffer,
592 
593  //Failed to allocate memory?
594  if(error)
595  {
596  //Clean up side effects
597  netBufferSetLength((NetBuffer *) &frag->buffer, 0);
598  //Exit immediately
599  return NULL;
600  }
601 
602  //Initial length of the reconstructed datagram
603  frag->headerLength = packet->headerLength * 4;
604  frag->dataLen = 0;
605 
606  //Fix the length of the first chunk
607  frag->buffer.chunk[0].length = (uint16_t) frag->headerLength;
608  //Copy IPv4 header from the incoming fragment
609  netBufferWrite((NetBuffer *) &frag->buffer, 0, packet, frag->headerLength);
610 
611  //Save current time
612  frag->timestamp = osGetSystemTime();
613  //Create a new entry in the hole descriptor list
614  frag->firstHole = 0;
615 
616  //Point to first hole descriptor
617  hole = ipv4FindHole(frag, frag->firstHole);
618  //The entry describes the datagram as being completely missing
619  hole->first = 0;
620  hole->last = IPV4_INFINITY;
621  hole->next = IPV4_INFINITY;
622 
623  //Dump hole descriptor list
624  ipv4DumpHoleList(frag);
625 
626  //Return the matching fragment descriptor
627  return frag;
628  }
629  }
630 
631  //The reassembly queue is full
632  return NULL;
633 }
634 
635 
636 /**
637  * @brief Flush IPv4 reassembly queue
638  * @param[in] interface Underlying network interface
639  **/
640 
642 {
643  uint_t i;
644 
645  //Loop through the reassembly queue
646  for(i = 0; i < IPV4_MAX_FRAG_DATAGRAMS; i++)
647  {
648  //Drop any partially reconstructed datagram
649  netBufferSetLength((NetBuffer *) &interface->ipv4Context.fragQueue[i].buffer, 0);
650  }
651 }
652 
653 
654 /**
655  * @brief Retrieve hole descriptor
656  * @param[in] frag IPv4 fragment descriptor
657  * @param[in] offset Offset of the hole
658  * @return A pointer to the hole descriptor is returned if the specified
659  * offset is valid. Otherwise NULL is returned
660  **/
661 
662 Ipv4HoleDesc *ipv4FindHole(Ipv4FragDesc *frag, uint16_t offset)
663 {
664  //Return a pointer to the hole descriptor
665  return netBufferAt((NetBuffer *) &frag->buffer, frag->headerLength + offset, 0);
666 }
667 
668 
669 /**
670  * @brief Dump hole descriptor list
671  * @param[in] frag IPv4 fragment descriptor
672  **/
673 
675 {
676 //Check debugging level
677 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
678  Ipv4HoleDesc *hole;
679 
680  //Debug message
681  TRACE_DEBUG("Hole descriptor list:\r\n");
682  //Select the first hole descriptor from the list
683  hole = ipv4FindHole(frag, frag->firstHole);
684 
685  //Loop through the hole descriptor list
686  while(hole != NULL)
687  {
688  //Display current hole
689  TRACE_DEBUG(" %" PRIu16 " - %" PRIu16 "\r\n", hole->first, hole->last);
690  //Select the next hole descriptor from the list
691  hole = ipv4FindHole(frag, hole->next);
692  }
693 #endif
694 }
695 
696 #endif
systime_t timestamp
Time at which the first fragment was received.
Definition: ipv4_frag.h:136
#define htons(value)
Definition: cpu_endian.h:413
ChunkDesc chunk[N(IPV4_MAX_FRAG_DATAGRAM_SIZE)+1]
Definition: ipv4_frag.h:126
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:716
#define Ipv4Header
Definition: ipv4.h:36
void ipv4FragTick(NetInterface *interface)
Fragment reassembly timeout handler.
Definition: ipv4_frag.c:469
@ IPV4_OFFSET_MASK
Definition: ipv4.h:264
void ipv4FlushFragQueue(NetInterface *interface)
Flush IPv4 reassembly queue.
Definition: ipv4_frag.c:641
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ICMP_TYPE_TIME_EXCEEDED
Definition: icmp.h:93
#define IPV4_MAX_FRAG_DATAGRAM_SIZE
Definition: ipv4_frag.h:69
void ipv4ProcessDatagram(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Incoming IPv4 datagram processing.
Definition: ipv4.c:830
error_t ipv4FragmentDatagram(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, uint16_t id, const NetBuffer *payload, size_t payloadOffset, NetTxAncillary *ancillary)
Fragment an IPv4 datagram into smaller packets.
Definition: ipv4_frag.c:67
void ipv4DumpHoleList(Ipv4FragDesc *frag)
Dump hole descriptor list.
Definition: ipv4_frag.c:674
error_t netBufferConcat(NetBuffer *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Concatenate two multi-part buffers.
Definition: net_mem.c:460
void ipv4DumpHeader(const Ipv4Header *ipHeader)
Dump IPv4 header for debugging purpose.
Definition: ipv4.c:1492
#define NET_MEM_POOL_BUFFER_SIZE
Definition: net_mem.h:55
uint16_t length
Definition: net_mem.h:79
uint16_t firstHole
Index of the first hole.
Definition: ipv4_frag.h:139
ICMP (Internet Control Message Protocol)
error_t
Error codes.
Definition: error.h:43
size_t dataLen
Length of the payload.
Definition: ipv4_frag.h:138
error_t ipv4SendPacket(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, uint16_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv4 packet.
Definition: ipv4.c:1104
void * address
Definition: net_mem.h:78
@ IPV4_FLAG_MF
Definition: ipv4.h:263
void ipv4ReassembleDatagram(NetInterface *interface, const Ipv4Header *packet, size_t length, NetRxAncillary *ancillary)
IPv4 datagram reassembly algorithm.
Definition: ipv4_frag.c:176
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
#define IPV4_DATA(packet)
Definition: ipv4.h:118
#define NetTxAncillary
Definition: net_misc.h:36
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define IPV4_FRAG_TIME_TO_LIVE
Definition: ipv4_frag.h:76
size_t headerLength
Length of the header.
Definition: ipv4_frag.h:137
uint32_t systime_t
System time.
#define ntohs(value)
Definition: cpu_endian.h:421
Fragmented packet descriptor.
Definition: ipv4_frag.h:135
#define IPV4_SYSTEM_STATS_INC_COUNTER32(name, value)
Definition: ipv4.h:191
#define IPV4_MAX_FRAG_DATAGRAMS
Definition: ipv4_frag.h:62
#define TRACE_DEBUG(...)
Definition: debug.h:119
uint32_t time
IPv4 fragmentation and reassembly.
IPv4 and IPv6 common routines.
uint8_t payload[]
Definition: ipv6.h:306
Ipv4FragDesc * ipv4SearchFragQueue(NetInterface *interface, const Ipv4Header *packet)
Search for a matching datagram in the reassembly queue.
Definition: ipv4_frag.c:537
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
size_t netBufferWrite(NetBuffer *dest, size_t destOffset, const void *src, size_t length)
Write data to a multi-part buffer.
Definition: net_mem.c:637
Ipv4HoleDesc
Definition: ipv4_frag.h:107
#define IPV4_IF_STATS_INC_COUNTER32(name, value)
Definition: ipv4.h:193
Ipv4HoleDesc * ipv4FindHole(Ipv4FragDesc *frag, uint16_t offset)
Retrieve hole descriptor.
Definition: ipv4_frag.c:662
#define IPV4_INFINITY
Definition: ipv4_frag.h:82
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
IPv4 (Internet Protocol Version 4)
uint16_t payloadLen
Definition: ipv6.h:301
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
uint16_t size
Definition: net_mem.h:80
uint16_t fragmentOffset
Definition: ipv4.h:349
Ipv4ReassemblyBuffer buffer
Buffer containing the reassembled datagram.
Definition: ipv4_frag.h:140
error_t icmpSendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, uint8_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset)
Send an ICMP Error message.
Definition: icmp.c:335
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define arraysize(a)
Definition: os_port.h:71
systime_t osGetSystemTime(void)
Retrieve system time.
@ ICMP_CODE_REASSEMBLY_TIME_EXCEEDED
Definition: icmp.h:127