xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_IPv6.c (revision b23fa86ac476770d3224c07213bec32f5b1628bd)
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