1 /*
2 * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 /**
29 * @file FreeRTOS_IPv6.c
30 * @brief Implements the basic functionality for the FreeRTOS+TCP network stack.
31 */
32
33 /* Standard includes. */
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <string.h>
37
38 /* FreeRTOS includes. */
39 #include "FreeRTOS.h"
40
41 /* FreeRTOS+TCP includes. */
42 #include "FreeRTOS_IP.h"
43
44 /* *INDENT-OFF* */
45 #if( ipconfigUSE_IPv6 != 0 )
46 /* *INDENT-ON* */
47
48 /** @brief Get the scope field in IPv6 multicast address. */
49 #define IPv6MC_GET_SCOPE_VALUE( pxIPv6Address ) ( ( ( pxIPv6Address )->ucBytes[ 1 ] ) & 0x0FU )
50
51 /** @brief Get the flags field in IPv6 multicast address. */
52 #define IPv6MC_GET_FLAGS_VALUE( pxIPv6Address ) ( ( ( pxIPv6Address )->ucBytes[ 1 ] ) & 0xF0U )
53
54 /** @brief Get the group ID field in IPv6 multicast address. */
55 #define IPv6MC_GET_GROUP_ID( pxIPv6Address, pxReturnGroupID ) ( xGetIPv6MulticastGroupID( pxIPv6Address, pxReturnGroupID ) )
56
57 /**
58 * This variable is initialized by the system to contain the wildcard IPv6 address.
59 */
60 const struct xIPv6_Address FreeRTOS_in6addr_any = { 0 };
61
62 /**
63 * This variable is initialized by the system to contain the loopback IPv6 address.
64 */
65 const struct xIPv6_Address FreeRTOS_in6addr_loopback = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } };
66
67 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
68 /* Check IPv6 packet length. */
69 static BaseType_t xCheckIPv6SizeFields( const void * const pvEthernetBuffer,
70 size_t uxBufferLength );
71 #endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) */
72
73 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
74 /* Check if ucNextHeader is an extension header. */
75 static BaseType_t xIsExtHeader( uint8_t ucNextHeader );
76 #endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) */
77
78 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
79
80 /**
81 * @brief Check IPv6 packet length.
82 *
83 * @param[in] pvEthernetBuffer The Ethernet packet received.
84 * @param[in] uxBufferLength The total number of bytes received.
85 *
86 * @return pdPASS when the length fields in the packet OK, pdFAIL when the packet
87 * should be dropped.
88 */
xCheckIPv6SizeFields(const void * const pvEthernetBuffer,size_t uxBufferLength)89 static BaseType_t xCheckIPv6SizeFields( const void * const pvEthernetBuffer,
90 size_t uxBufferLength )
91 {
92 BaseType_t xResult = pdFAIL;
93 uint16_t ucVersionTrafficClass;
94 uint16_t usPayloadLength;
95 uint8_t ucNextHeader;
96 size_t uxMinimumLength;
97 size_t uxExtHeaderLength = 0;
98 const IPExtHeader_IPv6_t * pxExtHeader = NULL;
99 const uint8_t * const pucEthernetBuffer = ( const uint8_t * const ) pvEthernetBuffer;
100
101 /* Map the buffer onto a IPv6-Packet struct to easily access the
102 * fields of the IPv6 packet. */
103 const IPPacket_IPv6_t * const pxIPv6Packet = ( const IPPacket_IPv6_t * const ) pucEthernetBuffer;
104
105 DEBUG_DECLARE_TRACE_VARIABLE( BaseType_t, xLocation, 0 );
106
107 do
108 {
109 /* Check for minimum packet size: Ethernet header and an IPv6-header, 54 bytes */
110 if( uxBufferLength < sizeof( IPHeader_IPv6_t ) )
111 {
112 DEBUG_SET_TRACE_VARIABLE( xLocation, 1 );
113 break;
114 }
115
116 ucVersionTrafficClass = pxIPv6Packet->xIPHeader.ucVersionTrafficClass;
117
118 /* Test if the IP-version is 6. */
119 if( ( ( ucVersionTrafficClass & ( uint8_t ) 0xF0U ) >> 4 ) != 6U )
120 {
121 DEBUG_SET_TRACE_VARIABLE( xLocation, 2 );
122 break;
123 }
124
125 /* Check if the IPv6-header is transferred. */
126 if( uxBufferLength < ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ) )
127 {
128 DEBUG_SET_TRACE_VARIABLE( xLocation, 3 );
129 break;
130 }
131
132 /* Check if the complete IPv6-header plus protocol data have been transferred: */
133 usPayloadLength = FreeRTOS_ntohs( pxIPv6Packet->xIPHeader.usPayloadLength );
134
135 if( uxBufferLength != ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + ( size_t ) usPayloadLength ) )
136 {
137 DEBUG_SET_TRACE_VARIABLE( xLocation, 4 );
138 break;
139 }
140
141 /* Identify the next protocol. */
142 ucNextHeader = pxIPv6Packet->xIPHeader.ucNextHeader;
143
144 while( xIsExtHeader( ucNextHeader ) )
145 {
146 pxExtHeader = ( const IPExtHeader_IPv6_t * ) ( &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtHeaderLength ] ) );
147 /* The definition of length in extension header - Length of this header in 8-octet units, not including the first 8 octets. */
148 uxExtHeaderLength += ( size_t ) ( ( 8 * pxExtHeader->ucHeaderExtLength ) + 8 );
149
150 ucNextHeader = pxExtHeader->ucNextHeader;
151
152 if( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtHeaderLength >= uxBufferLength )
153 {
154 break;
155 }
156 }
157
158 if( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtHeaderLength >= uxBufferLength )
159 {
160 DEBUG_SET_TRACE_VARIABLE( xLocation, 7 );
161 break;
162 }
163
164 /* Switch on the Layer 3/4 protocol. */
165 if( ucNextHeader == ( uint8_t ) ipPROTOCOL_UDP )
166 {
167 /* Expect at least a complete UDP header. */
168 uxMinimumLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtHeaderLength + ipSIZE_OF_UDP_HEADER;
169 }
170 else if( ucNextHeader == ( uint8_t ) ipPROTOCOL_TCP )
171 {
172 uxMinimumLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtHeaderLength + ipSIZE_OF_TCP_HEADER;
173 }
174 else if( ucNextHeader == ( uint8_t ) ipPROTOCOL_ICMP_IPv6 )
175 {
176 uxMinimumLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtHeaderLength + ipSIZE_OF_ICMPv6_HEADER;
177 }
178 else
179 {
180 /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
181 DEBUG_SET_TRACE_VARIABLE( xLocation, 5 );
182 break;
183 }
184
185 if( uxBufferLength < uxMinimumLength )
186 {
187 DEBUG_SET_TRACE_VARIABLE( xLocation, 6 );
188 break;
189 }
190
191 xResult = pdPASS;
192 } while( ipFALSE_BOOL );
193
194 if( xResult != pdPASS )
195 {
196 /* NOP if ipconfigHAS_PRINTF != 1 */
197 FreeRTOS_printf( ( "xCheckIPv6SizeFields: location %ld\n", xLocation ) );
198 }
199
200 return xResult;
201 }
202
203
204 #endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) */
205 /*-----------------------------------------------------------*/
206
207
208 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 )
209
210 /**
211 * @brief Check if ucNextHeader is an extension header.
212 *
213 * @param[in] ucNextHeader Next header, such as ipIPv6_EXT_HEADER_HOP_BY_HOP.
214 *
215 * @return pdTRUE if it's extension header, otherwise pdFALSE.
216 */
xIsExtHeader(uint8_t ucNextHeader)217 static BaseType_t xIsExtHeader( uint8_t ucNextHeader )
218 {
219 BaseType_t xReturn = pdFALSE;
220
221 switch( ucNextHeader )
222 {
223 case ipIPv6_EXT_HEADER_HOP_BY_HOP:
224 case ipIPv6_EXT_HEADER_ROUTING_HEADER:
225 case ipIPv6_EXT_HEADER_FRAGMENT_HEADER:
226 case ipIPv6_EXT_HEADER_SECURE_PAYLOAD:
227 case ipIPv6_EXT_HEADER_AUTHEN_HEADER:
228 case ipIPv6_EXT_HEADER_DESTINATION_OPTIONS:
229 case ipIPv6_EXT_HEADER_MOBILITY_HEADER:
230 xReturn = pdTRUE;
231 }
232
233 return xReturn;
234 }
235
236
237 #endif /* ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 1 ) */
238 /*-----------------------------------------------------------*/
239
240 /**
241 * This variable is initialized by the system to contain the unspecified IPv6 address.
242 */
243 static const struct xIPv6_Address xIPv6UnspecifiedAddress = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
244
245 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
246
247 /*
248 * Check if the packet is a loopback packet.
249 */
250 static BaseType_t xIsIPv6Loopback( const IPHeader_IPv6_t * const pxIPv6Header );
251 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 */
252
253 /**
254 * @brief Get the group ID and stored into IPv6_Address_t.
255 *
256 * @param[in] pxIPv6Address The multicast address to filter group ID.
257 * @param[out] pxReturnGroupID The buffer to store group ID.
258 */
xGetIPv6MulticastGroupID(const IPv6_Address_t * pxIPv6Address,IPv6_Address_t * pxReturnGroupID)259 static void xGetIPv6MulticastGroupID( const IPv6_Address_t * pxIPv6Address,
260 IPv6_Address_t * pxReturnGroupID )
261 {
262 configASSERT( pxIPv6Address != NULL );
263 configASSERT( pxReturnGroupID != NULL );
264
265 pxReturnGroupID->ucBytes[ 0 ] = 0U;
266 pxReturnGroupID->ucBytes[ 1 ] = 0U;
267 ( void ) memcpy( &( pxReturnGroupID->ucBytes[ 2 ] ), &( pxIPv6Address->ucBytes[ 2 ] ), 14 );
268 }
269
270
271 /*-----------------------------------------------------------*/
272
273 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
274
275 /**
276 * @brief Check if the packet is a loopback packet.
277 *
278 * @param[in] pxIPv6Header The IP packet in pxNetworkBuffer.
279 *
280 * @return Returns pdTRUE if it's a legal loopback packet, pdFALSE if not .
281 */
282 /* MISRA Ref 8.9.1 [File scoped variables] */
283 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
284 /* coverity[misra_c_2012_rule_8_9_violation] */
285 /* coverity[single_use] */
xIsIPv6Loopback(const IPHeader_IPv6_t * const pxIPv6Header)286 static BaseType_t xIsIPv6Loopback( const IPHeader_IPv6_t * const pxIPv6Header )
287 {
288 BaseType_t xReturn = pdFALSE;
289 const NetworkEndPoint_t * pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv6( &( pxIPv6Header->xSourceAddress ) );
290
291 /* Allow loopback packets from this node itself only. */
292 if( ( pxEndPoint != NULL ) &&
293 ( memcmp( pxIPv6Header->xDestinationAddress.ucBytes, FreeRTOS_in6addr_loopback.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) &&
294 ( memcmp( pxIPv6Header->xSourceAddress.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) )
295 {
296 xReturn = pdTRUE;
297 }
298
299 return xReturn;
300 }
301 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 */
302
303
304 /*-----------------------------------------------------------*/
305
306 /**
307 * @brief Check whether this IPv6 address is an allowed multicast address or not.
308 *
309 * @param[in] pxIPAddress The IP address to be checked.
310 *
311 * @return Returns pdTRUE if pxIPAddress is an allowed multicast address, pdFALSE if not.
312 */
xIsIPv6AllowedMulticast(const IPv6_Address_t * pxIPAddress)313 BaseType_t xIsIPv6AllowedMulticast( const IPv6_Address_t * pxIPAddress )
314 {
315 BaseType_t xReturn = pdFALSE;
316 IPv6_Address_t xGroupIDAddress;
317
318 if( pxIPAddress->ucBytes[ 0 ] == 0xffU )
319 {
320 IPv6MC_GET_GROUP_ID( pxIPAddress, &xGroupIDAddress );
321
322 /* From RFC4291 - sec 2.7, packets from multicast address whose scope field is 0
323 * should be silently dropped. */
324 if( IPv6MC_GET_SCOPE_VALUE( pxIPAddress ) == 0U )
325 {
326 xReturn = pdFALSE;
327 }
328
329 /* From RFC4291 - sec 2.7.1, packets from predefined multicast address should never be used.
330 * - 0xFF00::
331 * - 0xFF01::
332 * - ..
333 * - 0xFF0F:: */
334 else if( ( IPv6MC_GET_FLAGS_VALUE( pxIPAddress ) == 0U ) &&
335 ( memcmp( xGroupIDAddress.ucBytes, xIPv6UnspecifiedAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) )
336 {
337 xReturn = pdFALSE;
338 }
339 else
340 {
341 xReturn = pdTRUE;
342 }
343 }
344
345 return xReturn;
346 }
347
348
349 /*-----------------------------------------------------------*/
350
351 /**
352 * @brief Compares 2 IPv6 addresses and checks if the one
353 * on the left can handle the one on right. Note that 'xCompareIPv6_Address' will also check if 'pxRight' is
354 * the special unicast address: ff02::1:ffnn:nnnn, where nn:nnnn are
355 * the last 3 bytes of the IPv6 address.
356 *
357 * @param[in] pxLeft First IP address.
358 * @param[in] pxRight Second IP address.
359 * @param[in] uxPrefixLength The IP address prefix length in bits.
360 *
361 * @return Returns 0 if it can handle it, else non zero .
362 */
xCompareIPv6_Address(const IPv6_Address_t * pxLeft,const IPv6_Address_t * pxRight,size_t uxPrefixLength)363 BaseType_t xCompareIPv6_Address( const IPv6_Address_t * pxLeft,
364 const IPv6_Address_t * pxRight,
365 size_t uxPrefixLength )
366 {
367 BaseType_t xResult;
368 /* This variable is initialized by the system to contain the IPv6 multicast address for all nodes. */
369 static const struct xIPv6_Address FreeRTOS_in6addr_allnodes = { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } };
370
371 /* 0 2 4 6 8 10 12 14 */
372 /* ff02:0000:0000:0000:0000:0001:ff66:4a81 */
373 if( ( pxRight->ucBytes[ 0 ] == 0xffU ) &&
374 ( pxRight->ucBytes[ 1 ] == 0x02U ) &&
375 ( pxRight->ucBytes[ 12 ] == 0xffU ) )
376 {
377 /* This is an LLMNR address. */
378 xResult = memcmp( &( pxLeft->ucBytes[ 13 ] ), &( pxRight->ucBytes[ 13 ] ), 3 );
379 }
380 else
381 if( memcmp( pxRight->ucBytes, FreeRTOS_in6addr_allnodes.ucBytes, sizeof( IPv6_Address_t ) ) == 0 )
382 {
383 /* FF02::1 is all node address to reach out all nodes in the same link. */
384 xResult = 0;
385 }
386 else
387 if( ( pxRight->ucBytes[ 0 ] == 0xfeU ) &&
388 ( pxRight->ucBytes[ 1 ] == 0x80U ) &&
389 ( pxLeft->ucBytes[ 0 ] == 0xfeU ) &&
390 ( pxLeft->ucBytes[ 1 ] == 0x80U ) )
391 {
392 /* Both are local addresses. */
393 xResult = 0;
394 }
395 else
396 {
397 if( uxPrefixLength == 0U )
398 {
399 xResult = 0;
400 }
401 else if( uxPrefixLength == ( 8U * ipSIZE_OF_IPv6_ADDRESS ) )
402 {
403 xResult = memcmp( pxLeft->ucBytes, pxRight->ucBytes, ipSIZE_OF_IPv6_ADDRESS );
404 }
405 else
406 {
407 size_t uxLength = uxPrefixLength / 8U;
408
409 xResult = 0;
410
411 if( uxLength > 0U )
412 {
413 xResult = memcmp( pxLeft->ucBytes, pxRight->ucBytes, uxLength );
414 }
415
416 if( ( xResult == 0 ) && ( ( uxPrefixLength % 8U ) != 0U ) )
417 {
418 /* One byte has both a network- and a host-address. */
419 size_t uxBits = uxPrefixLength % 8U;
420 size_t uxHostLen = 8U - uxBits;
421 uint32_t uxHostMask = ( ( ( uint32_t ) 1U ) << uxHostLen ) - 1U;
422 uint8_t ucNetMask = ( uint8_t ) ~( uxHostMask );
423
424 if( ( pxLeft->ucBytes[ uxLength ] & ucNetMask ) != ( pxRight->ucBytes[ uxLength ] & ucNetMask ) )
425 {
426 xResult = 1;
427 }
428 }
429 }
430 }
431
432 return xResult;
433 }
434
435
436 /*-----------------------------------------------------------*/
437
438
439 /**
440 * @brief Check whether this IPv6 packet is to be allowed or to be dropped.
441 *
442 * @param[in] pxIPv6Header The IP packet under consideration.
443 * @param[in] pxNetworkBuffer The whole network buffer.
444 * @param[in] uxHeaderLength The length of the header.
445 *
446 * @return Whether the packet should be processed or dropped.
447 */
prvAllowIPPacketIPv6(const IPHeader_IPv6_t * const pxIPv6Header,const NetworkBufferDescriptor_t * const pxNetworkBuffer,UBaseType_t uxHeaderLength)448 eFrameProcessingResult_t prvAllowIPPacketIPv6( const IPHeader_IPv6_t * const pxIPv6Header,
449 const NetworkBufferDescriptor_t * const pxNetworkBuffer,
450 UBaseType_t uxHeaderLength )
451 {
452 eFrameProcessingResult_t eReturn;
453
454 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
455 {
456 /* In systems with a very small amount of RAM, it might be advantageous
457 * to have incoming messages checked earlier, by the network card driver.
458 * This method may decrease the usage of sparse network buffers. */
459 const IPv6_Address_t * pxDestinationIPAddress = &( pxIPv6Header->xDestinationAddress );
460 const IPv6_Address_t * pxSourceIPAddress = &( pxIPv6Header->xSourceAddress );
461 BaseType_t xHasUnspecifiedAddress = pdFALSE;
462
463 /* Drop if packet has unspecified IPv6 address (defined in RFC4291 - sec 2.5.2)
464 * either in source or destination address. */
465 if( ( memcmp( pxDestinationIPAddress->ucBytes, xIPv6UnspecifiedAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) ||
466 ( memcmp( pxSourceIPAddress->ucBytes, xIPv6UnspecifiedAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) )
467 {
468 xHasUnspecifiedAddress = pdTRUE;
469 }
470
471 /* Is the packet for this IP address? */
472 if( ( xHasUnspecifiedAddress == pdFALSE ) &&
473 ( pxNetworkBuffer->pxEndPoint != NULL ) &&
474 ( memcmp( pxDestinationIPAddress->ucBytes, pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) )
475 {
476 eReturn = eProcessBuffer;
477 }
478 /* Is it the legal multicast address? */
479 else if( ( xHasUnspecifiedAddress == pdFALSE ) &&
480 ( ( xIsIPv6AllowedMulticast( pxDestinationIPAddress ) != pdFALSE ) ||
481 /* Is it loopback address sent from this node? */
482 ( xIsIPv6Loopback( pxIPv6Header ) != pdFALSE ) ||
483 /* Or (during DHCP negotiation) we have no IP-address yet? */
484 ( FreeRTOS_IsNetworkUp() == 0 ) ) )
485 {
486 eReturn = eProcessBuffer;
487 }
488 else
489 {
490 /* Packet is not for this node, or the network is still not up,
491 * release it */
492 eReturn = eReleaseBuffer;
493 FreeRTOS_printf( ( "prvAllowIPPacketIPv6: drop %pip (from %pip)\n", pxDestinationIPAddress->ucBytes, pxIPv6Header->xSourceAddress.ucBytes ) );
494 }
495 }
496 #else /* if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) */
497 {
498 ( void ) pxIPv6Header;
499 /* The packet has been checked by the network interface. */
500 eReturn = eProcessBuffer;
501 }
502 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
503
504 #if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 )
505 {
506 /* Some drivers of NIC's with checksum-offloading will enable the above
507 * define, so that the checksum won't be checked again here */
508 if( eReturn == eProcessBuffer )
509 {
510 /* MISRA Ref 11.3.1 [Misaligned access] */
511 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
512 /* coverity[misra_c_2012_rule_11_3_violation] */
513 const IPPacket_t * pxIPPacket = ( ( const IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
514 const NetworkEndPoint_t * pxEndPoint = FreeRTOS_FindEndPointOnMAC( &( pxIPPacket->xEthernetHeader.xSourceAddress ), NULL );
515
516 /* IPv6 does not have a separate checksum in the IP-header */
517 /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */
518 /* Do not check the checksum of loop-back messages. */
519 if( pxEndPoint == NULL )
520 {
521 if( usGenerateProtocolChecksum( ( uint8_t * ) ( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )
522 {
523 /* Protocol checksum not accepted. */
524 eReturn = eReleaseBuffer;
525 }
526 }
527 }
528 }
529 #else /* if ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) */
530 {
531 if( eReturn == eProcessBuffer )
532 {
533 if( xCheckIPv6SizeFields( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength ) != pdPASS )
534 {
535 /* Some of the length checks were not successful. */
536 eReturn = eReleaseBuffer;
537 }
538 }
539
540 /* to avoid warning unused parameters */
541 ( void ) pxNetworkBuffer;
542 }
543 #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */
544 ( void ) uxHeaderLength;
545
546 return eReturn;
547 }
548
549 /*-----------------------------------------------------------*/
550
551 /**
552 * @brief Check extension header and next header and return their order.
553 *
554 * @param[in] ucProtocol Extension header ID.
555 * @param[in] ucNextHeader Next header ID.
556 *
557 * @return Extension header order in the packet.
558 */
xGetExtensionOrder(uint8_t ucProtocol,uint8_t ucNextHeader)559 BaseType_t xGetExtensionOrder( uint8_t ucProtocol,
560 uint8_t ucNextHeader )
561 {
562 BaseType_t xReturn;
563
564 switch( ucProtocol )
565 {
566 case ipIPv6_EXT_HEADER_HOP_BY_HOP:
567 xReturn = 1;
568 break;
569
570 case ipIPv6_EXT_HEADER_DESTINATION_OPTIONS:
571 xReturn = 7;
572
573 if( ucNextHeader == ipIPv6_EXT_HEADER_ROUTING_HEADER )
574 {
575 xReturn = 2;
576 }
577
578 break;
579
580 case ipIPv6_EXT_HEADER_ROUTING_HEADER:
581 xReturn = 3;
582 break;
583
584 case ipIPv6_EXT_HEADER_FRAGMENT_HEADER:
585 xReturn = 4;
586 break;
587
588 case ipIPv6_EXT_HEADER_AUTHEN_HEADER:
589 xReturn = 5;
590 break;
591
592 case ipIPv6_EXT_HEADER_SECURE_PAYLOAD:
593 xReturn = 6;
594 break;
595
596 /* Destination options may follow here in case there are no routing options. */
597 case ipIPv6_EXT_HEADER_MOBILITY_HEADER:
598 xReturn = 8;
599 break;
600
601 default:
602 xReturn = -1;
603 break;
604 }
605
606 return xReturn;
607 }
608
609
610 /*-----------------------------------------------------------*/
611
612
613
614 /**
615 * @brief Handle the IPv6 extension headers.
616 *
617 * @param[in,out] pxNetworkBuffer The received packet that contains IPv6 extension headers.
618 * @param[in] xDoRemove Function removes the extension header if xDoRemove is set to pdTRUE.
619 *
620 * @return eProcessBuffer in case the options are removed successfully, otherwise
621 * eReleaseBuffer.
622 */
eHandleIPv6ExtensionHeaders(NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t xDoRemove)623 eFrameProcessingResult_t eHandleIPv6ExtensionHeaders( NetworkBufferDescriptor_t * const pxNetworkBuffer,
624 BaseType_t xDoRemove )
625 {
626 eFrameProcessingResult_t eResult = eReleaseBuffer;
627 const size_t uxMaxLength = pxNetworkBuffer->xDataLength;
628 /* MISRA Ref 11.3.1 [Misaligned access] */
629 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
630 /* coverity[misra_c_2012_rule_11_3_violation] */
631 IPPacket_IPv6_t * pxIPPacket_IPv6 = ( ( IPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
632 size_t xMoveLen = 0U;
633 size_t uxRemovedBytes = 0U;
634 uint8_t ucNextHeader = 0U;
635 size_t uxIndex = 0U;
636
637 uxRemovedBytes = usGetExtensionHeaderLength( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, &ucNextHeader );
638 uxIndex = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxRemovedBytes;
639
640 if( uxIndex < uxMaxLength )
641 {
642 uint8_t * pucTo;
643 const uint8_t * pucFrom;
644 uint16_t usPayloadLength = FreeRTOS_ntohs( pxIPPacket_IPv6->xIPHeader.usPayloadLength );
645
646 if( uxRemovedBytes >= ( size_t ) usPayloadLength )
647 {
648 /* Can not remove more bytes than the payload length. */
649 }
650 else if( xDoRemove == pdTRUE )
651 {
652 pxIPPacket_IPv6->xIPHeader.ucNextHeader = ucNextHeader;
653 pucTo = &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ] );
654 pucFrom = &( pxNetworkBuffer->pucEthernetBuffer[ uxIndex ] );
655 xMoveLen = uxMaxLength - uxIndex;
656 ( void ) memmove( pucTo, pucFrom, xMoveLen );
657 pxNetworkBuffer->xDataLength -= uxRemovedBytes;
658
659 usPayloadLength = ( uint16_t ) ( usPayloadLength - uxRemovedBytes );
660 pxIPPacket_IPv6->xIPHeader.usPayloadLength = FreeRTOS_htons( usPayloadLength );
661 eResult = eProcessBuffer;
662 }
663 else
664 {
665 /* xDoRemove is false, so the function is not supposed to
666 * remove extension headers. */
667 }
668 }
669
670 FreeRTOS_printf( ( "Extension headers : %s Truncated %u bytes. Removed %u, Payload %u xDataLength now %u\n",
671 ( eResult == eProcessBuffer ) ? "good" : "bad",
672 ( unsigned ) xMoveLen,
673 ( unsigned ) uxRemovedBytes,
674 FreeRTOS_ntohs( pxIPPacket_IPv6->xIPHeader.usPayloadLength ),
675 ( unsigned ) pxNetworkBuffer->xDataLength ) );
676 return eResult;
677 }
678
679
680 /*-----------------------------------------------------------*/
681
682 /* *INDENT-OFF* */
683 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
684 /* *INDENT-ON* */
685