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_RA.c 28 * @brief A client implementation of Router advertisement protocol. 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_IP_Timers.h" 45 #include "FreeRTOS_ARP.h" 46 #include "FreeRTOS_UDP_IP.h" 47 #include "FreeRTOS_Routing.h" 48 #include "FreeRTOS_ND.h" 49 #if ( ipconfigUSE_LLMNR == 1 ) 50 #include "FreeRTOS_DNS.h" 51 #endif /* ipconfigUSE_LLMNR */ 52 #include "NetworkBufferManagement.h" 53 54 /* This define may exclude the entire source file. */ 55 #if ( ipconfigUSE_IPv6 != 0 ) && ( ipconfigUSE_RA != 0 ) 56 57 /*-----------------------------------------------------------*/ 58 59 /** A block time of 0 simply means "don't block". */ 60 #define raDONT_BLOCK ( ( TickType_t ) 0 ) 61 62 /** The default value for the IPv6-field 'ucVersionTrafficClass'. */ 63 #define raDEFAULT_VERSION_TRAFFIC_CLASS 0x60U 64 65 /** The default value for the IPv6-field 'ucHopLimit'. */ 66 #define raDEFAULT_HOP_LIMIT 255U 67 68 /*-----------------------------------------------------------*/ 69 70 /* Initialise the Router Advertisement process for a given end-point. */ 71 static void vRAProcessInit( NetworkEndPoint_t * pxEndPoint ); 72 73 /* Find a link-local address that is bound to a given interface. */ 74 static BaseType_t xGetLinkLocalAddress( const NetworkInterface_t * pxInterface, 75 IPv6_Address_t * pxAddress ); 76 77 /* Read the reply received from the RA server. */ 78 static ICMPPrefixOption_IPv6_t * vReceiveRA_ReadReply( const NetworkBufferDescriptor_t * pxNetworkBuffer ); 79 80 /* Handle the states that are limited by a timer. See if any of the timers has expired. */ 81 static TickType_t xRAProcess_HandleWaitStates( NetworkEndPoint_t * pxEndPoint, 82 TickType_t uxReloadTime ); 83 84 /* Handle the other states. */ 85 static TickType_t xRAProcess_HandleOtherStates( NetworkEndPoint_t * pxEndPoint, 86 TickType_t uxReloadTime ); 87 88 89 /*-----------------------------------------------------------*/ 90 91 /** 92 * @brief Find a link-local address that is bound to a given interface. 93 * 94 * @param[in] pxInterface The interface for which a link-local address is looked up. 95 * @param[out] pxAddress The IP address will be copied to this parameter. 96 * 97 * @return pdPASS in case a link-local address was found, otherwise pdFAIL. 98 */ xGetLinkLocalAddress(const NetworkInterface_t * pxInterface,IPv6_Address_t * pxAddress)99 static BaseType_t xGetLinkLocalAddress( const NetworkInterface_t * pxInterface, 100 IPv6_Address_t * pxAddress ) 101 { 102 BaseType_t xResult = pdFAIL; 103 NetworkEndPoint_t * pxEndPoint; 104 105 for( pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface ); 106 pxEndPoint != NULL; 107 pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ) ) 108 { 109 /* Check if it has the link-local prefix FE80::/10 */ 110 if( ( pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 0 ] == 0xfeU ) && 111 ( ( pxEndPoint->ipv6_settings.xIPAddress.ucBytes[ 1 ] & 0xc0U ) == 0x80U ) ) 112 { 113 ( void ) memcpy( pxAddress->ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 114 xResult = pdPASS; 115 break; 116 } 117 } 118 119 return xResult; 120 } 121 /*-----------------------------------------------------------*/ 122 123 /** 124 * @brief Send an ICMPv6 message of the type: Router Solicitation. 125 * 126 * @param[in] pxNetworkBuffer The network buffer which can be used for this. 127 * @param[in] pxIPAddress The target address, normally ff02::2 128 * 129 */ vNDSendRouterSolicitation(NetworkBufferDescriptor_t * pxNetworkBuffer,IPv6_Address_t * pxIPAddress)130 void vNDSendRouterSolicitation( NetworkBufferDescriptor_t * pxNetworkBuffer, 131 IPv6_Address_t * pxIPAddress ) 132 { 133 ICMPPacket_IPv6_t * pxICMPPacket; 134 ICMPRouterSolicitation_IPv6_t * xRASolicitationRequest; 135 const NetworkEndPoint_t * pxEndPoint = pxNetworkBuffer->pxEndPoint; 136 const size_t uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPRouterSolicitation_IPv6_t ); 137 MACAddress_t xMultiCastMacAddress; 138 NetworkBufferDescriptor_t * pxDescriptor = pxNetworkBuffer; 139 IPv6_Address_t xSourceAddress; 140 BaseType_t xHasLocal; 141 NetworkBufferDescriptor_t * pxNewDescriptor = NULL; 142 143 configASSERT( pxEndPoint != NULL ); 144 configASSERT( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED ); 145 146 xHasLocal = xGetLinkLocalAddress( pxEndPoint->pxNetworkInterface, &( xSourceAddress ) ); 147 148 if( xHasLocal == pdFAIL ) 149 { 150 FreeRTOS_printf( ( "RA: can not find a Link-local address\n" ) ); 151 ( void ) memset( xSourceAddress.ucBytes, 0, ipSIZE_OF_IPv6_ADDRESS ); 152 } 153 else 154 { 155 FreeRTOS_printf( ( "RA: source %pip\n", ( void * ) xSourceAddress.ucBytes ) ); 156 } 157 158 if( pxDescriptor->xDataLength < uxNeededSize ) 159 { 160 pxNewDescriptor = pxDuplicateNetworkBufferWithDescriptor( pxDescriptor, uxNeededSize ); 161 vReleaseNetworkBufferAndDescriptor( pxDescriptor ); 162 pxDescriptor = pxNewDescriptor; 163 } 164 165 if( pxDescriptor != NULL ) 166 { 167 /* MISRA Ref 11.3.1 [Misaligned access] */ 168 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 169 /* coverity[misra_c_2012_rule_11_3_violation] */ 170 pxICMPPacket = ( ( ICMPPacket_IPv6_t * ) pxDescriptor->pucEthernetBuffer ); 171 xRASolicitationRequest = ( ( ICMPRouterSolicitation_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); 172 173 pxDescriptor->xDataLength = uxNeededSize; 174 175 ( void ) eNDGetCacheEntry( pxIPAddress, &( xMultiCastMacAddress ), NULL ); 176 177 /* Set Ethernet header. Will be swapped. */ 178 ( void ) memcpy( pxICMPPacket->xEthernetHeader.xSourceAddress.ucBytes, xMultiCastMacAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); 179 ( void ) memcpy( pxICMPPacket->xEthernetHeader.xDestinationAddress.ucBytes, pxEndPoint->xMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); 180 pxICMPPacket->xEthernetHeader.usFrameType = ipIPv6_FRAME_TYPE; 181 182 /* Set IP-header. */ 183 pxICMPPacket->xIPHeader.ucVersionTrafficClass = raDEFAULT_VERSION_TRAFFIC_CLASS; 184 pxICMPPacket->xIPHeader.ucTrafficClassFlow = 0U; 185 pxICMPPacket->xIPHeader.usFlowLabel = 0U; 186 pxICMPPacket->xIPHeader.usPayloadLength = FreeRTOS_htons( sizeof( ICMPRouterSolicitation_IPv6_t ) ); 187 pxICMPPacket->xIPHeader.ucNextHeader = ipPROTOCOL_ICMP_IPv6; 188 pxICMPPacket->xIPHeader.ucHopLimit = raDEFAULT_HOP_LIMIT; 189 190 /* Normally, the source address is set as 'ipv6_settings.xIPAddress'. 191 * But is some routers will not accept a public IP-address, the original 192 * default address will be used. It must be a link-local address. */ 193 ( void ) memcpy( pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 194 195 ( void ) memcpy( pxICMPPacket->xIPHeader.xDestinationAddress.ucBytes, pxIPAddress->ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 196 197 /* Set ICMP header. */ 198 ( void ) memset( xRASolicitationRequest, 0, sizeof( *xRASolicitationRequest ) ); 199 xRASolicitationRequest->ucTypeOfMessage = ipICMP_ROUTER_SOLICITATION_IPv6; 200 201 /* __XX__ revisit on why commented out 202 * xRASolicitationRequest->ucOptionType = ndICMP_SOURCE_LINK_LAYER_ADDRESS; 203 * xRASolicitationRequest->ucOptionLength = 1; 204 * ( void ) memcpy( xRASolicitationRequest->ucOptionBytes, pxEndPoint->xMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ); 205 */ 206 207 /* Checksums. */ 208 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) 209 { 210 /* calculate the ICMPv6 checksum for outgoing package */ 211 ( void ) usGenerateProtocolChecksum( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, pdTRUE ); 212 } 213 #else 214 { 215 /* Many EMAC peripherals will only calculate the ICMP checksum 216 * correctly if the field is nulled beforehand. */ 217 xRASolicitationRequest->usChecksum = 0U; 218 } 219 #endif 220 221 /* This function will fill in the eth addresses and send the packet */ 222 vReturnEthernetFrame( pxDescriptor, pdTRUE ); 223 } 224 } 225 /*-----------------------------------------------------------*/ 226 227 /** 228 * @brief Receive a NA ( Neighbour Advertisement ) message to see if a chosen IP-address is already in use. 229 * 230 * @param[in] pxNetworkBuffer The buffer that contains the message. 231 */ vReceiveNA(const NetworkBufferDescriptor_t * pxNetworkBuffer)232 void vReceiveNA( const NetworkBufferDescriptor_t * pxNetworkBuffer ) 233 { 234 const NetworkInterface_t * pxInterface = pxNetworkBuffer->pxInterface; 235 NetworkEndPoint_t * pxPoint; 236 237 /* MISRA Ref 11.3.1 [Misaligned access] */ 238 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 239 /* coverity[misra_c_2012_rule_11_3_violation] */ 240 const ICMPPacket_IPv6_t * pxICMPPacket = ( ( const ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 241 const ICMPHeader_IPv6_t * pxICMPHeader_IPv6 = ( ( const ICMPHeader_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); 242 243 for( pxPoint = FreeRTOS_FirstEndPoint( pxInterface ); 244 pxPoint != NULL; 245 pxPoint = FreeRTOS_NextEndPoint( pxInterface, pxPoint ) ) 246 { 247 if( ( pxPoint->bits.bWantRA != pdFALSE_UNSIGNED ) && ( pxPoint->xRAData.eRAState == eRAStateIPWait ) ) 248 { 249 if( memcmp( pxPoint->ipv6_settings.xIPAddress.ucBytes, pxICMPHeader_IPv6->xIPv6Address.ucBytes, ipSIZE_OF_IPv6_ADDRESS ) == 0 ) 250 { 251 pxPoint->xRAData.bits.bIPAddressInUse = pdTRUE_UNSIGNED; 252 vDHCP_RATimerReload( pxPoint, 100U ); 253 } 254 } 255 } 256 } 257 /*-----------------------------------------------------------*/ 258 259 /** 260 * @brief Read a received RA reply and return the prefix option from the packet. 261 * 262 * @param[in] pxNetworkBuffer The buffer that contains the message. 263 * 264 * @returns Returns the ICMP prefix option pointer, pointing to its location in the 265 * input RA reply message buffer. 266 */ vReceiveRA_ReadReply(const NetworkBufferDescriptor_t * pxNetworkBuffer)267 static ICMPPrefixOption_IPv6_t * vReceiveRA_ReadReply( const NetworkBufferDescriptor_t * pxNetworkBuffer ) 268 { 269 size_t uxIndex = 0U; 270 const size_t uxICMPSize = sizeof( ICMPRouterAdvertisement_IPv6_t ); 271 const size_t uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize; 272 /* uxLast points to the first byte after the buffer. */ 273 const size_t uxLast = pxNetworkBuffer->xDataLength - uxNeededSize; 274 uint8_t * pucBytes = &( pxNetworkBuffer->pucEthernetBuffer[ uxNeededSize ] ); 275 ICMPPrefixOption_IPv6_t * pxPrefixOption = NULL; 276 277 while( ( uxIndex + 1U ) < uxLast ) 278 { 279 uint8_t ucType = pucBytes[ uxIndex ]; 280 size_t uxPrefixLength = ( size_t ) pucBytes[ uxIndex + 1U ]; 281 size_t uxLength = uxPrefixLength * 8U; 282 283 if( uxPrefixLength == 0U ) 284 { 285 /* According to RFC 4861, length of the option value 0 is invalid. Hence returning from here */ 286 FreeRTOS_printf( ( "RA: Invalid length of the option value as zero. " ) ); 287 break; 288 } 289 290 if( uxLast < ( uxIndex + uxLength ) ) 291 { 292 FreeRTOS_printf( ( "RA: Not enough bytes ( %u > %u )\n", ( unsigned ) ( uxIndex + uxLength ), ( unsigned ) uxLast ) ); 293 break; 294 } 295 296 switch( ucType ) 297 { 298 case ndICMP_SOURCE_LINK_LAYER_ADDRESS: /* 1 */ 299 FreeRTOS_printf( ( "RA: Source = %02x-%02x-%02x-%02x-%02x-%02x\n", 300 pucBytes[ uxIndex + 2U ], 301 pucBytes[ uxIndex + 3U ], 302 pucBytes[ uxIndex + 4U ], 303 pucBytes[ uxIndex + 5U ], 304 pucBytes[ uxIndex + 6U ], 305 pucBytes[ uxIndex + 7U ] ) ); 306 break; 307 308 case ndICMP_TARGET_LINK_LAYER_ADDRESS: /* 2 */ 309 break; 310 311 case ndICMP_PREFIX_INFORMATION: /* 3 */ 312 /* MISRA Ref 11.3.1 [Misaligned access] */ 313 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 314 /* coverity[misra_c_2012_rule_11_3_violation] */ 315 pxPrefixOption = ( ( ICMPPrefixOption_IPv6_t * ) &( pucBytes[ uxIndex ] ) ); 316 317 FreeRTOS_printf( ( "RA: Prefix len %d Life %u, %u (%pip)\n", 318 pxPrefixOption->ucPrefixLength, 319 FreeRTOS_ntohl( pxPrefixOption->ulValidLifeTime ), 320 FreeRTOS_ntohl( pxPrefixOption->ulPreferredLifeTime ), 321 ( void * ) pxPrefixOption->ucPrefix ) ); 322 break; 323 324 case ndICMP_REDIRECTED_HEADER: /* 4 */ 325 break; 326 327 case ndICMP_MTU_OPTION: /* 5 */ 328 { 329 uint32_t ulMTU; 330 ( void ) ulMTU; 331 332 /* ulChar2u32 returns host-endian numbers. */ 333 ulMTU = ulChar2u32( &( pucBytes[ uxIndex + 4U ] ) ); 334 FreeRTOS_printf( ( "RA: MTU = %u\n", ( unsigned int ) ulMTU ) ); 335 } 336 break; 337 338 default: 339 FreeRTOS_printf( ( "RA: Type 0x%02x not implemented\n", ucType ) ); 340 break; 341 } 342 343 uxIndex = uxIndex + uxLength; 344 } /* while( ( uxIndex + 1 ) < uxLast ) */ 345 346 return pxPrefixOption; 347 } 348 /*-----------------------------------------------------------*/ 349 350 /** 351 * @brief Receive and analyse a RA ( Router Advertisement ) message. 352 * If the reply is satisfactory, the end-point will do SLAAC: choose an IP-address using the 353 * prefix offered, and completed with random bits. It will start testing if another device 354 * already exists that uses the same IP-address. 355 * 356 * @param[in] pxNetworkBuffer The buffer that contains the message. 357 */ vReceiveRA(const NetworkBufferDescriptor_t * pxNetworkBuffer)358 void vReceiveRA( const NetworkBufferDescriptor_t * pxNetworkBuffer ) 359 { 360 /* MISRA Ref 11.3.1 [Misaligned access] */ 361 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 362 /* coverity[misra_c_2012_rule_11_3_violation] */ 363 const ICMPPacket_IPv6_t * pxICMPPacket = ( ( const ICMPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 364 const ICMPPrefixOption_IPv6_t * pxPrefixOption = NULL; 365 const size_t uxICMPSize = sizeof( ICMPRouterAdvertisement_IPv6_t ); 366 const size_t uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxICMPSize; 367 368 /* A Router Advertisement was received, handle it here. */ 369 if( uxNeededSize > pxNetworkBuffer->xDataLength ) 370 { 371 FreeRTOS_printf( ( "vReceiveRA: The buffer provided is too small\n" ) ); 372 } 373 else 374 { 375 /* MISRA Ref 11.3.1 [Misaligned access] */ 376 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 377 /* coverity[misra_c_2012_rule_11_3_violation] */ 378 const ICMPRouterAdvertisement_IPv6_t * pxAdvertisement = ( ( const ICMPRouterAdvertisement_IPv6_t * ) &( pxICMPPacket->xICMPHeaderIPv6 ) ); 379 FreeRTOS_printf( ( "RA: Type %02x Srv %02x Checksum %04x Hops %d Flags %02x Life %d\n", 380 pxAdvertisement->ucTypeOfMessage, 381 pxAdvertisement->ucTypeOfService, 382 FreeRTOS_ntohs( pxAdvertisement->usChecksum ), 383 pxAdvertisement->ucHopLimit, 384 pxAdvertisement->ucFlags, 385 FreeRTOS_ntohs( pxAdvertisement->usLifetime ) ) ); 386 387 if( pxAdvertisement->usLifetime != 0U ) 388 { 389 pxPrefixOption = vReceiveRA_ReadReply( pxNetworkBuffer ); 390 391 configASSERT( pxNetworkBuffer->pxInterface != NULL ); 392 393 if( pxPrefixOption != NULL ) 394 { 395 NetworkEndPoint_t * pxEndPoint; 396 397 for( pxEndPoint = FreeRTOS_FirstEndPoint( pxNetworkBuffer->pxInterface ); 398 pxEndPoint != NULL; 399 pxEndPoint = FreeRTOS_NextEndPoint( pxNetworkBuffer->pxInterface, pxEndPoint ) ) 400 { 401 if( ( pxEndPoint->bits.bWantRA != pdFALSE_UNSIGNED ) && ( pxEndPoint->xRAData.eRAState == eRAStateWait ) ) 402 { 403 pxEndPoint->ipv6_settings.uxPrefixLength = pxPrefixOption->ucPrefixLength; 404 ( void ) memcpy( pxEndPoint->ipv6_settings.xPrefix.ucBytes, pxPrefixOption->ucPrefix, ipSIZE_OF_IPv6_ADDRESS ); 405 ( void ) memcpy( pxEndPoint->ipv6_settings.xGatewayAddress.ucBytes, pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 406 407 pxEndPoint->xRAData.bits.bRouterReplied = pdTRUE_UNSIGNED; 408 pxEndPoint->xRAData.uxRetryCount = 0U; 409 pxEndPoint->xRAData.ulPreferredLifeTime = FreeRTOS_ntohl( pxPrefixOption->ulPreferredLifeTime ); 410 /* Force taking a new random IP-address. */ 411 pxEndPoint->xRAData.bits.bIPAddressInUse = pdTRUE_UNSIGNED; 412 pxEndPoint->xRAData.eRAState = eRAStateIPTest; 413 vRAProcess( pdFALSE, pxEndPoint ); 414 } 415 } 416 } 417 } 418 else 419 { 420 /* The life-time field contains zero. */ 421 } 422 } 423 } 424 /*-----------------------------------------------------------*/ 425 426 /** 427 * @brief Handles the RA wait state and calculates the new timer reload value 428 * based on the wait state. Also checks if any timer has expired. If its found that 429 * there is no other device using the same IP-address vIPNetworkUpCalls() is called 430 * to send the network up event. 431 * 432 * @param[in] pxEndPoint The end point for which RA assignment is required. 433 * @param[out] uxReloadTime Timer reload value in ticks. 434 * 435 * @return New timer reload value. 436 */ xRAProcess_HandleWaitStates(NetworkEndPoint_t * pxEndPoint,TickType_t uxReloadTime)437 static TickType_t xRAProcess_HandleWaitStates( NetworkEndPoint_t * pxEndPoint, 438 TickType_t uxReloadTime ) 439 { 440 TickType_t uxNewReloadTime = uxReloadTime; 441 442 if( pxEndPoint->xRAData.eRAState == eRAStateWait ) 443 { 444 /* A Router Solicitation has been sent, waited for a reply, but no came. 445 * All replies will be handled in the function vReceiveRA(). */ 446 pxEndPoint->xRAData.uxRetryCount++; 447 448 if( pxEndPoint->xRAData.uxRetryCount < ( UBaseType_t ) ipconfigRA_SEARCH_COUNT ) 449 { 450 pxEndPoint->xRAData.eRAState = eRAStateApply; 451 } 452 else 453 { 454 FreeRTOS_printf( ( "RA: Giving up waiting for a Router.\n" ) ); 455 ( void ) memcpy( &( pxEndPoint->ipv6_settings ), &( pxEndPoint->ipv6_defaults ), sizeof( pxEndPoint->ipv6_settings ) ); 456 457 pxEndPoint->xRAData.bits.bRouterReplied = pdFALSE_UNSIGNED; 458 pxEndPoint->xRAData.uxRetryCount = 0U; 459 /* Force taking a new random IP-address. */ 460 pxEndPoint->xRAData.bits.bIPAddressInUse = pdTRUE_UNSIGNED; 461 pxEndPoint->xRAData.eRAState = eRAStateIPTest; 462 } 463 } 464 else if( pxEndPoint->xRAData.eRAState == eRAStateIPWait ) 465 { 466 /* A Neighbour Solicitation has been sent, waited for a reply. 467 * Repeat this 'ipconfigRA_IP_TEST_COUNT' times to be sure. */ 468 if( pxEndPoint->xRAData.bits.bIPAddressInUse != pdFALSE_UNSIGNED ) 469 { 470 /* Another device has responded with the same IPv4 address. */ 471 pxEndPoint->xRAData.uxRetryCount = 0U; 472 pxEndPoint->xRAData.eRAState = eRAStateIPTest; 473 uxNewReloadTime = pdMS_TO_TICKS( ipconfigRA_IP_TEST_TIME_OUT_MSEC ); 474 } 475 else if( pxEndPoint->xRAData.uxRetryCount < ( UBaseType_t ) ipconfigRA_IP_TEST_COUNT ) 476 { 477 /* Try again. */ 478 pxEndPoint->xRAData.uxRetryCount++; 479 pxEndPoint->xRAData.eRAState = eRAStateIPTest; 480 uxNewReloadTime = pdMS_TO_TICKS( ipconfigRA_IP_TEST_TIME_OUT_MSEC ); 481 } 482 else 483 { 484 /* Now it is assumed that there is no other device using the same IP-address. */ 485 if( pxEndPoint->xRAData.bits.bRouterReplied != pdFALSE_UNSIGNED ) 486 { 487 /* Obtained configuration from a router. */ 488 uxNewReloadTime = pdMS_TO_TICKS( 1000U * pxEndPoint->xRAData.ulPreferredLifeTime ); 489 pxEndPoint->xRAData.eRAState = eRAStatePreLease; 490 iptraceRA_SUCCEDEED( &( pxEndPoint->ipv6_settings.xIPAddress ) ); 491 FreeRTOS_printf( ( "RA: succeeded, using IP address %pip Reload after %u seconds\n", 492 ( void * ) pxEndPoint->ipv6_settings.xIPAddress.ucBytes, 493 ( unsigned ) pxEndPoint->xRAData.ulPreferredLifeTime ) ); 494 } 495 else 496 { 497 /* Using the default network parameters. */ 498 pxEndPoint->xRAData.eRAState = eRAStateFailed; 499 500 iptraceRA_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( &( pxEndPoint->ipv6_settings.xIPAddress ) ); 501 502 FreeRTOS_printf( ( "RA: failed, using default parameters and IP address %pip\n", ( void * ) pxEndPoint->ipv6_settings.xIPAddress.ucBytes ) ); 503 /* Disable the timer. */ 504 uxNewReloadTime = 0U; 505 } 506 507 /* Now call vIPNetworkUpCalls() to send the network-up event and 508 * start the ARP timer. */ 509 vIPNetworkUpCalls( pxEndPoint ); 510 } 511 } 512 else 513 { 514 /* Do nothing */ 515 } 516 517 return uxNewReloadTime; 518 } 519 /*-----------------------------------------------------------*/ 520 521 /** 522 * @brief Handles the RA states other than the wait states. 523 * 524 * @param[in] pxEndPoint The end point for which RA assignment is required. 525 * @param[out] uxReloadTime Timer reload value in ticks. 526 * 527 * @return New timer reload value. 528 */ xRAProcess_HandleOtherStates(NetworkEndPoint_t * pxEndPoint,TickType_t uxReloadTime)529 static TickType_t xRAProcess_HandleOtherStates( NetworkEndPoint_t * pxEndPoint, 530 TickType_t uxReloadTime ) 531 { 532 TickType_t uxNewReloadTime = uxReloadTime; 533 534 switch( pxEndPoint->xRAData.eRAState ) 535 { 536 case eRAStateApply: 537 { 538 IPv6_Address_t xIPAddress; 539 size_t uxNeededSize; 540 NetworkBufferDescriptor_t * pxNetworkBuffer; 541 542 /* Send a Router Solicitation to ff02::2 */ 543 ( void ) memset( xIPAddress.ucBytes, 0, sizeof( xIPAddress.ucBytes ) ); 544 xIPAddress.ucBytes[ 0 ] = 0xffU; 545 xIPAddress.ucBytes[ 1 ] = 0x02U; 546 xIPAddress.ucBytes[ 15 ] = 0x02U; 547 uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPRouterSolicitation_IPv6_t ); 548 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxNeededSize, raDONT_BLOCK ); 549 550 if( pxNetworkBuffer != NULL ) 551 { 552 pxNetworkBuffer->pxEndPoint = pxEndPoint; 553 vNDSendRouterSolicitation( pxNetworkBuffer, &( xIPAddress ) ); 554 } 555 556 FreeRTOS_printf( ( "vRAProcess: Router Solicitation, attempt %lu/%u\n", 557 pxEndPoint->xRAData.uxRetryCount + 1U, 558 ipconfigRA_SEARCH_COUNT ) ); 559 /* Wait a configurable time for a router advertisement. */ 560 uxNewReloadTime = pdMS_TO_TICKS( ipconfigRA_SEARCH_TIME_OUT_MSEC ); 561 pxEndPoint->xRAData.eRAState = eRAStateWait; 562 } 563 break; 564 565 case eRAStateIPTest: /* Assuming an IP address, test if another device is using it already. */ 566 { 567 size_t uxNeededSize; 568 NetworkBufferDescriptor_t * pxNetworkBuffer; 569 570 /* Get an IP-address, using the network prefix and a random host address. */ 571 if( pxEndPoint->xRAData.bits.bIPAddressInUse != 0U ) 572 { 573 pxEndPoint->xRAData.bits.bIPAddressInUse = pdFALSE_UNSIGNED; 574 575 ( void ) FreeRTOS_CreateIPv6Address( &pxEndPoint->ipv6_settings.xIPAddress, &pxEndPoint->ipv6_settings.xPrefix, pxEndPoint->ipv6_settings.uxPrefixLength, pdTRUE ); 576 577 FreeRTOS_printf( ( "RA: Creating a random IP-address\n" ) ); 578 } 579 580 FreeRTOS_printf( ( "RA: Neighbour solicitation for %pip\n", ( void * ) pxEndPoint->ipv6_settings.xIPAddress.ucBytes ) ); 581 582 uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPHeader_IPv6_t ); 583 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxNeededSize, raDONT_BLOCK ); 584 585 if( pxNetworkBuffer != NULL ) 586 { 587 pxNetworkBuffer->pxEndPoint = pxEndPoint; 588 vNDSendNeighbourSolicitation( pxNetworkBuffer, &( pxEndPoint->ipv6_settings.xIPAddress ) ); 589 } 590 591 uxNewReloadTime = pdMS_TO_TICKS( 1000U ); 592 pxEndPoint->xRAData.eRAState = eRAStateIPWait; 593 } 594 break; 595 596 case eRAStatePreLease: 597 pxEndPoint->xRAData.eRAState = eRAStateLease; 598 break; 599 600 case eRAStateLease: 601 602 vRAProcessInit( pxEndPoint ); 603 uxNewReloadTime = pdMS_TO_TICKS( 1000U ); 604 605 break; 606 607 case eRAStateFailed: 608 break; 609 610 default: 611 /* All states were handled. */ 612 break; 613 } 614 615 return uxNewReloadTime; 616 } 617 /*-----------------------------------------------------------*/ 618 619 /** 620 * @brief Initialise the RA state machine. 621 * 622 * @param[in] pxEndPoint The end-point for which Router Advertisement is required. 623 */ vRAProcessInit(NetworkEndPoint_t * pxEndPoint)624 static void vRAProcessInit( NetworkEndPoint_t * pxEndPoint ) 625 { 626 pxEndPoint->xRAData.uxRetryCount = 0U; 627 pxEndPoint->xRAData.eRAState = eRAStateApply; 628 } 629 630 /** 631 * @brief Do a single cycle of the RA state machine. 632 * 633 * @param[in] xDoReset pdTRUE if the state machine must be reset. 634 * @param[in] pxEndPoint The end-point for which a RA assignment is required. 635 */ vRAProcess(BaseType_t xDoReset,NetworkEndPoint_t * pxEndPoint)636 void vRAProcess( BaseType_t xDoReset, 637 NetworkEndPoint_t * pxEndPoint ) 638 { 639 TickType_t uxReloadTime = pdMS_TO_TICKS( 5000U ); 640 641 configASSERT( pxEndPoint != NULL ); 642 643 #if ( ipconfigHAS_PRINTF == 1 ) 644 /* Remember the initial state, just for logging. */ 645 eRAState_t eRAState = pxEndPoint->xRAData.eRAState; 646 #endif 647 648 if( xDoReset != pdFALSE ) 649 { 650 vRAProcessInit( pxEndPoint ); 651 } 652 653 /* First handle the states that are limited by a timer. See if some 654 * timer has expired. */ 655 uxReloadTime = xRAProcess_HandleWaitStates( pxEndPoint, uxReloadTime ); 656 657 /* Now handle the other states. */ 658 uxReloadTime = xRAProcess_HandleOtherStates( pxEndPoint, uxReloadTime ); 659 660 #if ( ipconfigHAS_PRINTF == 1 ) 661 { 662 FreeRTOS_printf( ( "vRAProcess( %ld, %pip) bRouterReplied=%d bIPAddressInUse=%d state %d -> %d\n", 663 xDoReset, 664 ( void * ) pxEndPoint->ipv6_defaults.xIPAddress.ucBytes, 665 pxEndPoint->xRAData.bits.bRouterReplied, 666 pxEndPoint->xRAData.bits.bIPAddressInUse, 667 eRAState, 668 pxEndPoint->xRAData.eRAState ) ); 669 } 670 #endif /* ( ipconfigHAS_PRINTF == 1 ) */ 671 672 if( uxReloadTime != 0U ) 673 { 674 FreeRTOS_printf( ( "RA: Reload %u seconds\n", ( unsigned ) ( uxReloadTime / 1000U ) ) ); 675 vDHCP_RATimerReload( pxEndPoint, uxReloadTime ); 676 } 677 else 678 { 679 /* Disable the timer, this function vRAProcess() won't be called anymore for this end-point. */ 680 FreeRTOS_printf( ( "RA: Disabled timer.\n" ) ); 681 vIPSetDHCP_RATimerEnableState( pxEndPoint, pdFALSE ); 682 } 683 } 684 /*-----------------------------------------------------------*/ 685 686 #endif /* ( ipconfigUSE_IPv6 != 0 ) && ( ipconfigUSE_RA != 0 ) */ 687