1 /* 2 * FreeRTOS+TCP V2.3.1 3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy of 6 * this software and associated documentation files (the "Software"), to deal in 7 * the Software without restriction, including without limitation the rights to 8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 * the Software, and to permit persons to whom the Software is furnished to do so, 10 * subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in all 13 * copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * http://aws.amazon.com/freertos 23 * http://www.FreeRTOS.org 24 */ 25 26 /** 27 * @file FreeRTOS_ND.c 28 * @brief Implements a few functions that handle Neighbour Discovery and other ICMPv6 messages. 29 */ 30 31 /* Standard includes. */ 32 #include <stdint.h> 33 #include <stdio.h> 34 35 36 /* FreeRTOS includes. */ 37 #include "FreeRTOS.h" 38 #include "task.h" 39 40 /* FreeRTOS+TCP includes. */ 41 #include "FreeRTOS_IP.h" 42 #include "FreeRTOS_Sockets.h" 43 #include "FreeRTOS_IP_Private.h" 44 #include "FreeRTOS_ARP.h" 45 #include "FreeRTOS_UDP_IP.h" 46 #include "FreeRTOS_Routing.h" 47 #include "FreeRTOS_ND.h" 48 #include "FreeRTOS_IP_Timers.h" 49 50 #if ( ipconfigUSE_LLMNR == 1 ) 51 #include "FreeRTOS_DNS.h" 52 #endif /* ipconfigUSE_LLMNR */ 53 #include "NetworkBufferManagement.h" 54 55 /* The entire module FreeRTOS_ND.c is skipped when IPv6 is not used. */ 56 #if ( ipconfigUSE_IPv6 != 0 ) 57 58 /** @brief Type of Neighbour Advertisement packets - SOLICIT. */ 59 #define ndICMPv6_FLAG_SOLICITED 0x40000000U 60 /** @brief Type of Neighbour Advertisement packets - UPDATE. */ 61 #define ndICMPv6_FLAG_UPDATE 0x20000000U 62 63 /** @brief A block time of 0 simply means "don't block". */ 64 #define ndDONT_BLOCK ( ( TickType_t ) 0 ) 65 66 /** @brief The character used to fill ICMP echo requests, and therefore also the 67 * character expected to fill ICMP echo replies. 68 */ 69 #define ndECHO_DATA_FILL_BYTE 'x' 70 71 /** @brief When ucAge becomes 3 or less, it is time for a new 72 * neighbour solicitation. 73 */ 74 #define ndMAX_CACHE_AGE_BEFORE_NEW_ND_SOLICITATION ( 3U ) 75 76 /** @brief All nodes on the local network segment: IP address. */ 77 /* MISRA Ref 8.9.1 [File scoped variables] */ 78 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */ 79 /* coverity[misra_c_2012_rule_8_9_violation] */ 80 static const uint8_t pcLOCAL_ALL_NODES_MULTICAST_IP[ ipSIZE_OF_IPv6_ADDRESS ] = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; /* ff02:1 */ 81 /** @brief All nodes on the local network segment: MAC address. */ 82 static const uint8_t pcLOCAL_ALL_NODES_MULTICAST_MAC[ ipMAC_ADDRESS_LENGTH_BYTES ] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 }; 83 84 /** @brief See if the MAC-address can be resolved because it is a multi-cast address. */ 85 static eARPLookupResult_t prvMACResolve( const IPv6_Address_t * pxAddressToLookup, 86 MACAddress_t * const pxMACAddress, 87 NetworkEndPoint_t ** ppxEndPoint ); 88 89 /** @brief Lookup an MAC address in the ND cache from the IP address. */ 90 static eARPLookupResult_t prvNDCacheLookup( const IPv6_Address_t * pxAddressToLookup, 91 MACAddress_t * const pxMACAddress, 92 NetworkEndPoint_t ** ppxEndPoint ); 93 94 #if ( ipconfigHAS_PRINTF == 1 ) 95 static const char * pcMessageType( BaseType_t xType ); 96 #endif 97 98 /** @brief Find the first end-point of type IPv6. */ 99 static NetworkEndPoint_t * pxFindLocalEndpoint( void ); 100 101 /** @brief The ND cache. */ 102 static NDCacheRow_t xNDCache[ ipconfigND_CACHE_ENTRIES ]; 103 104 /*-----------------------------------------------------------*/ 105 106 /* 107 * ff02::1: All IPv6 devices 108 * ff02::2: All IPv6 routers 109 * ff02::5: All OSPFv3 routers 110 * ff02::a: All EIGRP (IPv6) routers 111 */ 112 113 /** 114 * @brief Find the first end-point of type IPv6. 115 * 116 * @return The first IPv6 end-point found. 117 */ pxFindLocalEndpoint(void)118 static NetworkEndPoint_t * pxFindLocalEndpoint( void ) 119 { 120 NetworkEndPoint_t * pxEndPoint; 121 122 for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL ); 123 pxEndPoint != NULL; 124 pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) ) 125 { 126 if( pxEndPoint->bits.bIPv6 == pdTRUE_UNSIGNED ) 127 { 128 IPv6_Type_t eType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) ); 129 130 if( eType == eIPv6_LinkLocal ) 131 { 132 break; 133 } 134 } 135 } 136 137 return pxEndPoint; 138 } 139 140 /** 141 * @brief See if the MAC-address can be resolved because it is a multi-cast address. 142 * 143 * @param[in] pxAddressToLookup The IP-address to look-up. 144 * @param[out] pxMACAddress The resulting MAC-address is stored here. 145 * @param[out] ppxEndPoint A pointer to an end-point pointer where the end-point will be stored. 146 * 147 * @return An enum, either eARPCacheHit or eARPCacheMiss. 148 */ prvMACResolve(const IPv6_Address_t * pxAddressToLookup,MACAddress_t * const pxMACAddress,NetworkEndPoint_t ** ppxEndPoint)149 static eARPLookupResult_t prvMACResolve( const IPv6_Address_t * pxAddressToLookup, 150 MACAddress_t * const pxMACAddress, 151 NetworkEndPoint_t ** ppxEndPoint ) 152 { 153 eARPLookupResult_t eReturn; 154 155 /* Mostly used multi-cast address is ff02::. */ 156 if( xIsIPv6AllowedMulticast( pxAddressToLookup ) != pdFALSE ) 157 { 158 vSetMultiCastIPv6MacAddress( pxAddressToLookup, pxMACAddress ); 159 160 if( ppxEndPoint != NULL ) 161 { 162 *ppxEndPoint = pxFindLocalEndpoint(); 163 } 164 165 eReturn = eARPCacheHit; 166 } 167 else 168 { 169 /* Not a multicast IP address. */ 170 eReturn = eARPCacheMiss; 171 } 172 173 return eReturn; 174 } 175 /*-----------------------------------------------------------*/ 176 177 /** 178 * @brief Find the MAC-address of an IPv6 address. It will first determine if is a multicast 179 * address, if not, it will check the ND cache. 180 * 181 * @param[in] pxIPAddress The IPv6 address to be looked up. 182 * @param[out] pxMACAddress The MAC-address found. 183 * @param[out] ppxEndPoint A pointer to a pointer to an end-point, where the end-point will be stored. 184 * 185 * @return An enum which says whether the address was found: eARPCacheHit or eARPCacheMiss. 186 */ eNDGetCacheEntry(IPv6_Address_t * pxIPAddress,MACAddress_t * const pxMACAddress,struct xNetworkEndPoint ** ppxEndPoint)187 eARPLookupResult_t eNDGetCacheEntry( IPv6_Address_t * pxIPAddress, 188 MACAddress_t * const pxMACAddress, 189 struct xNetworkEndPoint ** ppxEndPoint ) 190 { 191 eARPLookupResult_t eReturn; 192 NetworkEndPoint_t * pxEndPoint; 193 194 /* Multi-cast addresses can be resolved immediately. */ 195 eReturn = prvMACResolve( pxIPAddress, pxMACAddress, ppxEndPoint ); 196 197 if( eReturn == eARPCacheMiss ) 198 { 199 /* See if the IP-address has an entry in the cache. */ 200 eReturn = prvNDCacheLookup( pxIPAddress, pxMACAddress, ppxEndPoint ); 201 } 202 203 if( eReturn == eARPCacheMiss ) 204 { 205 FreeRTOS_printf( ( "eNDGetCacheEntry: lookup %pip miss\n", ( void * ) pxIPAddress->ucBytes ) ); 206 } 207 208 if( eReturn == eARPCacheMiss ) 209 { 210 IPv6_Type_t eIPType = xIPv6_GetIPType( pxIPAddress ); 211 212 pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv6( pxIPAddress ); 213 214 if( pxEndPoint != NULL ) 215 { 216 if( ppxEndPoint != NULL ) 217 { 218 *( ppxEndPoint ) = pxEndPoint; 219 } 220 221 FreeRTOS_printf( ( "eNDGetCacheEntry: FindEndPointOnIP failed for %pip (endpoint %pip)\n", 222 ( void * ) pxIPAddress->ucBytes, 223 ( void * ) pxEndPoint->ipv6_settings.xIPAddress.ucBytes ) ); 224 } 225 else 226 { 227 if( eIPType == eIPv6_LinkLocal ) 228 { 229 for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL ); 230 pxEndPoint != NULL; 231 pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) ) 232 { 233 IPv6_Type_t eMyType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) ); 234 235 if( eMyType == eIPType ) 236 { 237 eReturn = prvNDCacheLookup( pxIPAddress, pxMACAddress, ppxEndPoint ); 238 break; 239 } 240 } 241 242 FreeRTOS_printf( ( "eNDGetCacheEntry: LinkLocal %pip \"%s\"\n", ( void * ) pxIPAddress->ucBytes, 243 ( eReturn == eARPCacheHit ) ? "hit" : "miss" ) ); 244 } 245 else 246 { 247 pxEndPoint = FreeRTOS_FindGateWay( ( BaseType_t ) ipTYPE_IPv6 ); 248 249 if( pxEndPoint != NULL ) 250 { 251 ( void ) memcpy( pxIPAddress->ucBytes, pxEndPoint->ipv6_settings.xGatewayAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 252 FreeRTOS_printf( ( "eNDGetCacheEntry: Using gw %pip\n", ( void * ) pxIPAddress->ucBytes ) ); 253 FreeRTOS_printf( ( "eNDGetCacheEntry: From addr %pip\n", ( void * ) pxEndPoint->ipv6_settings.xIPAddress.ucBytes ) ); 254 255 /* See if the gateway has an entry in the cache. */ 256 eReturn = prvNDCacheLookup( pxIPAddress, pxMACAddress, ppxEndPoint ); 257 258 if( *ppxEndPoint != NULL ) 259 { 260 FreeRTOS_printf( ( "eNDGetCacheEntry: found end-point %pip\n", ( void * ) ( *ppxEndPoint )->ipv6_settings.xIPAddress.ucBytes ) ); 261 } 262 263 *( ppxEndPoint ) = pxEndPoint; 264 } 265 } 266 } 267 } 268 269 return eReturn; 270 } 271 /*-----------------------------------------------------------*/ 272 273 /** 274 * @brief Store a combination of IP-address, MAC-address and an end-point in a free location 275 * in the ND cache. 276 * 277 * @param[in] pxMACAddress The MAC-address 278 * @param[in] pxIPAddress The IP-address 279 * @param[in] pxEndPoint The end-point through which the IP-address can be reached. 280 * 281 */ vNDRefreshCacheEntry(const MACAddress_t * pxMACAddress,const IPv6_Address_t * pxIPAddress,NetworkEndPoint_t * pxEndPoint)282 void vNDRefreshCacheEntry( const MACAddress_t * pxMACAddress, 283 const IPv6_Address_t * pxIPAddress, 284 NetworkEndPoint_t * pxEndPoint ) 285 { 286 BaseType_t x; 287 BaseType_t xFreeEntry = -1, xEntryFound = -1; 288 289 /* For each entry in the ND cache table. */ 290 for( x = 0; x < ipconfigND_CACHE_ENTRIES; x++ ) 291 { 292 if( xNDCache[ x ].ucValid == ( uint8_t ) pdFALSE ) 293 { 294 if( xFreeEntry == -1 ) 295 { 296 xFreeEntry = x; 297 } 298 } 299 else if( memcmp( xNDCache[ x ].xIPAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 ) 300 { 301 xEntryFound = x; 302 break; 303 } 304 else 305 { 306 /* Entry is valid but the IP-address doesn't match. */ 307 } 308 } 309 310 if( xEntryFound < 0 ) 311 { 312 /* The IP-address was not found, use the first free location. */ 313 xEntryFound = xFreeEntry; 314 } 315 316 if( xEntryFound >= 0 ) 317 { 318 /* Copy the IP-address. */ 319 ( void ) memcpy( xNDCache[ xEntryFound ].xIPAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 320 /* Copy the MAC-address. */ 321 ( void ) memcpy( xNDCache[ xEntryFound ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( MACAddress_t ) ); 322 xNDCache[ xEntryFound ].pxEndPoint = pxEndPoint; 323 xNDCache[ xEntryFound ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE; 324 xNDCache[ xEntryFound ].ucValid = ( uint8_t ) pdTRUE; 325 } 326 else 327 { 328 FreeRTOS_printf( ( "vNDRefreshCacheEntry: %pip not found\n", ( void * ) pxIPAddress->ucBytes ) ); 329 } 330 } 331 /*-----------------------------------------------------------*/ 332 333 /** 334 * @brief Reduce the age counter in each entry within the ND cache. An entry is no 335 * longer considered valid and is deleted if its age reaches zero. 336 * Just before getting to zero, 3 times a neighbour solicitation will be sent. 337 */ vNDAgeCache(void)338 void vNDAgeCache( void ) 339 { 340 BaseType_t x; 341 342 /* Loop through each entry in the ND cache. */ 343 for( x = 0; x < ipconfigND_CACHE_ENTRIES; x++ ) 344 { 345 BaseType_t xDoSolicitate = pdFALSE; 346 347 /* If the entry is valid (its age is greater than zero). */ 348 if( xNDCache[ x ].ucAge > 0U ) 349 { 350 /* Decrement the age value of the entry in this ND cache table row. 351 * When the age reaches zero it is no longer considered valid. */ 352 ( xNDCache[ x ].ucAge )--; 353 354 if( xNDCache[ x ].ucAge == 0U ) 355 { 356 /* The entry is no longer valid. Wipe it out. */ 357 iptraceND_TABLE_ENTRY_EXPIRED( xNDCache[ x ].xIPAddress ); 358 ( void ) memset( &( xNDCache[ x ] ), 0, sizeof( xNDCache[ x ] ) ); 359 } 360 else 361 { 362 /* If the entry is not yet valid, then it is waiting an ND 363 * advertisement, and the ND solicitation should be retransmitted. */ 364 if( xNDCache[ x ].ucValid == ( uint8_t ) pdFALSE ) 365 { 366 xDoSolicitate = pdTRUE; 367 } 368 else if( xNDCache[ x ].ucAge <= ( uint8_t ) ndMAX_CACHE_AGE_BEFORE_NEW_ND_SOLICITATION ) 369 { 370 /* This entry will get removed soon. See if the MAC address is 371 * still valid to prevent this happening. */ 372 iptraceND_TABLE_ENTRY_WILL_EXPIRE( xNDCache[ x ].xIPAddress ); 373 xDoSolicitate = pdTRUE; 374 } 375 else 376 { 377 /* The age has just ticked down, with nothing to do. */ 378 } 379 380 if( xDoSolicitate != pdFALSE ) 381 { 382 size_t uxNeededSize; 383 NetworkBufferDescriptor_t * pxNetworkBuffer; 384 385 uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPHeader_IPv6_t ); 386 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxNeededSize, 0U ); 387 388 if( pxNetworkBuffer != NULL ) 389 { 390 pxNetworkBuffer->pxEndPoint = xNDCache[ x ].pxEndPoint; 391 /* _HT_ From here I am suspecting a network buffer leak */ 392 vNDSendNeighbourSolicitation( pxNetworkBuffer, &( xNDCache[ x ].xIPAddress ) ); 393 } 394 } 395 } 396 } 397 } 398 } 399 /*-----------------------------------------------------------*/ 400 401 /** 402 * @brief Clear the Neighbour Discovery cache. 403 */ FreeRTOS_ClearND(void)404 void FreeRTOS_ClearND( void ) 405 { 406 ( void ) memset( xNDCache, 0, sizeof( xNDCache ) ); 407 } 408 /*-----------------------------------------------------------*/ 409 410 /** 411 * @brief Look-up an IPv6 address in the cache. 412 * 413 * @param[in] pxAddressToLookup The IPv6 address to look-up.Ethernet packet. 414 * @param[out] pxMACAddress The resulting MAC-address will be stored here. 415 * @param[out] ppxEndPoint A pointer to a pointer to an end-point, where the end-point will be stored. 416 * 417 * @return An enum: either eARPCacheHit or eARPCacheMiss. 418 */ prvNDCacheLookup(const IPv6_Address_t * pxAddressToLookup,MACAddress_t * const pxMACAddress,NetworkEndPoint_t ** ppxEndPoint)419 static eARPLookupResult_t prvNDCacheLookup( const IPv6_Address_t * pxAddressToLookup, 420 MACAddress_t * const pxMACAddress, 421 NetworkEndPoint_t ** ppxEndPoint ) 422 { 423 BaseType_t x; 424 eARPLookupResult_t eReturn = eARPCacheMiss; 425 426 /* For each entry in the ND cache table. */ 427 for( x = 0; x < ipconfigND_CACHE_ENTRIES; x++ ) 428 { 429 if( xNDCache[ x ].ucValid == ( uint8_t ) pdFALSE ) 430 { 431 /* Skip invalid entries. */ 432 } 433 else if( memcmp( xNDCache[ x ].xIPAddress.ucBytes, pxAddressToLookup->ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 ) 434 { 435 ( void ) memcpy( pxMACAddress->ucBytes, xNDCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ); 436 eReturn = eARPCacheHit; 437 438 if( ppxEndPoint != NULL ) 439 { 440 *ppxEndPoint = xNDCache[ x ].pxEndPoint; 441 } 442 443 FreeRTOS_debug_printf( ( "prvCacheLookup6[ %d ] %pip with %02x:%02x:%02x:%02x:%02x:%02x\n", 444 ( int ) x, 445 ( void * ) pxAddressToLookup->ucBytes, 446 pxMACAddress->ucBytes[ 0 ], 447 pxMACAddress->ucBytes[ 1 ], 448 pxMACAddress->ucBytes[ 2 ], 449 pxMACAddress->ucBytes[ 3 ], 450 pxMACAddress->ucBytes[ 4 ], 451 pxMACAddress->ucBytes[ 5 ] ) ); 452 break; 453 } 454 else 455 { 456 /* Entry is valid but the MAC-address doesn't match. */ 457 } 458 } 459 460 if( eReturn == eARPCacheMiss ) 461 { 462 FreeRTOS_printf( ( "prvNDCacheLookup %pip Miss\n", ( void * ) pxAddressToLookup->ucBytes ) ); 463 464 if( ppxEndPoint != NULL ) 465 { 466 *ppxEndPoint = NULL; 467 } 468 } 469 470 return eReturn; 471 } 472 /*-----------------------------------------------------------*/ 473 474 #if ( ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) ) 475 476 /** 477 * @brief Print the contents of the ND cache, for debugging only. 478 */ FreeRTOS_PrintNDCache(void)479 void FreeRTOS_PrintNDCache( void ) 480 { 481 BaseType_t x, xCount = 0; 482 char pcBuffer[ 40 ]; 483 484 /* Loop through each entry in the ND cache. */ 485 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) 486 { 487 if( xNDCache[ x ].ucValid != ( uint8_t ) 0U ) 488 { 489 /* See if the MAC-address also matches, and we're all happy */ 490 491 FreeRTOS_printf( ( "ND %2d: age %3u - %pip MAC %02x-%02x-%02x-%02x-%02x-%02x endPoint %s\n", 492 ( int ) x, 493 xNDCache[ x ].ucAge, 494 ( void * ) xNDCache[ x ].xIPAddress.ucBytes, 495 xNDCache[ x ].xMACAddress.ucBytes[ 0 ], 496 xNDCache[ x ].xMACAddress.ucBytes[ 1 ], 497 xNDCache[ x ].xMACAddress.ucBytes[ 2 ], 498 xNDCache[ x ].xMACAddress.ucBytes[ 3 ], 499 xNDCache[ x ].xMACAddress.ucBytes[ 4 ], 500 xNDCache[ x ].xMACAddress.ucBytes[ 5 ], 501 pcEndpointName( xNDCache[ x ].pxEndPoint, pcBuffer, sizeof( pcBuffer ) ) ) ); 502 xCount++; 503 } 504 } 505 506 FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) ); 507 } 508 509 #endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ 510 /*-----------------------------------------------------------*/ 511 512 /** 513 * @brief Return an ICMPv6 packet to the peer. 514 * 515 * @param[in] pxNetworkBuffer The Ethernet packet. 516 * @param[in] uxICMPSize The number of bytes to be sent. 517 */ prvReturnICMP_IPv6(NetworkBufferDescriptor_t * const pxNetworkBuffer,size_t uxICMPSize)518 static void prvReturnICMP_IPv6( NetworkBufferDescriptor_t * const pxNetworkBuffer, 519 size_t uxICMPSize ) 520 { 521 const NetworkEndPoint_t * pxEndPoint = pxNetworkBuffer->pxEndPoint; 522 523 /* MISRA Ref 11.3.1 [Misaligned access] */ 524 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 525 /* coverity[misra_c_2012_rule_11_3_violation] */ 526 ICMPPacket_IPv6_t * pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 527 528 ( void ) memcpy( pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 529 ( void ) memcpy( pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 530 pxICMPPacket->xIPHeader.usPayloadLength = FreeRTOS_htons( uxICMPSize ); 531 532 /* Important: tell NIC driver how many bytes must be sent */ 533 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); 534 535 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) 536 { 537 /* calculate the ICMPv6 checksum for outgoing package */ 538 ( void ) usGenerateProtocolChecksum( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, pdTRUE ); 539 } 540 #else 541 { 542 /* Many EMAC peripherals will only calculate the ICMP checksum 543 * correctly if the field is nulled beforehand. */ 544 pxICMPPacket->xICMPHeaderIPv6.usChecksum = 0; 545 } 546 #endif 547 548 /* This function will fill in the Ethernet addresses and send the packet */ 549 vReturnEthernetFrame( pxNetworkBuffer, pdFALSE ); 550 } 551 /*-----------------------------------------------------------*/ 552 553 /** 554 * @brief Send out an ND request for the IPv6 address contained in pxNetworkBuffer, and 555 * add an entry into the ND table that indicates that an ND reply is outstanding 556 * so re-transmissions can be generated. 557 * 558 * @param[in] pxNetworkBuffer The network buffer in which the message shall be stored. 559 * @param[in] pxIPAddress The IPv6 address that is asked to send a Neighbour Advertisement. 560 * 561 * @note Send out an ND request for the IPv6 address contained in pxNetworkBuffer, and 562 * add an entry into the ND table that indicates that an ND reply is 563 * outstanding so re-transmissions can be generated. 564 */ 565 vNDSendNeighbourSolicitation(NetworkBufferDescriptor_t * pxNetworkBuffer,const IPv6_Address_t * pxIPAddress)566 void vNDSendNeighbourSolicitation( NetworkBufferDescriptor_t * pxNetworkBuffer, 567 const IPv6_Address_t * pxIPAddress ) 568 { 569 ICMPPacket_IPv6_t * pxICMPPacket; 570 ICMPHeader_IPv6_t * pxICMPHeader_IPv6; 571 const NetworkEndPoint_t * pxEndPoint = pxNetworkBuffer->pxEndPoint; 572 size_t uxNeededSize; 573 IPv6_Address_t xTargetIPAddress; 574 MACAddress_t xMultiCastMacAddress; 575 NetworkBufferDescriptor_t * pxDescriptor = pxNetworkBuffer; 576 NetworkBufferDescriptor_t * pxNewDescriptor = NULL; 577 578 if( ( pxEndPoint != NULL ) && ( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) ) 579 { 580 uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPHeader_IPv6_t ); 581 582 if( pxDescriptor->xDataLength < uxNeededSize ) 583 { 584 pxNewDescriptor = pxDuplicateNetworkBufferWithDescriptor( pxDescriptor, uxNeededSize ); 585 vReleaseNetworkBufferAndDescriptor( pxDescriptor ); 586 pxDescriptor = pxNewDescriptor; 587 } 588 589 if( pxDescriptor != NULL ) 590 { 591 const uint32_t ulPayloadLength = 32U; 592 593 /* MISRA Ref 11.3.1 [Misaligned access] */ 594 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 595 /* coverity[misra_c_2012_rule_11_3_violation] */ 596 pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxDescriptor->pucEthernetBuffer ); 597 pxICMPHeader_IPv6 = ( ( ICMPHeader_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); 598 599 pxDescriptor->xDataLength = uxNeededSize; 600 601 /* Set the multi-cast MAC-address. */ 602 xMultiCastMacAddress.ucBytes[ 0 ] = 0x33U; 603 xMultiCastMacAddress.ucBytes[ 1 ] = 0x33U; 604 xMultiCastMacAddress.ucBytes[ 2 ] = 0xffU; 605 xMultiCastMacAddress.ucBytes[ 3 ] = pxIPAddress->ucBytes[ 13 ]; 606 xMultiCastMacAddress.ucBytes[ 4 ] = pxIPAddress->ucBytes[ 14 ]; 607 xMultiCastMacAddress.ucBytes[ 5 ] = pxIPAddress->ucBytes[ 15 ]; 608 609 /* Set Ethernet header. Source and Destination will be swapped. */ 610 ( void ) memcpy( pxICMPPacket->xEthernetHeader.xSourceAddress.ucBytes, xMultiCastMacAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); 611 ( void ) memcpy( pxICMPPacket->xEthernetHeader.xDestinationAddress.ucBytes, pxEndPoint->xMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); 612 pxICMPPacket->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE; 613 614 /* Set IP-header. */ 615 pxICMPPacket->xIPHeader.ucVersionTrafficClass = 0x60U; 616 pxICMPPacket->xIPHeader.ucTrafficClassFlow = 0U; 617 pxICMPPacket->xIPHeader.usFlowLabel = 0U; 618 pxICMPPacket->xIPHeader.usPayloadLength = FreeRTOS_htons( ulPayloadLength ); 619 pxICMPPacket->xIPHeader.ucNextHeader = ipPROTOCOL_ICMP_IPv6; 620 pxICMPPacket->xIPHeader.ucHopLimit = 255U; 621 622 /* Source address */ 623 ( void ) memcpy( pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 624 625 /*ff02::1:ff5a:afe7 */ 626 ( void ) memset( xTargetIPAddress.ucBytes, 0, sizeof( xTargetIPAddress.ucBytes ) ); 627 xTargetIPAddress.ucBytes[ 0 ] = 0xff; 628 xTargetIPAddress.ucBytes[ 1 ] = 0x02; 629 xTargetIPAddress.ucBytes[ 11 ] = 0x01; 630 xTargetIPAddress.ucBytes[ 12 ] = 0xff; 631 xTargetIPAddress.ucBytes[ 13 ] = pxIPAddress->ucBytes[ 13 ]; 632 xTargetIPAddress.ucBytes[ 14 ] = pxIPAddress->ucBytes[ 14 ]; 633 xTargetIPAddress.ucBytes[ 15 ] = pxIPAddress->ucBytes[ 15 ]; 634 ( void ) memcpy( pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, xTargetIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 635 636 /* Set ICMP header. */ 637 ( void ) memset( pxICMPHeader_IPv6, 0, sizeof( *pxICMPHeader_IPv6 ) ); 638 pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_NEIGHBOR_SOLICITATION_IPv6; 639 ( void ) memcpy( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 640 pxICMPHeader_IPv6->ucOptionType = ndICMP_SOURCE_LINK_LAYER_ADDRESS; 641 pxICMPHeader_IPv6->ucOptionLength = 1U; /* times 8 bytes. */ 642 ( void ) memcpy( pxICMPHeader_IPv6->ucOptionBytes, pxEndPoint->xMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); 643 644 /* Checksums. */ 645 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) 646 { 647 /* calculate the ICMPv6 checksum for outgoing package */ 648 ( void ) usGenerateProtocolChecksum( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, pdTRUE ); 649 } 650 #else 651 { 652 /* Many EMAC peripherals will only calculate the ICMP checksum 653 * correctly if the field is nulled beforehand. */ 654 pxICMPHeader_IPv6->usChecksum = 0U; 655 } 656 #endif 657 658 /* This function will fill in the eth addresses and send the packet */ 659 vReturnEthernetFrame( pxDescriptor, pdTRUE ); 660 } 661 } 662 } 663 /*-----------------------------------------------------------*/ 664 665 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) 666 667 /** 668 * @brief Send a PING request using an ICMPv6 format. 669 * 670 * @param[in] pxIPAddress Send an IPv6 PING request. 671 * @param[in] uxNumberOfBytesToSend The number of bytes to be sent. 672 * @param[in] uxBlockTimeTicks The maximum number of clock-ticks to wait while 673 * putting the message on the queue for the IP-task. 674 * 675 * @return When failed: pdFAIL, otherwise the PING sequence number. 676 */ FreeRTOS_SendPingRequestIPv6(const IPv6_Address_t * pxIPAddress,size_t uxNumberOfBytesToSend,TickType_t uxBlockTimeTicks)677 BaseType_t FreeRTOS_SendPingRequestIPv6( const IPv6_Address_t * pxIPAddress, 678 size_t uxNumberOfBytesToSend, 679 TickType_t uxBlockTimeTicks ) 680 { 681 NetworkBufferDescriptor_t * pxNetworkBuffer = NULL; 682 EthernetHeader_t * pxEthernetHeader; 683 ICMPPacket_IPv6_t * pxICMPPacket; 684 ICMPEcho_IPv6_t * pxICMPHeader; 685 BaseType_t xReturn = pdFAIL; 686 static uint16_t usSequenceNumber = 0; 687 uint8_t * pucChar; 688 IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL }; 689 NetworkEndPoint_t * pxEndPoint = NULL; 690 size_t uxPacketLength = 0U; 691 BaseType_t xEnoughSpace; 692 693 pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv6( pxIPAddress ); 694 695 /* MISRA Ref 14.3.1 [Configuration dependent invariant] */ 696 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-143 */ 697 /* coverity[misra_c_2012_rule_14_3_violation] */ 698 /* coverity[notnull] */ 699 if( pxEndPoint == NULL ) 700 { 701 BaseType_t xWanted = ( xIPv6_GetIPType( pxIPAddress ) == eIPv6_Global ) ? 1 : 0; 702 703 for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL ); 704 pxEndPoint != NULL; 705 pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) ) 706 { 707 if( pxEndPoint->bits.bIPv6 != 0U ) 708 { 709 BaseType_t xGot = ( xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) ) == eIPv6_Global ) ? 1 : 0; 710 711 if( xWanted == xGot ) 712 { 713 break; 714 } 715 } 716 } 717 } 718 719 if( uxNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_IPv6_t ) ) - sizeof( ICMPEcho_IPv6_t ) ) ) 720 { 721 xEnoughSpace = pdTRUE; 722 } 723 else 724 { 725 xEnoughSpace = pdFALSE; 726 } 727 728 if( pxEndPoint == NULL ) 729 { 730 /* No endpoint found for the target IP-address. */ 731 FreeRTOS_printf( ( "SendPingRequestIPv6: no end-point found for %pip\n", 732 ( void * ) pxIPAddress->ucBytes ) ); 733 } 734 else if( ( uxGetNumberOfFreeNetworkBuffers() >= 3U ) && ( uxNumberOfBytesToSend >= 1U ) && ( xEnoughSpace != pdFALSE ) ) 735 { 736 uxPacketLength = sizeof( EthernetHeader_t ) + sizeof( IPHeader_IPv6_t ) + sizeof( ICMPEcho_IPv6_t ) + uxNumberOfBytesToSend; 737 738 /* MISRA Ref 11.3.1 [Misaligned access] */ 739 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 740 /* coverity[misra_c_2012_rule_11_3_violation] */ 741 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( BUFFER_FROM_WHERE_CALL( 181 ) uxPacketLength, uxBlockTimeTicks ); 742 743 if( pxNetworkBuffer != NULL ) 744 { 745 /* Probably not necessary to clear the buffer. */ 746 ( void ) memset( pxNetworkBuffer->pucEthernetBuffer, 0, pxNetworkBuffer->xDataLength ); 747 748 pxNetworkBuffer->pxEndPoint = pxEndPoint; 749 pxNetworkBuffer->pxInterface = pxEndPoint->pxNetworkInterface; 750 751 /* MISRA Ref 11.3.1 [Misaligned access] */ 752 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 753 /* coverity[misra_c_2012_rule_11_3_violation] */ 754 pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 755 756 pxICMPHeader = ( ( ICMPEcho_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); 757 usSequenceNumber++; 758 759 pxICMPPacket->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE; 760 761 pxICMPPacket->xIPHeader.usPayloadLength = FreeRTOS_htons( sizeof( ICMPEcho_IPv6_t ) + uxNumberOfBytesToSend ); 762 ( void ) memcpy( pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 763 ( void ) memcpy( pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 764 FreeRTOS_printf( ( "ICMP send from %pip\n", ( void * ) pxICMPPacket->xIPHeader.xSourceAddress.ucBytes ) ); 765 766 /* Fill in the basic header information. */ 767 pxICMPHeader->ucTypeOfMessage = ipICMP_PING_REQUEST_IPv6; 768 pxICMPHeader->ucTypeOfService = 0; 769 pxICMPHeader->usIdentifier = FreeRTOS_htons( usSequenceNumber ); 770 pxICMPHeader->usSequenceNumber = FreeRTOS_htons( usSequenceNumber ); 771 772 /* Find the start of the data. */ 773 pucChar = ( uint8_t * ) pxICMPHeader; 774 pucChar = &( pucChar[ sizeof( ICMPEcho_IPv6_t ) ] ); 775 776 /* Just memset the data to a fixed value. */ 777 ( void ) memset( pucChar, ( int32_t ) ndECHO_DATA_FILL_BYTE, uxNumberOfBytesToSend ); 778 779 /* The message is complete, IP and checksum's are handled by 780 * vProcessGeneratedUDPPacket */ 781 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT; 782 ( void ) memset( pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS ); 783 ( void ) memcpy( pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 784 /* Let vProcessGeneratedUDPPacket() know that this is an ICMP packet. */ 785 pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA; 786 /* 'uxPacketLength' is initialised due to the flow of the program. */ 787 pxNetworkBuffer->xDataLength = uxPacketLength; 788 789 /* MISRA Ref 11.3.1 [Misaligned access] */ 790 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 791 /* coverity[misra_c_2012_rule_11_3_violation] */ 792 pxEthernetHeader = ( ( EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer ); 793 pxEthernetHeader->usFrameType = ipIPv6_FRAME_TYPE; 794 795 /* Send to the stack. */ 796 xStackTxEvent.pvData = pxNetworkBuffer; 797 798 if( xSendEventStructToIPTask( &xStackTxEvent, uxBlockTimeTicks ) != pdPASS ) 799 { 800 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); 801 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT ); 802 } 803 else 804 { 805 xReturn = ( BaseType_t ) usSequenceNumber; 806 } 807 } 808 } 809 else 810 { 811 /* Either no proper end-pint found, or allocating the network buffer failed. */ 812 } 813 814 return xReturn; 815 } 816 817 #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */ 818 /*-----------------------------------------------------------*/ 819 820 821 #if ( ipconfigHAS_PRINTF == 1 ) 822 823 /** 824 * @brief Returns a printable string for the major ICMPv6 message types. Used for 825 * debugging only. 826 * 827 * @param[in] xType The type of message. 828 * 829 * @return A null-terminated string that represents the type the kind of message. 830 */ pcMessageType(BaseType_t xType)831 static const char * pcMessageType( BaseType_t xType ) 832 { 833 const char * pcReturn; 834 835 switch( ( uint8_t ) xType ) 836 { 837 case ipICMP_DEST_UNREACHABLE_IPv6: 838 pcReturn = "DEST_UNREACHABLE"; 839 break; 840 841 case ipICMP_PACKET_TOO_BIG_IPv6: 842 pcReturn = "PACKET_TOO_BIG"; 843 break; 844 845 case ipICMP_TIME_EXEEDED_IPv6: 846 pcReturn = "TIME_EXEEDED"; 847 break; 848 849 case ipICMP_PARAMETER_PROBLEM_IPv6: 850 pcReturn = "PARAMETER_PROBLEM"; 851 break; 852 853 case ipICMP_PING_REQUEST_IPv6: 854 pcReturn = "PING_REQUEST"; 855 break; 856 857 case ipICMP_PING_REPLY_IPv6: 858 pcReturn = "PING_REPLY"; 859 break; 860 861 case ipICMP_ROUTER_SOLICITATION_IPv6: 862 pcReturn = "ROUTER_SOL"; 863 break; 864 865 case ipICMP_ROUTER_ADVERTISEMENT_IPv6: 866 pcReturn = "ROUTER_ADV"; 867 break; 868 869 case ipICMP_NEIGHBOR_SOLICITATION_IPv6: 870 pcReturn = "NEIGHBOR_SOL"; 871 break; 872 873 case ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6: 874 pcReturn = "NEIGHBOR_ADV"; 875 break; 876 877 default: 878 pcReturn = "UNKNOWN ICMP"; 879 break; 880 } 881 882 return pcReturn; 883 } 884 #endif /* ( ipconfigHAS_PRINTF == 1 ) */ 885 /*-----------------------------------------------------------*/ 886 887 /** 888 * @brief When a neighbour advertisement has been received, check if 'pxARPWaitingNetworkBuffer' 889 * was waiting for this new address look-up. If so, feed it to the IP-task as a new 890 * incoming packet. 891 */ prvCheckWaitingBuffer(const IPv6_Address_t * pxIPv6Address)892 static void prvCheckWaitingBuffer( const IPv6_Address_t * pxIPv6Address ) 893 { 894 /* MISRA Ref 11.3.1 [Misaligned access] */ 895 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 896 /* coverity[misra_c_2012_rule_11_3_violation] */ 897 const IPPacket_IPv6_t * pxIPPacket = ( ( IPPacket_IPv6_t * ) pxARPWaitingNetworkBuffer->pucEthernetBuffer ); 898 const IPHeader_IPv6_t * pxIPHeader = &( pxIPPacket->xIPHeader ); 899 900 if( memcmp( pxIPv6Address->ucBytes, pxIPHeader->xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 ) 901 { 902 FreeRTOS_printf( ( "Waiting done\n" ) ); 903 IPStackEvent_t xEventMessage; 904 const TickType_t xDontBlock = ( TickType_t ) 0; 905 906 xEventMessage.eEventType = eNetworkRxEvent; 907 xEventMessage.pvData = ( void * ) pxARPWaitingNetworkBuffer; 908 909 if( xSendEventStructToIPTask( &xEventMessage, xDontBlock ) != pdPASS ) 910 { 911 /* Failed to send the message, so release the network buffer. */ 912 vReleaseNetworkBufferAndDescriptor( BUFFER_FROM_WHERE_CALL( 140 ) pxARPWaitingNetworkBuffer ); 913 } 914 915 /* Clear the buffer. */ 916 pxARPWaitingNetworkBuffer = NULL; 917 918 /* Found an ARP resolution, disable ARP resolution timer. */ 919 vIPSetARPResolutionTimerEnableState( pdFALSE ); 920 921 iptrace_DELAYED_ARP_REQUEST_REPLIED(); 922 } 923 } 924 /*-----------------------------------------------------------*/ 925 926 /** 927 * @brief Process an ICMPv6 packet and send replies when applicable. 928 * 929 * @param[in] pxNetworkBuffer The Ethernet packet which contains an IPv6 message. 930 * 931 * @return A const value 'eReleaseBuffer' which means that the network must still be released. 932 */ prvProcessICMPMessage_IPv6(NetworkBufferDescriptor_t * const pxNetworkBuffer)933 eFrameProcessingResult_t prvProcessICMPMessage_IPv6( NetworkBufferDescriptor_t * const pxNetworkBuffer ) 934 { 935 /* MISRA Ref 11.3.1 [Misaligned access] */ 936 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 937 /* coverity[misra_c_2012_rule_11_3_violation] */ 938 ICMPPacket_IPv6_t * pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 939 /* coverity[misra_c_2012_rule_11_3_violation] */ 940 ICMPHeader_IPv6_t * pxICMPHeader_IPv6 = ( ( ICMPHeader_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); 941 NetworkEndPoint_t * pxEndPoint = pxNetworkBuffer->pxEndPoint; 942 size_t uxNeededSize; 943 944 #if ( ipconfigHAS_PRINTF == 1 ) 945 { 946 if( pxICMPHeader_IPv6->ucTypeOfMessage != ipICMP_PING_REQUEST_IPv6 ) 947 { 948 char pcAddress[ 40 ]; 949 FreeRTOS_printf( ( "ICMPv6_recv %d (%s) from %pip to %pip end-point = %s\n", 950 pxICMPHeader_IPv6->ucTypeOfMessage, 951 pcMessageType( ( BaseType_t ) pxICMPHeader_IPv6->ucTypeOfMessage ), 952 ( void * ) pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, 953 ( void * ) pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, 954 pcEndpointName( pxEndPoint, pcAddress, sizeof( pcAddress ) ) ) ); 955 } 956 } 957 #endif /* ( ipconfigHAS_PRINTF == 1 ) */ 958 959 if( ( pxEndPoint != NULL ) && ( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ) ) 960 { 961 switch( pxICMPHeader_IPv6->ucTypeOfMessage ) 962 { 963 case ipICMP_DEST_UNREACHABLE_IPv6: 964 case ipICMP_PACKET_TOO_BIG_IPv6: 965 case ipICMP_TIME_EXEEDED_IPv6: 966 case ipICMP_PARAMETER_PROBLEM_IPv6: 967 /* These message types are not implemented. They are logged here above. */ 968 break; 969 970 case ipICMP_PING_REQUEST_IPv6: 971 { 972 size_t uxICMPSize; 973 uint16_t usICMPSize; 974 975 /* Lint would complain about casting '()' immediately. */ 976 usICMPSize = FreeRTOS_ntohs( pxICMPPacket->xIPHeader.usPayloadLength ); 977 uxICMPSize = ( size_t ) usICMPSize; 978 uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); 979 980 if( uxNeededSize > pxNetworkBuffer->xDataLength ) 981 { 982 FreeRTOS_printf( ( "Too small\n" ) ); 983 break; 984 } 985 986 pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_PING_REPLY_IPv6; 987 prvReturnICMP_IPv6( pxNetworkBuffer, uxICMPSize ); 988 } 989 break; 990 991 #if ( ipconfigSUPPORT_OUTGOING_PINGS != 0 ) 992 case ipICMP_PING_REPLY_IPv6: 993 { 994 ePingReplyStatus_t eStatus = eSuccess; 995 /* MISRA Ref 11.3.1 [Misaligned access] */ 996 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 997 /* coverity[misra_c_2012_rule_11_3_violation] */ 998 const ICMPEcho_IPv6_t * pxICMPEchoHeader = ( ( const ICMPEcho_IPv6_t * ) pxICMPHeader_IPv6 ); 999 size_t uxDataLength, uxCount; 1000 const uint8_t * pucByte; 1001 1002 /* Find the total length of the IP packet. */ 1003 uxDataLength = ipNUMERIC_CAST( size_t, FreeRTOS_ntohs( pxICMPPacket->xIPHeader.usPayloadLength ) ); 1004 uxDataLength = uxDataLength - sizeof( *pxICMPEchoHeader ); 1005 1006 /* Find the first byte of the data within the ICMP packet. */ 1007 pucByte = ( const uint8_t * ) pxICMPEchoHeader; 1008 pucByte = &( pucByte[ sizeof( *pxICMPEchoHeader ) ] ); 1009 1010 /* Check each byte. */ 1011 for( uxCount = 0; uxCount < uxDataLength; uxCount++ ) 1012 { 1013 if( *pucByte != ( uint8_t ) ipECHO_DATA_FILL_BYTE ) 1014 { 1015 eStatus = eInvalidData; 1016 break; 1017 } 1018 1019 pucByte++; 1020 } 1021 1022 /* Call back into the application to pass it the result. */ 1023 vApplicationPingReplyHook( eStatus, pxICMPEchoHeader->usIdentifier ); 1024 } 1025 break; 1026 #endif /* ( ipconfigSUPPORT_OUTGOING_PINGS != 0 ) */ 1027 case ipICMP_NEIGHBOR_SOLICITATION_IPv6: 1028 { 1029 size_t uxICMPSize; 1030 BaseType_t xCompare; 1031 NetworkEndPoint_t * pxEndPointFound = FreeRTOS_FindEndPointOnIP_IPv6( &( pxICMPHeader_IPv6->xIPv6Address ) ); 1032 char pcName[ 40 ]; 1033 ( void ) memset( &( pcName ), 0, sizeof( pcName ) ); 1034 FreeRTOS_printf( ( "Lookup %pip : endpoint %s\n", 1035 ( void * ) pxICMPHeader_IPv6->xIPv6Address.ucBytes, 1036 pcEndpointName( pxEndPointFound, pcName, sizeof( pcName ) ) ) ); 1037 1038 if( pxEndPointFound != NULL ) 1039 { 1040 pxEndPoint = pxEndPointFound; 1041 } 1042 1043 pxNetworkBuffer->pxEndPoint = pxEndPoint; 1044 pxNetworkBuffer->pxInterface = pxEndPoint->pxNetworkInterface; 1045 1046 uxICMPSize = sizeof( ICMPHeader_IPv6_t ); 1047 uxNeededSize = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); 1048 1049 if( uxNeededSize > pxNetworkBuffer->xDataLength ) 1050 { 1051 FreeRTOS_printf( ( "Too small\n" ) ); 1052 break; 1053 } 1054 1055 xCompare = memcmp( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 1056 1057 FreeRTOS_printf( ( "ND NS for %pip endpoint %pip %s\n", 1058 ( void * ) pxICMPHeader_IPv6->xIPv6Address.ucBytes, 1059 ( void * ) pxEndPoint->ipv6_settings.xIPAddress.ucBytes, 1060 ( xCompare == 0 ) ? "Reply" : "Ignore" ) ); 1061 1062 if( xCompare == 0 ) 1063 { 1064 pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; 1065 pxICMPHeader_IPv6->ucTypeOfService = 0U; 1066 pxICMPHeader_IPv6->ulReserved = ndICMPv6_FLAG_SOLICITED | ndICMPv6_FLAG_UPDATE; 1067 pxICMPHeader_IPv6->ulReserved = FreeRTOS_htonl( pxICMPHeader_IPv6->ulReserved ); 1068 1069 /* Type of option. */ 1070 pxICMPHeader_IPv6->ucOptionType = ndICMP_TARGET_LINK_LAYER_ADDRESS; 1071 /* Length of option in units of 8 bytes. */ 1072 pxICMPHeader_IPv6->ucOptionLength = 1U; 1073 ( void ) memcpy( pxICMPHeader_IPv6->ucOptionBytes, pxEndPoint->xMACAddress.ucBytes, sizeof( MACAddress_t ) ); 1074 pxICMPPacket->xIPHeader.ucHopLimit = 255U; 1075 ( void ) memcpy( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); 1076 prvReturnICMP_IPv6( pxNetworkBuffer, uxICMPSize ); 1077 } 1078 } 1079 break; 1080 1081 case ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6: 1082 /* MISRA Ref 11.3.1 [Misaligned access] */ 1083 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1084 /* coverity[misra_c_2012_rule_11_3_violation] */ 1085 vNDRefreshCacheEntry( ( ( const MACAddress_t * ) pxICMPHeader_IPv6->ucOptionBytes ), 1086 &( pxICMPHeader_IPv6->xIPv6Address ), 1087 pxEndPoint ); 1088 FreeRTOS_printf( ( "NEIGHBOR_ADV from %pip\n", 1089 ( void * ) pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); 1090 1091 #if ( ipconfigUSE_RA != 0 ) 1092 1093 /* Receive a NA ( Neighbour Advertisement ) message to see if a chosen IP-address is already in use. 1094 * This is important during SLAAC. */ 1095 vReceiveNA( pxNetworkBuffer ); 1096 #endif 1097 1098 if( ( pxARPWaitingNetworkBuffer != NULL ) && 1099 ( uxIPHeaderSizePacket( pxARPWaitingNetworkBuffer ) == ipSIZE_OF_IPv6_HEADER ) ) 1100 { 1101 prvCheckWaitingBuffer( &( pxICMPHeader_IPv6->xIPv6Address ) ); 1102 } 1103 1104 break; 1105 1106 case ipICMP_ROUTER_SOLICITATION_IPv6: 1107 break; 1108 1109 #if ( ipconfigUSE_RA != 0 ) 1110 case ipICMP_ROUTER_ADVERTISEMENT_IPv6: 1111 vReceiveRA( pxNetworkBuffer ); 1112 break; 1113 #endif /* ( ipconfigUSE_RA != 0 ) */ 1114 1115 default: 1116 /* All possible values are included here above. */ 1117 break; 1118 } /* switch( pxICMPHeader_IPv6->ucTypeOfMessage ) */ 1119 } /* if( pxEndPoint != NULL ) */ 1120 1121 return eReleaseBuffer; 1122 } 1123 /*-----------------------------------------------------------*/ 1124 1125 /** 1126 * @brief Send out a Neighbour Advertisement message. 1127 * 1128 * @param[in] pxEndPoint The end-point to use. 1129 */ 1130 /* MISRA Ref 8.9.1 [File scoped variables] */ 1131 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */ 1132 /* coverity[misra_c_2012_rule_8_9_violation] */ 1133 /* coverity[single_use] */ FreeRTOS_OutputAdvertiseIPv6(NetworkEndPoint_t * pxEndPoint)1134 void FreeRTOS_OutputAdvertiseIPv6( NetworkEndPoint_t * pxEndPoint ) 1135 { 1136 NetworkBufferDescriptor_t * pxNetworkBuffer; 1137 ICMPPacket_IPv6_t * pxICMPPacket; 1138 NetworkInterface_t * pxInterface; 1139 ICMPHeader_IPv6_t * pxICMPHeader_IPv6; 1140 size_t uxICMPSize; 1141 size_t uxPacketSize; 1142 1143 uxPacketSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPHeader_IPv6_t ); 1144 1145 /* This is called from the context of the IP event task, so a block time 1146 * must not be used. */ 1147 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxPacketSize, ndDONT_BLOCK ); 1148 1149 if( pxNetworkBuffer != NULL ) 1150 { 1151 ( void ) memset( pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS ); 1152 pxNetworkBuffer->pxEndPoint = pxEndPoint; 1153 1154 pxInterface = pxEndPoint->pxNetworkInterface; 1155 1156 configASSERT( pxInterface != NULL ); 1157 1158 /* MISRA Ref 11.3.1 [Misaligned access] */ 1159 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1160 /* coverity[misra_c_2012_rule_11_3_violation] */ 1161 pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 1162 pxICMPHeader_IPv6 = ( ( ICMPHeader_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); 1163 1164 ( void ) memcpy( pxICMPPacket->xEthernetHeader.xDestinationAddress.ucBytes, pcLOCAL_ALL_NODES_MULTICAST_MAC, ipMAC_ADDRESS_LENGTH_BYTES ); 1165 ( void ) memcpy( pxICMPPacket->xEthernetHeader.xSourceAddress.ucBytes, pxEndPoint->xMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); 1166 pxICMPPacket->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE; /* 12 + 2 = 14 */ 1167 1168 pxICMPPacket->xIPHeader.ucVersionTrafficClass = 0x60; 1169 pxICMPPacket->xIPHeader.ucTrafficClassFlow = 0; 1170 pxICMPPacket->xIPHeader.usFlowLabel = 0; 1171 1172 pxICMPPacket->xIPHeader.usPayloadLength = FreeRTOS_htons( sizeof( ICMPHeader_IPv6_t ) ); 1173 pxICMPPacket->xIPHeader.ucNextHeader = ipPROTOCOL_ICMP_IPv6; 1174 pxICMPPacket->xIPHeader.ucHopLimit = 255; 1175 ( void ) memcpy( pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 1176 ( void ) memcpy( pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, pcLOCAL_ALL_NODES_MULTICAST_IP, ipSIZE_OF_IPv6_ADDRESS ); 1177 1178 uxICMPSize = sizeof( ICMPHeader_IPv6_t ); 1179 pxICMPHeader_IPv6->ucTypeOfMessage = ipICMP_NEIGHBOR_ADVERTISEMENT_IPv6; 1180 pxICMPHeader_IPv6->ucTypeOfService = 0; 1181 pxICMPHeader_IPv6->ulReserved = ndICMPv6_FLAG_SOLICITED | ndICMPv6_FLAG_UPDATE; 1182 pxICMPHeader_IPv6->ulReserved = FreeRTOS_htonl( pxICMPHeader_IPv6->ulReserved ); 1183 1184 /* Type of option. */ 1185 pxICMPHeader_IPv6->ucOptionType = ndICMP_TARGET_LINK_LAYER_ADDRESS; 1186 /* Length of option in units of 8 bytes. */ 1187 pxICMPHeader_IPv6->ucOptionLength = 1; 1188 ( void ) memcpy( pxICMPHeader_IPv6->ucOptionBytes, pxEndPoint->xMACAddress.ucBytes, sizeof( MACAddress_t ) ); 1189 pxICMPPacket->xIPHeader.ucHopLimit = 255; 1190 ( void ) memcpy( pxICMPHeader_IPv6->xIPv6Address.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( pxICMPHeader_IPv6->xIPv6Address.ucBytes ) ); 1191 1192 /* Important: tell NIC driver how many bytes must be sent */ 1193 pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize ); 1194 1195 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) 1196 { 1197 /* calculate the ICMPv6 checksum for outgoing package */ 1198 ( void ) usGenerateProtocolChecksum( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, pdTRUE ); 1199 } 1200 #else 1201 { 1202 /* Many EMAC peripherals will only calculate the ICMP checksum 1203 * correctly if the field is nulled beforehand. */ 1204 pxICMPHeader_IPv6->usChecksum = 0; 1205 } 1206 #endif 1207 1208 /* Set the parameter 'bReleaseAfterSend'. */ 1209 ( void ) pxInterface->pfOutput( pxInterface, pxNetworkBuffer, pdTRUE ); 1210 } 1211 } 1212 /*-----------------------------------------------------------*/ 1213 1214 /** 1215 * @brief Create an IPv16 address, based on a prefix. 1216 * 1217 * @param[out] pxIPAddress The location where the new IPv6 address will be stored. 1218 * @param[in] pxPrefix The prefix to be used. 1219 * @param[in] uxPrefixLength The length of the prefix. 1220 * @param[in] xDoRandom A non-zero value if the bits after the prefix should have a random value. 1221 * 1222 * @return pdPASS if the operation was successful. Or pdFAIL in case xApplicationGetRandomNumber() 1223 * returned an error. 1224 */ FreeRTOS_CreateIPv6Address(IPv6_Address_t * pxIPAddress,const IPv6_Address_t * pxPrefix,size_t uxPrefixLength,BaseType_t xDoRandom)1225 BaseType_t FreeRTOS_CreateIPv6Address( IPv6_Address_t * pxIPAddress, 1226 const IPv6_Address_t * pxPrefix, 1227 size_t uxPrefixLength, 1228 BaseType_t xDoRandom ) 1229 { 1230 uint32_t pulRandom[ 4 ]; 1231 uint8_t * pucSource; 1232 BaseType_t xIndex, xResult = pdPASS; 1233 1234 if( xDoRandom != pdFALSE ) 1235 { 1236 /* Create an IP-address, based on a net prefix and a 1237 * random host address. 1238 * ARRAY_SIZE_X() returns the size of an array as a 1239 * signed value ( BaseType_t ). 1240 */ 1241 for( xIndex = 0; xIndex < ARRAY_SIZE_X( pulRandom ); xIndex++ ) 1242 { 1243 if( xApplicationGetRandomNumber( &( pulRandom[ xIndex ] ) ) == pdFAIL ) 1244 { 1245 xResult = pdFAIL; 1246 break; 1247 } 1248 } 1249 } 1250 else 1251 { 1252 ( void ) memset( pulRandom, 0, sizeof( pulRandom ) ); 1253 } 1254 1255 if( xResult == pdPASS ) 1256 { 1257 configASSERT( ( uxPrefixLength > 0U ) && ( uxPrefixLength < ( 8U * ipSIZE_OF_IPv6_ADDRESS ) ) ); 1258 1259 if( uxPrefixLength >= 8U ) 1260 { 1261 ( void ) memcpy( pxIPAddress->ucBytes, pxPrefix->ucBytes, ( uxPrefixLength + 7U ) / 8U ); 1262 } 1263 1264 pucSource = ( uint8_t * ) pulRandom; 1265 size_t uxIndex = uxPrefixLength / 8U; 1266 1267 if( ( uxPrefixLength % 8U ) != 0U ) 1268 { 1269 /* uxHostLen is between 1 and 7 bits long. */ 1270 size_t uxHostLen = 8U - ( uxPrefixLength % 8U ); 1271 uint32_t uxHostMask = ( ( ( uint32_t ) 1U ) << uxHostLen ) - 1U; 1272 uint8_t ucNetMask = ( uint8_t ) ~( uxHostMask ); 1273 1274 pxIPAddress->ucBytes[ uxIndex ] &= ucNetMask; 1275 pxIPAddress->ucBytes[ uxIndex ] |= ( pucSource[ 0 ] & ( ( uint8_t ) uxHostMask ) ); 1276 pucSource = &( pucSource[ 1 ] ); 1277 uxIndex++; 1278 } 1279 1280 if( uxIndex < ipSIZE_OF_IPv6_ADDRESS ) 1281 { 1282 ( void ) memcpy( &( pxIPAddress->ucBytes[ uxIndex ] ), pucSource, ipSIZE_OF_IPv6_ADDRESS - uxIndex ); 1283 } 1284 } 1285 1286 return xResult; 1287 } 1288 /*-----------------------------------------------------------*/ 1289 #endif /* ipconfigUSE_IPv6 */ 1290