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_DNS.c 30 * @brief Implements the Domain Name System for the FreeRTOS+TCP network stack. 31 */ 32 33 /* Standard includes. */ 34 #include <stdint.h> 35 #include <stdio.h> 36 37 /* FreeRTOS includes. */ 38 #include "FreeRTOS.h" 39 #include "task.h" 40 #include "semphr.h" 41 42 /* FreeRTOS+TCP includes. */ 43 #include "FreeRTOS_IP.h" 44 #include "FreeRTOS_IP_Timers.h" 45 #include "FreeRTOS_IP_Private.h" 46 #include "FreeRTOS_UDP_IP.h" 47 #include "FreeRTOS_DNS.h" 48 #include "FreeRTOS_DHCP.h" 49 #include "NetworkBufferManagement.h" 50 #include "FreeRTOS_Routing.h" 51 #include "NetworkInterface.h" 52 53 #include "FreeRTOS_DNS_Globals.h" 54 #include "FreeRTOS_DNS_Cache.h" 55 #include "FreeRTOS_DNS_Parser.h" 56 #include "FreeRTOS_DNS_Networking.h" 57 #include "FreeRTOS_DNS_Callback.h" 58 59 60 /* Exclude the entire file if DNS is not enabled. */ 61 #if ( ipconfigUSE_DNS != 0 ) 62 63 /* 64 * Create the DNS message in the zero copy buffer passed in the first parameter. 65 */ 66 static size_t prvCreateDNSMessage( uint8_t * pucUDPPayloadBuffer, 67 const char * pcHostName, 68 TickType_t uxIdentifier, 69 UBaseType_t uxHostType ); 70 71 72 /* 73 * Check if hostname is already known. If not, call prvGetHostByName() to send a DNS request. 74 */ 75 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 76 static uint32_t prvPrepareLookup( const char * pcHostName, 77 struct freertos_addrinfo ** ppxAddressInfo, 78 BaseType_t xFamily, /* FREERTOS_AF_INET4 / 6. */ 79 FOnDNSEvent pCallbackFunction, 80 void * pvSearchID, 81 TickType_t uxTimeout ); 82 #else 83 static uint32_t prvPrepareLookup( const char * pcHostName, 84 struct freertos_addrinfo ** ppxAddressInfo, 85 BaseType_t xFamily ); /* FREERTOS_AF_INET4 / 6. */ 86 #endif 87 88 /* 89 * Prepare and send a message to a DNS server. 'uxReadTimeOut_ticks' will be passed as 90 * zero, in case the user has supplied a call-back function. 91 */ 92 static uint32_t prvGetHostByName( const char * pcHostName, 93 TickType_t uxIdentifier, 94 TickType_t uxReadTimeOut_ticks, 95 struct freertos_addrinfo ** ppxAddressInfo, 96 BaseType_t xFamily ); 97 98 #if ( ipconfigUSE_LLMNR == 1 ) 99 /** @brief The MAC address used for LLMNR. */ 100 const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } }; 101 #endif /* ipconfigUSE_LLMNR == 1 */ 102 103 /*-----------------------------------------------------------*/ 104 #if ( ipconfigUSE_LLMNR == 1 ) && ( ipconfigUSE_IPv6 != 0 ) 105 106 /** 107 * @brief The IPv6 link-scope multicast address 108 */ 109 const IPv6_Address_t ipLLMNR_IP_ADDR_IPv6 = 110 { 111 { /* ff02::1:3 */ 112 0xff, 0x02, 113 0x00, 0x00, 114 0x00, 0x00, 115 0x00, 0x00, 116 0x00, 0x00, 117 0x00, 0x00, 118 0x00, 0x01, 119 0x00, 0x03, 120 } 121 }; 122 123 /** 124 * @brief The IPv6 link-scope multicast MAC address 125 */ 126 const MACAddress_t xLLMNR_MacAdressIPv6 = { { 0x33, 0x33, 0x00, 0x01, 0x00, 0x03 } }; 127 #endif /* ipconfigUSE_LLMNR && ipconfigUSE_IPv6 */ 128 129 #if ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 ) 130 131 /** 132 * @brief multicast DNS IPv6 address 133 */ 134 const IPv6_Address_t ipMDNS_IP_ADDR_IPv6 = 135 { 136 { /* ff02::fb */ 137 0xff, 0x02, 138 0x00, 0x00, 139 0x00, 0x00, 140 0x00, 0x00, 141 0x00, 0x00, 142 0x00, 0x00, 143 0x00, 0x00, 144 0x00, 0xfb, 145 } 146 }; 147 148 /** 149 * @brief The IPv6 multicast DNS MAC address. 150 * The MAC-addresses are provided here in case a network 151 * interface needs it. 152 */ 153 const MACAddress_t xMDNS_MACAdressIPv6 = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0xFB } }; 154 #endif /* ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_IPv6 != 0 ) */ 155 156 157 #if ( ipconfigUSE_MDNS == 1 ) 158 /** @brief The MAC address used for MDNS. */ 159 const MACAddress_t xMDNS_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb } }; 160 #endif /* ipconfigUSE_MDNS == 1 */ 161 162 /** @brief This global variable is being used to indicate to the driver which IP type 163 * is preferred for name service lookup, either IPv6 or IPv4. */ 164 /* TODO: Fix IPv6 DNS query in Windows Simulator. */ 165 IPPreference_t xDNS_IP_Preference = xPreferenceIPv4; 166 167 /*-----------------------------------------------------------*/ 168 169 /** 170 * @brief A DNS query consists of a header, as described in 'struct xDNSMessage' 171 * It is followed by 1 or more queries, each one consisting of a name and a tail, 172 * with two fields: type and class 173 */ 174 #include "pack_struct_start.h" 175 struct xDNSTail 176 { 177 uint16_t usType; /**< Type of DNS message. */ 178 uint16_t usClass; /**< Class of DNS message. */ 179 } 180 #include "pack_struct_end.h" 181 typedef struct xDNSTail DNSTail_t; 182 183 #if ( ipconfigUSE_IPv4 != 0 ) 184 /** @brief Increment the field 'ucDNSIndex', which is an index in the array */ 185 static void prvIncreaseDNS4Index( NetworkEndPoint_t * pxEndPoint ); 186 #endif 187 188 #if ( ipconfigUSE_IPv6 != 0 ) 189 /** @brief Increment the field 'ucDNSIndex', which is an index in the array */ 190 static void prvIncreaseDNS6Index( NetworkEndPoint_t * pxEndPoint ); 191 #endif 192 193 /*-----------------------------------------------------------*/ 194 195 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 196 197 /** 198 * @brief Define FreeRTOS_gethostbyname() as a normal blocking call. 199 * @param[in] pcHostName The hostname whose IP address is being searched for. 200 * @return The IP-address of the hostname. 201 */ FreeRTOS_gethostbyname(const char * pcHostName)202 uint32_t FreeRTOS_gethostbyname( const char * pcHostName ) 203 { 204 return FreeRTOS_gethostbyname_a( pcHostName, NULL, ( void * ) NULL, 0U ); 205 } 206 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */ 207 /*-----------------------------------------------------------*/ 208 209 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 210 211 /** @brief Initialise the list of call-back structures. 212 */ vDNSInitialise(void)213 void vDNSInitialise( void ) 214 { 215 vDNSCallbackInitialise(); 216 } 217 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */ 218 /*-----------------------------------------------------------*/ 219 220 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 221 222 /** 223 * @brief Remove the entry defined by the search ID to cancel a DNS request. 224 * @param[in] pvSearchID The search ID of the callback function associated with 225 * the DNS request being cancelled. Note that the value of 226 * the pointer matters, not the pointee. 227 */ FreeRTOS_gethostbyname_cancel(void * pvSearchID)228 void FreeRTOS_gethostbyname_cancel( void * pvSearchID ) 229 { 230 vDNSCheckCallBack( pvSearchID ); 231 } 232 233 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */ 234 /*-----------------------------------------------------------*/ 235 236 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 237 238 /** 239 * @brief Look-up the IP-address of a host. 240 * 241 * @param[in] pcName The name of the node or device 242 * @param[in] pcService Ignored for now. 243 * @param[in] pxHints If not NULL preferences. Can be used to indicate the preferred type if IP ( v4 or v6 ). 244 * @param[out] ppxResult An allocated struct, containing the results. 245 * 246 * @return Zero when the operation was successful, otherwise a negative errno value. 247 */ FreeRTOS_getaddrinfo(const char * pcName,const char * pcService,const struct freertos_addrinfo * pxHints,struct freertos_addrinfo ** ppxResult)248 BaseType_t FreeRTOS_getaddrinfo( const char * pcName, /* The name of the node or device */ 249 const char * pcService, /* Ignored for now. */ 250 const struct freertos_addrinfo * pxHints, /* If not NULL: preferences. */ 251 struct freertos_addrinfo ** ppxResult ) /* An allocated struct, containing the results. */ 252 { 253 /* Call the asynchronous version with NULL parameters. */ 254 return FreeRTOS_getaddrinfo_a( pcName, pcService, pxHints, ppxResult, NULL, NULL, 0U ); 255 } 256 #endif /* ( ipconfigDNS_USE_CALLBACKS == 1 ) */ 257 /*-----------------------------------------------------------*/ 258 259 /** 260 * @brief Internal function: allocate and initialise a new struct of type freertos_addrinfo. 261 * 262 * @param[in] pcName the name of the host. 263 * @param[in] xFamily the type of IP-address: FREERTOS_AF_INET4 or FREERTOS_AF_INET6. 264 * @param[in] pucAddress The IP-address of the host. 265 * 266 * @return A pointer to the newly allocated struct, or NULL in case malloc failed.. 267 */ pxNew_AddrInfo(const char * pcName,BaseType_t xFamily,const uint8_t * pucAddress)268 struct freertos_addrinfo * pxNew_AddrInfo( const char * pcName, 269 BaseType_t xFamily, 270 const uint8_t * pucAddress ) 271 { 272 struct freertos_addrinfo * pxAddrInfo = NULL; 273 void * pvBuffer; 274 275 /* 'xFamily' might not be used when IPv6 is disabled. */ 276 ( void ) xFamily; 277 pvBuffer = pvPortMalloc( sizeof( *pxAddrInfo ) ); 278 279 if( pvBuffer != NULL ) 280 { 281 pxAddrInfo = ( struct freertos_addrinfo * ) pvBuffer; 282 283 ( void ) memset( pxAddrInfo, 0, sizeof( *pxAddrInfo ) ); 284 pxAddrInfo->ai_canonname = pxAddrInfo->xPrivateStorage.ucName; 285 ( void ) strncpy( pxAddrInfo->xPrivateStorage.ucName, pcName, sizeof( pxAddrInfo->xPrivateStorage.ucName ) ); 286 287 pxAddrInfo->ai_addr = ( ( struct freertos_sockaddr * ) &( pxAddrInfo->xPrivateStorage.sockaddr ) ); 288 289 switch( xFamily ) 290 { 291 #if ( ipconfigUSE_IPv4 != 0 ) 292 case FREERTOS_AF_INET4: 293 { 294 /* ulChar2u32 reads from big-endian to host-endian. */ 295 uint32_t ulIPAddress = ulChar2u32( pucAddress ); 296 /* Translate to network-endian. */ 297 pxAddrInfo->ai_addr->sin_address.ulIP_IPv4 = FreeRTOS_htonl( ulIPAddress ); 298 pxAddrInfo->ai_family = FREERTOS_AF_INET4; 299 pxAddrInfo->ai_addrlen = ipSIZE_OF_IPv4_ADDRESS; 300 } 301 break; 302 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 303 304 #if ( ipconfigUSE_IPv6 != 0 ) 305 case FREERTOS_AF_INET6: 306 pxAddrInfo->ai_family = FREERTOS_AF_INET6; 307 pxAddrInfo->ai_addrlen = ipSIZE_OF_IPv6_ADDRESS; 308 ( void ) memcpy( pxAddrInfo->xPrivateStorage.sockaddr.sin_address.xIP_IPv6.ucBytes, pucAddress, ipSIZE_OF_IPv6_ADDRESS ); 309 break; 310 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 311 312 default: 313 /* MISRA 16.4 Compliance */ 314 FreeRTOS_debug_printf( ( "pxNew_AddrInfo: Undefined xFamily Type \n" ) ); 315 316 vPortFree( pvBuffer ); 317 pxAddrInfo = NULL; 318 319 break; 320 } 321 } 322 323 return pxAddrInfo; 324 } 325 /*-----------------------------------------------------------*/ 326 327 /** 328 * @brief Free a chain of structs of type 'freertos_addrinfo'. 329 * @param[in] pxInfo The first find result. 330 */ FreeRTOS_freeaddrinfo(struct freertos_addrinfo * pxInfo)331 void FreeRTOS_freeaddrinfo( struct freertos_addrinfo * pxInfo ) 332 { 333 struct freertos_addrinfo * pxNext; 334 struct freertos_addrinfo * pxIterator = pxInfo; 335 336 if( pxInfo != NULL ) 337 { 338 while( pxIterator != NULL ) 339 { 340 pxNext = pxIterator->ai_next; 341 vPortFree( pxIterator ); 342 pxIterator = pxNext; 343 } 344 } 345 } 346 /*-----------------------------------------------------------*/ 347 348 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 349 350 /** 351 * @brief Asynchronous version of getaddrinfo(). 352 * 353 * @param[in] pcName The name of the node or device 354 * @param[in] pcService Ignored for now. 355 * @param[in] pxHints If not NULL preferences. Can be used to indicate the preferred type if IP ( v4 or v6 ). 356 * @param[out] ppxResult An allocated struct, containing the results. 357 * @param[in] pCallback A user-defined function which will be called on completion, either when found or after a time-out. 358 * @param[in] pvSearchID A user provided void pointer that will be communicated on completion. 359 * @param[in] uxTimeout The maximum number of clock ticks that must be waited for a reply. 360 * 361 * @return Zero when the operation was successful, otherwise a negative errno value. 362 */ FreeRTOS_getaddrinfo_a(const char * pcName,const char * pcService,const struct freertos_addrinfo * pxHints,struct freertos_addrinfo ** ppxResult,FOnDNSEvent pCallback,void * pvSearchID,TickType_t uxTimeout)363 BaseType_t FreeRTOS_getaddrinfo_a( const char * pcName, /* The name of the node or device */ 364 const char * pcService, /* Ignored for now. */ 365 const struct freertos_addrinfo * pxHints, /* If not NULL: preferences. */ 366 struct freertos_addrinfo ** ppxResult, /* An allocated struct, containing the results. */ 367 FOnDNSEvent pCallback, 368 void * pvSearchID, 369 TickType_t uxTimeout ) 370 #else 371 372 /** 373 * @brief Look-up the IP-address of a host. 374 * @param[in] pcName The name of the node or device 375 * @param[in] pcService Ignored for now. 376 * @param[in] pxHints If not NULL preferences. Can be used to indicate the preferred type if IP ( v4 or v6 ). 377 * @param[out] ppxResult An allocated struct, containing the results. 378 * @return Zero when the operation was successful, otherwise a negative errno value. 379 */ 380 BaseType_t FreeRTOS_getaddrinfo( const char * pcName, /* The name of the node or device */ 381 const char * pcService, /* Ignored for now. */ 382 const struct freertos_addrinfo * pxHints, /* If not NULL: preferences. */ 383 struct freertos_addrinfo ** ppxResult ) /* An allocated struct, containing the results. */ 384 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */ 385 { 386 BaseType_t xReturn = 0; 387 uint32_t ulResult; 388 BaseType_t xFamily = FREERTOS_AF_INET4; 389 390 ( void ) pcService; 391 ( void ) pxHints; 392 393 if( ppxResult != NULL ) 394 { 395 *( ppxResult ) = NULL; 396 397 #if ( ipconfigUSE_IPv6 != 0 ) 398 if( pxHints != NULL ) 399 { 400 if( pxHints->ai_family == FREERTOS_AF_INET6 ) 401 { 402 xFamily = FREERTOS_AF_INET6; 403 } 404 else if( pxHints->ai_family != FREERTOS_AF_INET4 ) 405 { 406 xReturn = -pdFREERTOS_ERRNO_EINVAL; 407 } 408 else 409 { 410 /* This is FREERTOS_AF_INET4, carry on. */ 411 } 412 } 413 #endif /* ( ipconfigUSE_IPv6 == 0 ) */ 414 415 #if ( ipconfigUSE_IPv6 != 0 ) 416 if( xReturn == 0 ) 417 #endif 418 { 419 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 420 { 421 ulResult = prvPrepareLookup( pcName, ppxResult, xFamily, pCallback, pvSearchID, uxTimeout ); 422 } 423 #else 424 { 425 ulResult = prvPrepareLookup( pcName, ppxResult, xFamily ); 426 } 427 #endif /* ( ipconfigDNS_USE_CALLBACKS == 1 ) */ 428 429 if( ulResult != 0U ) 430 { 431 if( *( ppxResult ) != NULL ) 432 { 433 xReturn = 0; 434 } 435 else 436 { 437 xReturn = -pdFREERTOS_ERRNO_ENOMEM; 438 } 439 } 440 else 441 { 442 xReturn = -pdFREERTOS_ERRNO_ENOENT; 443 } 444 } 445 } 446 else 447 { 448 xReturn = -pdFREERTOS_ERRNO_EINVAL; 449 } 450 451 return xReturn; 452 } 453 /*-----------------------------------------------------------*/ 454 455 #if ( ipconfigDNS_USE_CALLBACKS == 0 ) 456 457 /** 458 * @brief Get the IP-address corresponding to the given hostname. 459 * @param[in] pcHostName The hostname whose IP address is being queried. 460 * @return The IP-address corresponding to the hostname. 0 is returned in 461 * case of failure. 462 */ FreeRTOS_gethostbyname(const char * pcHostName)463 uint32_t FreeRTOS_gethostbyname( const char * pcHostName ) 464 { 465 return prvPrepareLookup( pcHostName, NULL, FREERTOS_AF_INET4 ); 466 } 467 #else 468 469 /** 470 * @brief Get the IP-address corresponding to the given hostname. 471 * @param[in] pcHostName The hostname whose IP address is being queried. 472 * @param[in] pCallback The callback function which will be called upon DNS response. It will be called 473 * with pcHostName, pvSearchID and pxAddressInfo which points to address info. 474 * The pxAddressInfo should be freed by the application once the callback 475 * has been called by the FreeRTOS_freeaddrinfo(). 476 * In case of timeouts pxAddressInfo can be NULL. 477 * @param[in] pvSearchID Search ID for the callback function. 478 * @param[in] uxTimeout Timeout for the callback function. 479 * @return The IP-address corresponding to the hostname. 0 is returned in case of 480 * failure. 481 */ FreeRTOS_gethostbyname_a(const char * pcHostName,FOnDNSEvent pCallback,void * pvSearchID,TickType_t uxTimeout)482 uint32_t FreeRTOS_gethostbyname_a( const char * pcHostName, 483 FOnDNSEvent pCallback, 484 void * pvSearchID, 485 TickType_t uxTimeout ) 486 { 487 uint32_t ulResult; 488 struct freertos_addrinfo * pxAddressInfo = NULL; 489 490 ulResult = prvPrepareLookup( pcHostName, &( pxAddressInfo ), FREERTOS_AF_INET4, pCallback, pvSearchID, uxTimeout ); 491 492 if( pxAddressInfo != NULL ) 493 { 494 FreeRTOS_freeaddrinfo( pxAddressInfo ); 495 } 496 497 return ulResult; 498 } 499 #endif /* if ( ipconfigDNS_USE_CALLBACKS == 0 ) */ 500 501 #if ( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) 502 503 /** 504 * @brief See if pcHostName contains a valid IPv4 or IPv6 IP-address. 505 * @param[in] pcHostName The name to be looked up 506 * @param[in] xFamily the IP-type, either FREERTOS_AF_INET4 or FREERTOS_AF_INET6. 507 * @param[in] ppxAddressInfo A pointer to a pointer where the find results will 508 * be stored. 509 * @return Either 0 or an IP=address. 510 */ prvPrepare_ReadIPAddress(const char * pcHostName,BaseType_t xFamily,struct freertos_addrinfo ** ppxAddressInfo)511 static uint32_t prvPrepare_ReadIPAddress( const char * pcHostName, 512 BaseType_t xFamily, 513 struct freertos_addrinfo ** ppxAddressInfo ) 514 { 515 uint32_t ulIPAddress = 0U; 516 517 ( void ) xFamily; 518 519 /* Check if the hostname given is actually an IP-address. */ 520 switch( xFamily ) /* LCOV_EXCL_BR_LINE - Family is always either FREERTOS_AF_INET or FREERTOS_AF_INET6. */ 521 { 522 #if ( ipconfigUSE_IPv4 != 0 ) 523 case FREERTOS_AF_INET: 524 ulIPAddress = FreeRTOS_inet_addr( pcHostName ); 525 526 if( ( ulIPAddress != 0U ) && ( ppxAddressInfo != NULL ) ) 527 { 528 const uint8_t * ucBytes = ( uint8_t * ) &( ulIPAddress ); 529 530 *( ppxAddressInfo ) = pxNew_AddrInfo( pcHostName, FREERTOS_AF_INET4, ucBytes ); 531 } 532 break; 533 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 534 535 #if ( ipconfigUSE_IPv6 != 0 ) 536 case FREERTOS_AF_INET6: 537 { 538 IPv6_Address_t xAddress_IPv6; 539 BaseType_t xResult; 540 541 /* ulIPAddress does not represent an IPv4 address here. It becomes non-zero when the look-up succeeds. */ 542 xResult = FreeRTOS_inet_pton6( pcHostName, xAddress_IPv6.ucBytes ); 543 544 if( xResult == 1 ) 545 { 546 /* This function returns either a valid IPv4 address, or 547 * in case of an IPv6 lookup, it will return a non-zero */ 548 ulIPAddress = 1U; 549 550 /* ppxAddressInfo is always non-NULL in IPv6 case. */ 551 *( ppxAddressInfo ) = pxNew_AddrInfo( pcHostName, FREERTOS_AF_INET6, xAddress_IPv6.ucBytes ); 552 } 553 } 554 break; 555 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 556 557 default: /* LCOV_EXCL_LINE - Family is always either FREERTOS_AF_INET or FREERTOS_AF_INET6. */ 558 /* MISRA 16.4 Compliance */ 559 FreeRTOS_debug_printf( ( "prvPrepare_ReadIPAddress: Undefined xFamily Type \n" ) ); 560 break; /* LCOV_EXCL_LINE - Family is always either FREERTOS_AF_INET or FREERTOS_AF_INET6. */ 561 } 562 563 return ulIPAddress; 564 } 565 #endif /* ( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) */ 566 /*-----------------------------------------------------------*/ 567 568 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 569 570 /** 571 * @brief Check if hostname is already known. If not, call prvGetHostByName() to send a DNS request. 572 * 573 * @param[in] pcHostName The hostname whose IP address is being queried. 574 * @param[in,out] ppxAddressInfo A pointer to a pointer where the find results 575 * will be stored. 576 * @param [in] xFamily indicate what type of record is needed: 577 * FREERTOS_AF_INET4 or FREERTOS_AF_INET6. 578 * @param[in] pCallbackFunction The callback function which will be called upon DNS response. 579 * @param[in] pvSearchID Search ID for the callback function. 580 * @param[in] uxTimeout Timeout for the callback function. 581 * @return The IP-address corresponding to the hostname. 582 */ prvPrepareLookup(const char * pcHostName,struct freertos_addrinfo ** ppxAddressInfo,BaseType_t xFamily,FOnDNSEvent pCallbackFunction,void * pvSearchID,TickType_t uxTimeout)583 static uint32_t prvPrepareLookup( const char * pcHostName, 584 struct freertos_addrinfo ** ppxAddressInfo, 585 BaseType_t xFamily, 586 FOnDNSEvent pCallbackFunction, 587 void * pvSearchID, 588 TickType_t uxTimeout ) 589 #else 590 591 /** 592 * @brief Check if hostname is already known. If not, call prvGetHostByName() to send a DNS request. 593 * @param[in] pcHostName The hostname whose IP address is being queried. 594 * @return The IP-address corresponding to the hostname. 595 */ 596 static uint32_t prvPrepareLookup( const char * pcHostName, 597 struct freertos_addrinfo ** ppxAddressInfo, 598 BaseType_t xFamily ) 599 #endif /* if ( ipconfigDNS_USE_CALLBACKS == 1 ) */ 600 { 601 uint32_t ulIPAddress = 0U; 602 TickType_t uxReadTimeOut_ticks = ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS; 603 604 /* Generate a unique identifier for this query. Keep it in a local variable 605 * as gethostbyname() may be called from different threads */ 606 BaseType_t xHasRandom = pdFALSE; 607 TickType_t uxIdentifier = 0U; 608 609 #if ( ipconfigUSE_DNS_CACHE != 0 ) 610 BaseType_t xLengthOk = pdFALSE; 611 #endif 612 613 #if ( ipconfigUSE_DNS_CACHE != 0 ) 614 { 615 if( pcHostName != NULL ) 616 { 617 size_t uxLength = strlen( pcHostName ) + 1U; 618 619 if( uxLength <= ipconfigDNS_CACHE_NAME_LENGTH ) 620 { 621 /* The name is not too long. */ 622 xLengthOk = pdTRUE; 623 } 624 else 625 { 626 FreeRTOS_printf( ( "prvPrepareLookup: name is too long ( %u > %u )\n", 627 ( unsigned ) uxLength, 628 ( unsigned ) ipconfigDNS_CACHE_NAME_LENGTH ) ); 629 } 630 } 631 } 632 633 if( ( pcHostName != NULL ) && ( xLengthOk != pdFALSE ) ) 634 #else /* if ( ipconfigUSE_DNS_CACHE != 0 ) */ 635 if( pcHostName != NULL ) 636 #endif /* ( ipconfigUSE_DNS_CACHE != 0 ) */ 637 { 638 /* If the supplied hostname is an IP address, put it in ppxAddressInfo 639 * and return. */ 640 #if ( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) 641 { 642 ulIPAddress = prvPrepare_ReadIPAddress( pcHostName, xFamily, ppxAddressInfo ); 643 } 644 #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */ 645 646 /* If a DNS cache is used then check the cache before issuing another DNS 647 * request. */ 648 #if ( ipconfigUSE_DNS_CACHE == 1 ) 649 /* Check the cache before issuing another DNS request. */ 650 if( ulIPAddress == 0U ) 651 { 652 ulIPAddress = Prepare_CacheLookup( pcHostName, xFamily, ppxAddressInfo ); 653 654 if( ulIPAddress != 0UL ) 655 { 656 #if ( ipconfigUSE_IPv6 != 0 ) 657 if( ( ppxAddressInfo != NULL ) && ( ( *ppxAddressInfo )->ai_family == FREERTOS_AF_INET6 ) ) 658 { 659 FreeRTOS_printf( ( "prvPrepareLookup: found '%s' in cache: %pip\n", 660 pcHostName, ( void * ) ( *ppxAddressInfo )->xPrivateStorage.sockaddr.sin_address.xIP_IPv6.ucBytes ) ); 661 } 662 else 663 #endif 664 { 665 FreeRTOS_printf( ( "prvPrepareLookup: found '%s' in cache: %xip\n", pcHostName, ( unsigned ) ulIPAddress ) ); 666 } 667 } 668 } 669 #endif /* ipconfigUSE_DNS_CACHE == 1 */ 670 671 /* Generate a unique identifier. */ 672 if( ulIPAddress == 0U ) 673 { 674 uint32_t ulNumber; 675 676 xHasRandom = xApplicationGetRandomNumber( &( ulNumber ) ); 677 /* DNS identifiers are 16-bit. */ 678 uxIdentifier = ( TickType_t ) ( ulNumber & 0xffffU ); 679 } 680 681 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 682 { 683 if( pCallbackFunction != NULL ) 684 { 685 if( ulIPAddress == 0U ) 686 { 687 /* The user has provided a callback function, so do not block on recvfrom() */ 688 if( xHasRandom != pdFALSE ) 689 { 690 uxReadTimeOut_ticks = 0U; 691 vDNSSetCallBack( pcHostName, 692 pvSearchID, 693 pCallbackFunction, 694 uxTimeout, 695 ( TickType_t ) uxIdentifier, 696 ( xFamily == FREERTOS_AF_INET6 ) ? pdTRUE : pdFALSE ); 697 } 698 } 699 else /* When ipconfigDNS_USE_CALLBACKS enabled, ppxAddressInfo is always non null. */ 700 { 701 /* The IP address is known, do the call-back now. */ 702 pCallbackFunction( pcHostName, pvSearchID, *( ppxAddressInfo ) ); 703 } 704 } 705 } 706 #endif /* if ( ipconfigDNS_USE_CALLBACKS == 1 ) */ 707 708 if( ( ulIPAddress == 0U ) && ( xHasRandom != pdFALSE ) ) 709 { 710 ulIPAddress = prvGetHostByName( pcHostName, 711 uxIdentifier, 712 uxReadTimeOut_ticks, 713 ppxAddressInfo, 714 xFamily ); 715 } 716 } 717 718 return ulIPAddress; 719 } 720 /*-----------------------------------------------------------*/ 721 722 #if ( ipconfigUSE_IPv6 != 0 ) 723 724 /** 725 * @brief Increment the field 'ucDNSIndex', which is an index in the array 726 * of DNS addresses. 727 * @param[in] pxEndPoint The end-point of which the DNS index should be 728 * incremented. 729 */ prvIncreaseDNS6Index(NetworkEndPoint_t * pxEndPoint)730 static void prvIncreaseDNS6Index( NetworkEndPoint_t * pxEndPoint ) 731 { 732 uint8_t ucIndex = pxEndPoint->ipv6_settings.ucDNSIndex; 733 uint8_t ucInitialIndex = ucIndex; 734 735 for( ; ; ) 736 { 737 ucIndex++; 738 739 if( ucIndex >= ( uint8_t ) ipconfigENDPOINT_DNS_ADDRESS_COUNT ) 740 { 741 ucIndex = 0U; 742 } 743 744 if( ( pxEndPoint->ipv6_settings.xDNSServerAddresses[ ucIndex ].ucBytes[ 0 ] != 0U ) || 745 ( ucInitialIndex == ucIndex ) ) 746 { 747 break; 748 } 749 } 750 751 FreeRTOS_printf( ( "prvIncreaseDNS6Index: from %d to %d\n", ( int ) ucInitialIndex, ( int ) ucIndex ) ); 752 pxEndPoint->ipv6_settings.ucDNSIndex = ucIndex; 753 } 754 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 755 /*-----------------------------------------------------------*/ 756 757 #if ( ipconfigUSE_IPv4 != 0 ) 758 759 /** 760 * @brief Increment the field 'ucDNSIndex', which is an index in the array 761 * of DNS addresses. 762 * @param[in] pxEndPoint The end-point of which the DNS index should be 763 * incremented. 764 */ prvIncreaseDNS4Index(NetworkEndPoint_t * pxEndPoint)765 static void prvIncreaseDNS4Index( NetworkEndPoint_t * pxEndPoint ) 766 { 767 uint8_t ucIndex = pxEndPoint->ipv4_settings.ucDNSIndex; 768 uint8_t ucInitialIndex = ucIndex; 769 770 for( ; ; ) 771 { 772 ucIndex++; 773 774 if( ucIndex >= ( uint8_t ) ipconfigENDPOINT_DNS_ADDRESS_COUNT ) 775 { 776 ucIndex = 0U; 777 } 778 779 if( ( pxEndPoint->ipv4_settings.ulDNSServerAddresses[ ucIndex ] != 0U ) || 780 ( ucInitialIndex == ucIndex ) ) 781 { 782 break; 783 } 784 } 785 786 FreeRTOS_printf( ( "prvIncreaseDNS4Index: from %d to %d\n", ( int ) ucInitialIndex, ( int ) ucIndex ) ); 787 pxEndPoint->ipv4_settings.ucDNSIndex = ucIndex; 788 } 789 /*-----------------------------------------------------------*/ 790 #endif /* #if ( ipconfigUSE_IPv4 != 0 ) */ 791 792 /*! 793 * @brief create a payload buffer and return it through the parameter 794 * @param [out] ppxNetworkBuffer network buffer to create 795 * @param [in] pcHostName hostname to get its length 796 * @param [in] uxHeaderBytes Size of the header (IPv4/IPv6) 797 * @returns pointer address to the payload buffer 798 * 799 */ prvGetPayloadBuffer(NetworkBufferDescriptor_t ** ppxNetworkBuffer,const char * pcHostName,size_t uxHeaderBytes)800 static uint8_t * prvGetPayloadBuffer( NetworkBufferDescriptor_t ** ppxNetworkBuffer, 801 const char * pcHostName, 802 size_t uxHeaderBytes ) 803 { 804 size_t uxExpectedPayloadLength; 805 uint8_t * pucUDPPayloadBuffer = NULL; 806 807 uxExpectedPayloadLength = sizeof( DNSMessage_t ) + 808 strlen( pcHostName ) + 809 sizeof( uint16_t ) + 810 sizeof( uint16_t ) + 2U; 811 812 /* Get a buffer. This uses a maximum delay, but the delay will be 813 * capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value 814 * still needs to be tested. */ 815 *ppxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxExpectedPayloadLength + 816 uxHeaderBytes, 817 0U ); 818 819 if( *ppxNetworkBuffer != NULL ) 820 { 821 pucUDPPayloadBuffer = &( ( *ppxNetworkBuffer )->pucEthernetBuffer[ uxHeaderBytes ] ); 822 } 823 824 return pucUDPPayloadBuffer; 825 } 826 827 /*! 828 * @brief fill pxAddress from pucUDPPayloadBuffer 829 * @param [out] pxAddress ip address and port ... structure 830 * @param [in] pcHostName hostname to get its length 831 * @return The end-point that holds the DNS address. 832 */ prvFillSockAddress(struct freertos_sockaddr * pxAddress,const char * pcHostName)833 static NetworkEndPoint_t * prvFillSockAddress( struct freertos_sockaddr * pxAddress, 834 const char * pcHostName ) 835 { 836 NetworkEndPoint_t * pxEndPoint = NULL; 837 838 #if ( ipconfigUSE_MDNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) 839 BaseType_t xNeed_Endpoint = pdFALSE; 840 #endif 841 842 #if ( ipconfigUSE_LLMNR != 1 ) 843 ( void ) pcHostName; 844 #endif 845 846 /* Make sure all fields of the 'sockaddr' are cleared. */ 847 ( void ) memset( ( void * ) pxAddress, 0, sizeof( *pxAddress ) ); 848 849 /* And set the address type to IPv4. 850 * It may change to IPv6 in case an IPv6 DNS server will be used. */ 851 pxAddress->sin_family = FREERTOS_AF_INET; 852 853 /* 'sin_len' doesn't really matter, 'sockaddr' and 'sockaddr6' 854 * have the same size. */ 855 pxAddress->sin_len = ( uint8_t ) sizeof( struct freertos_sockaddr ); 856 /* Use the DNS port by default, this may be changed later. */ 857 pxAddress->sin_port = dnsDNS_PORT; 858 859 /* If LLMNR is being used then determine if the host name includes a '.' - 860 * if not then LLMNR can be used as the lookup method. */ 861 /* For local resolution, mDNS uses names ending with the string ".local" */ 862 BaseType_t bHasDot = pdFALSE; 863 BaseType_t bHasLocal = pdFALSE; 864 const char * pcDot = ( const char * ) strchr( pcHostName, ( int32_t ) '.' ); 865 866 if( pcDot != NULL ) 867 { 868 bHasDot = pdTRUE; 869 870 if( strcmp( pcDot, ".local" ) == 0 ) 871 { 872 bHasLocal = pdTRUE; 873 } 874 else 875 { 876 /* a DNS look-up of a public URL with at least one dot. */ 877 } 878 } 879 880 /* Is this a local lookup? */ 881 if( ( bHasDot == pdFALSE ) || ( bHasLocal == pdTRUE ) ) 882 { 883 /* Looking for e.g. "mydevice" or "mydevice.local", 884 * while using either mDNS or LLMNR. */ 885 #if ( ipconfigUSE_MDNS == 1 ) 886 { 887 if( bHasLocal ) 888 { 889 /* Looking up a name like "mydevice.local". 890 * Use mDNS addresses. */ 891 892 pxAddress->sin_port = ipMDNS_PORT; 893 pxAddress->sin_port = FreeRTOS_ntohs( pxAddress->sin_port ); 894 xNeed_Endpoint = pdTRUE; 895 896 switch( xDNS_IP_Preference ) 897 { 898 #if ( ipconfigUSE_IPv4 != 0 ) 899 case xPreferenceIPv4: 900 pxAddress->sin_address.ulIP_IPv4 = ipMDNS_IP_ADDRESS; /* Is in network byte order. */ 901 /* sin_family is default set to FREERTOS_AF_INET */ 902 break; 903 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 904 905 #if ( ipconfigUSE_IPv6 != 0 ) 906 case xPreferenceIPv6: 907 memcpy( pxAddress->sin_address.xIP_IPv6.ucBytes, 908 ipMDNS_IP_ADDR_IPv6.ucBytes, 909 ipSIZE_OF_IPv6_ADDRESS ); 910 pxAddress->sin_family = FREERTOS_AF_INET6; 911 break; 912 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 913 914 default: 915 /* MISRA 16.4 Compliance */ 916 xNeed_Endpoint = pdFALSE; 917 FreeRTOS_debug_printf( ( "prvFillSockAddress: Undefined xDNS_IP_Preference \n" ) ); 918 break; 919 } 920 } 921 } 922 #endif /* if ( ipconfigUSE_MDNS == 1 ) */ 923 #if ( ipconfigUSE_LLMNR == 1 ) 924 { 925 /* The hostname doesn't have a dot. */ 926 if( bHasDot == pdFALSE ) 927 { 928 /* Use LLMNR addressing. */ 929 pxAddress->sin_port = ipLLMNR_PORT; 930 pxAddress->sin_port = FreeRTOS_ntohs( pxAddress->sin_port ); 931 xNeed_Endpoint = pdTRUE; 932 933 switch( xDNS_IP_Preference ) 934 { 935 #if ( ipconfigUSE_IPv4 != 0 ) 936 case xPreferenceIPv4: 937 pxAddress->sin_address.ulIP_IPv4 = ipLLMNR_IP_ADDR; /* Is in network byte order. */ 938 pxAddress->sin_family = FREERTOS_AF_INET; 939 break; 940 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 941 942 #if ( ipconfigUSE_IPv6 != 0 ) 943 case xPreferenceIPv6: 944 memcpy( pxAddress->sin_address.xIP_IPv6.ucBytes, 945 ipLLMNR_IP_ADDR_IPv6.ucBytes, 946 ipSIZE_OF_IPv6_ADDRESS ); 947 pxAddress->sin_family = FREERTOS_AF_INET6; 948 break; 949 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 950 951 default: 952 /* MISRA 16.4 Compliance */ 953 xNeed_Endpoint = pdFALSE; 954 FreeRTOS_debug_printf( ( "prvFillSockAddress: Undefined xDNS_IP_Preference (LLMNR) \n" ) ); 955 break; 956 } 957 } 958 } 959 #endif /* if ( ipconfigUSE_LLMNR == 1 ) */ 960 961 #if ( ipconfigUSE_MDNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) 962 if( xNeed_Endpoint == pdTRUE ) 963 { 964 for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL ); 965 pxEndPoint != NULL; 966 pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) ) 967 { 968 #if ( ipconfigUSE_IPv6 != 0 ) 969 if( xDNS_IP_Preference == xPreferenceIPv6 ) 970 { 971 if( pxEndPoint->bits.bIPv6 != 0U ) 972 { 973 break; 974 } 975 } 976 else 977 { 978 #if ( ipconfigUSE_IPv4 != 0 ) 979 if( pxEndPoint->bits.bIPv6 == 0U ) 980 { 981 break; 982 } 983 #endif /* if ( ipconfigUSE_IPv4 != 0 ) */ 984 } 985 #else /* if ( ipconfigUSE_IPv6 != 0 ) */ 986 /* IPv6 is not included, so all end-points are IPv4. */ 987 break; 988 #endif /* if ( ipconfigUSE_IPv6 != 0 ) */ 989 } 990 } 991 #endif /* if ( ipconfigUSE_MDNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) */ 992 } 993 else 994 { 995 BaseType_t xBreakLoop = pdFALSE; 996 997 /* Look for an end-point that has defined a DNS server address. */ 998 for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL ); 999 pxEndPoint != NULL; 1000 pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) ) 1001 { 1002 switch( xDNS_IP_Preference ) 1003 { 1004 #if ( ipconfigUSE_IPv4 != 0 ) 1005 case xPreferenceIPv4: 1006 1007 if( pxEndPoint->bits.bIPv6 == 0U ) 1008 { 1009 uint8_t ucIndex = pxEndPoint->ipv4_settings.ucDNSIndex; 1010 configASSERT( ucIndex < ipconfigENDPOINT_DNS_ADDRESS_COUNT ); 1011 uint32_t ulIPAddress = pxEndPoint->ipv4_settings.ulDNSServerAddresses[ ucIndex ]; 1012 1013 if( ( ulIPAddress != 0U ) && ( ulIPAddress != ipBROADCAST_IP_ADDRESS ) ) 1014 { 1015 pxAddress->sin_family = FREERTOS_AF_INET; 1016 pxAddress->sin_len = ( uint8_t ) sizeof( struct freertos_sockaddr ); 1017 pxAddress->sin_address.ulIP_IPv4 = ulIPAddress; 1018 xBreakLoop = pdTRUE; 1019 } 1020 } 1021 break; 1022 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 1023 1024 #if ( ipconfigUSE_IPv6 != 0 ) 1025 case xPreferenceIPv6: 1026 1027 if( pxEndPoint->bits.bIPv6 != 0U ) 1028 { 1029 uint8_t ucIndex = pxEndPoint->ipv6_settings.ucDNSIndex; 1030 configASSERT( ucIndex < ipconfigENDPOINT_DNS_ADDRESS_COUNT ); 1031 const uint8_t * ucBytes = pxEndPoint->ipv6_settings.xDNSServerAddresses[ ucIndex ].ucBytes; 1032 1033 /* Test if the DNS entry is in used. */ 1034 if( ( ucBytes[ 0 ] != 0U ) && ( ucBytes[ 1 ] != 0U ) ) 1035 { 1036 pxAddress->sin_family = FREERTOS_AF_INET6; 1037 pxAddress->sin_len = ( uint8_t ) sizeof( struct freertos_sockaddr ); 1038 ( void ) memcpy( pxAddress->sin_address.xIP_IPv6.ucBytes, 1039 pxEndPoint->ipv6_settings.xDNSServerAddresses[ ucIndex ].ucBytes, 1040 ipSIZE_OF_IPv6_ADDRESS ); 1041 xBreakLoop = pdTRUE; 1042 } 1043 } 1044 break; 1045 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 1046 1047 default: 1048 /* MISRA 16.4 Compliance */ 1049 FreeRTOS_debug_printf( ( "prvFillSockAddress: Undefined xDNS_IP_Preference \n" ) ); 1050 break; 1051 } 1052 1053 if( xBreakLoop == pdTRUE ) 1054 { 1055 break; 1056 } 1057 } 1058 } 1059 1060 return pxEndPoint; 1061 } 1062 1063 /*! 1064 * @brief return ip address from the dns reply message 1065 * @param [in] pxReceiveBuffer received buffer from the DNS server 1066 * @param[in,out] ppxAddressInfo A pointer to a pointer where the find results 1067 * will be stored. 1068 * @param [in] uxIdentifier matches sent and received packets 1069 * @param [in] usPort Port from which DNS reply was read 1070 * @returns ip address or zero on error 1071 * 1072 */ prvDNSReply(const struct xDNSBuffer * pxReceiveBuffer,struct freertos_addrinfo ** ppxAddressInfo,TickType_t uxIdentifier,uint16_t usPort)1073 static uint32_t prvDNSReply( const struct xDNSBuffer * pxReceiveBuffer, 1074 struct freertos_addrinfo ** ppxAddressInfo, 1075 TickType_t uxIdentifier, 1076 uint16_t usPort ) 1077 { 1078 uint32_t ulIPAddress = 0U; 1079 BaseType_t xExpected; 1080 1081 /* MISRA Ref 11.3.1 [Misaligned access] */ 1082 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1083 /* coverity[misra_c_2012_rule_11_3_violation] */ 1084 const DNSMessage_t * pxDNSMessageHeader = 1085 ( ( const DNSMessage_t * ) 1086 pxReceiveBuffer->pucPayloadBuffer ); 1087 1088 #if ( ipconfigUSE_MDNS == 1 ) 1089 /* _HT_ changed 'pxReceiveBuffer->sin_port' to 'usPort' */ 1090 if( FreeRTOS_ntohs( usPort ) == ipMDNS_PORT ) /* mDNS port 5353. */ 1091 { 1092 /* In mDNS, the query ID field is ignored. */ 1093 xExpected = pdTRUE; 1094 } 1095 else 1096 #endif /* if ( ipconfigUSE_MDNS == 1 ) */ 1097 1098 /* See if the identifiers match. */ 1099 if( uxIdentifier == ( TickType_t ) pxDNSMessageHeader->usIdentifier ) 1100 { 1101 xExpected = pdTRUE; 1102 } 1103 else 1104 { 1105 xExpected = pdFALSE; 1106 } 1107 1108 /* The reply was received. Process it. */ 1109 #if ( ipconfigDNS_USE_CALLBACKS == 0 ) 1110 1111 /* It is useless to analyse the unexpected reply 1112 * unless asynchronous look-ups are enabled. */ 1113 if( xExpected != pdFALSE ) 1114 #endif /* ipconfigDNS_USE_CALLBACKS == 0 */ 1115 { 1116 ulIPAddress = DNS_ParseDNSReply( pxReceiveBuffer->pucPayloadBuffer, 1117 pxReceiveBuffer->uxPayloadLength, 1118 ppxAddressInfo, 1119 xExpected, 1120 usPort ); 1121 } 1122 1123 return ulIPAddress; 1124 } 1125 1126 /*! 1127 * @brief prepare the buffer before sending 1128 * @param [in] pcHostName hostname to be looked up 1129 * @param [in] uxIdentifier matches sent and received packets 1130 * @param [in] xDNSSocket a valid socket 1131 * @param [in] xFamily indicate what type of record is needed: 1132 * FREERTOS_AF_INET4 or FREERTOS_AF_INET6. 1133 * @param [in] pxAddress address structure 1134 * @returns pdTRUE if sending the data was successful, pdFALSE otherwise. 1135 */ prvSendBuffer(const char * pcHostName,TickType_t uxIdentifier,Socket_t xDNSSocket,BaseType_t xFamily,const struct freertos_sockaddr * pxAddress)1136 static BaseType_t prvSendBuffer( const char * pcHostName, 1137 TickType_t uxIdentifier, 1138 Socket_t xDNSSocket, 1139 BaseType_t xFamily, 1140 const struct freertos_sockaddr * pxAddress ) 1141 { 1142 BaseType_t xReturn = pdFAIL; 1143 struct xDNSBuffer xDNSBuf = { 0 }; 1144 NetworkBufferDescriptor_t * pxNetworkBuffer = NULL; 1145 size_t uxHeaderBytes; 1146 UBaseType_t uxHostType; 1147 1148 /* Calculate the size of the headers. */ 1149 if( pxAddress->sin_family == ( uint8_t ) FREERTOS_AF_INET6 ) 1150 { 1151 uxHeaderBytes = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + ipSIZE_OF_UDP_HEADER; 1152 } 1153 else 1154 { 1155 uxHeaderBytes = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER; 1156 } 1157 1158 if( xFamily == FREERTOS_AF_INET6 ) 1159 { 1160 /* Note that 'dnsTYPE_ANY_HOST' could be used here as well, 1161 * but for testing, we want an IPv6 address. */ 1162 uxHostType = dnsTYPE_AAAA_HOST; 1163 } 1164 else 1165 { 1166 uxHostType = dnsTYPE_A_HOST; 1167 } 1168 1169 /*get dns message buffer */ 1170 xDNSBuf.pucPayloadBuffer = prvGetPayloadBuffer( &pxNetworkBuffer, 1171 pcHostName, uxHeaderBytes ); 1172 1173 if( xDNSBuf.pucPayloadBuffer != NULL ) 1174 { 1175 #if ( ipconfigUSE_LLMNR == 1 ) 1176 { 1177 if( FreeRTOS_ntohs( pxAddress->sin_port ) == ipLLMNR_PORT ) 1178 { 1179 /* MISRA Ref 11.3.1 [Misaligned access] */ 1180 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1181 /* coverity[misra_c_2012_rule_11_3_violation] */ 1182 ( ( ( DNSMessage_t * ) xDNSBuf.pucPayloadBuffer ) )->usFlags = 0; 1183 } 1184 } 1185 #endif 1186 1187 /* A two-step conversion to conform to MISRA. */ 1188 size_t uxIndex = ipUDP_PAYLOAD_IP_TYPE_OFFSET; 1189 BaseType_t xIndex = ( BaseType_t ) uxIndex; 1190 1191 /* Later when translating form UDP payload to a Network Buffer, 1192 * it is important to know whether this is an IPv4 packet. */ 1193 if( pxAddress->sin_family == ( uint8_t ) FREERTOS_AF_INET6 ) 1194 { 1195 xDNSBuf.pucPayloadBuffer[ -xIndex ] = ( uint8_t ) ipTYPE_IPv6; 1196 } 1197 else 1198 { 1199 xDNSBuf.pucPayloadBuffer[ -xIndex ] = ( uint8_t ) ipTYPE_IPv4; 1200 } 1201 1202 xDNSBuf.uxPayloadLength = prvCreateDNSMessage( xDNSBuf.pucPayloadBuffer, 1203 pcHostName, 1204 uxIdentifier, 1205 uxHostType ); 1206 1207 /* ipLLMNR_IP_ADDR is in network byte order. */ 1208 if( ( pxAddress->sin_address.ulIP_IPv4 == ipLLMNR_IP_ADDR ) || ( pxAddress->sin_address.ulIP_IPv4 == ipMDNS_IP_ADDRESS ) ) 1209 { 1210 /* Use LLMNR addressing. */ 1211 /* MISRA Ref 11.3.1 [Misaligned access] */ 1212 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1213 /* coverity[misra_c_2012_rule_11_3_violation] */ 1214 ( ( ( DNSMessage_t * ) xDNSBuf.pucPayloadBuffer ) )->usFlags = 0; 1215 } 1216 1217 /* send the dns message */ 1218 xReturn = DNS_SendRequest( xDNSSocket, 1219 pxAddress, 1220 &xDNSBuf ); 1221 1222 if( xReturn == pdFAIL ) 1223 { 1224 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); 1225 } 1226 } 1227 1228 return xReturn; 1229 } 1230 1231 /*! 1232 * @brief main dns operation description function 1233 * @param [in] pcHostName hostname to get its ip address 1234 * @param [in] uxIdentifier Identifier to match sent and received packets 1235 * @param [in] xDNSSocket socket 1236 * @param[in,out] ppxAddressInfo A pointer to a pointer where the find results 1237 * will be stored. 1238 * @param[in] xFamily Either FREERTOS_AF_INET4 or FREERTOS_AF_INET6. 1239 * @param[in] uxReadTimeOut_ticks The timeout in ticks for waiting. In case the user has supplied 1240 * a call-back function, this value should be zero. 1241 * @returns ip address or zero on error 1242 */ prvGetHostByNameOp(const char * pcHostName,TickType_t uxIdentifier,Socket_t xDNSSocket,struct freertos_addrinfo ** ppxAddressInfo,BaseType_t xFamily,TickType_t uxReadTimeOut_ticks)1243 static uint32_t prvGetHostByNameOp( const char * pcHostName, 1244 TickType_t uxIdentifier, 1245 Socket_t xDNSSocket, 1246 struct freertos_addrinfo ** ppxAddressInfo, 1247 BaseType_t xFamily, 1248 TickType_t uxReadTimeOut_ticks ) 1249 { 1250 uint32_t ulIPAddress = 0; 1251 struct freertos_sockaddr xAddress; 1252 struct freertos_sockaddr xRecvAddress; 1253 DNSBuffer_t xReceiveBuffer = { 0 }; 1254 BaseType_t xReturn = pdFAIL; 1255 BaseType_t xBytes; 1256 NetworkEndPoint_t * pxEndPoint; 1257 1258 /* Make sure all fields of the 'sockaddr' are cleared. */ 1259 ( void ) memset( ( void * ) &xAddress, 0, sizeof( xAddress ) ); 1260 1261 #if ( ipconfigUSE_IPv6 != 0 ) 1262 if( xFamily == ( BaseType_t ) FREERTOS_AF_INET6 ) 1263 { 1264 xDNS_IP_Preference = xPreferenceIPv6; 1265 } 1266 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 1267 1268 pxEndPoint = prvFillSockAddress( &xAddress, pcHostName ); 1269 1270 if( pxEndPoint != NULL ) 1271 { 1272 do 1273 { 1274 if( xDNSSocket->usLocalPort == 0U ) 1275 { 1276 /* Bind the client socket to a random port number. */ 1277 uint16_t usPort = 0U; 1278 #if ( ipconfigUSE_MDNS == 1 ) 1279 if( xAddress.sin_port == FreeRTOS_htons( ipMDNS_PORT ) ) 1280 { 1281 /* For a mDNS lookup, bind to the mDNS port 5353. */ 1282 usPort = FreeRTOS_htons( ipMDNS_PORT ); 1283 } 1284 #endif 1285 1286 if( DNS_BindSocket( xDNSSocket, usPort ) != 0 ) 1287 { 1288 FreeRTOS_printf( ( "DNS bind to %u failed\n", FreeRTOS_ntohs( usPort ) ) ); 1289 break; 1290 } 1291 } 1292 1293 xReturn = prvSendBuffer( pcHostName, 1294 uxIdentifier, 1295 xDNSSocket, 1296 xFamily, 1297 &xAddress ); 1298 1299 if( xReturn == pdFAIL ) 1300 { 1301 break; 1302 } 1303 1304 /* Create the message in the obtained buffer. */ 1305 1306 /* receive a dns reply message */ 1307 xBytes = DNS_ReadReply( xDNSSocket, 1308 &xRecvAddress, 1309 &xReceiveBuffer ); 1310 1311 if( ( uxReadTimeOut_ticks > 0U ) && 1312 ( ( xBytes == -pdFREERTOS_ERRNO_EWOULDBLOCK ) || 1313 ( xBytes == 0 ) ) ) 1314 { 1315 /* This search timed out, next time try with a different DNS. */ 1316 switch( xAddress.sin_family ) /* LCOV_EXCL_BR_LINE - This is filled by static function, default case is impossible to reach. */ 1317 { 1318 #if ( ipconfigUSE_IPv4 != 0 ) 1319 case FREERTOS_AF_INET: 1320 prvIncreaseDNS4Index( pxEndPoint ); 1321 break; 1322 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 1323 1324 #if ( ipconfigUSE_IPv6 != 0 ) 1325 case FREERTOS_AF_INET6: 1326 prvIncreaseDNS6Index( pxEndPoint ); 1327 break; 1328 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 1329 1330 default: /* LCOV_EXCL_LINE - This is filled by static function, default case is impossible to reach. */ 1331 /* MISRA 16.4 Compliance */ 1332 FreeRTOS_debug_printf( ( "prvGetHostByNameOp: Undefined sin_family \n" ) ); 1333 break; /* LCOV_EXCL_LINE - This is filled by static function, default case is impossible to reach. */ 1334 } 1335 } 1336 1337 if( xReceiveBuffer.pucPayloadBuffer != NULL ) 1338 { 1339 if( xBytes > 0 ) 1340 { 1341 xReceiveBuffer.uxPayloadLength = ( size_t ) xBytes; 1342 ulIPAddress = prvDNSReply( &xReceiveBuffer, ppxAddressInfo, uxIdentifier, xRecvAddress.sin_port ); 1343 } 1344 1345 /* Finished with the buffer. The zero copy interface 1346 * is being used, so the buffer must be freed by the 1347 * task. */ 1348 FreeRTOS_ReleaseUDPPayloadBuffer( xReceiveBuffer.pucPayloadBuffer ); 1349 } 1350 } while( ipFALSE_BOOL ); 1351 } 1352 else 1353 { 1354 /* No endpoint was found that defines a DNS address. */ 1355 FreeRTOS_printf( ( "Can not find a DNS address, along with an end-point.\n" ) ); 1356 } 1357 1358 return ulIPAddress; 1359 } 1360 1361 /*! 1362 * @brief helper function to prvGetHostByNameOP with multiple retries equal to 1363 * ipconfigDNS_REQUEST_ATTEMPTS 1364 * 1365 * @param [in] pcHostName hostname to get its ip address 1366 * @param [in] uxIdentifier Identifier to match sent and received packets 1367 * @param [in] xDNSSocket socket 1368 * @param[in,out] ppxAddressInfo A pointer to a pointer where the find results 1369 * will be stored. 1370 * @param[in] xFamily Either FREERTOS_AF_INET4 or FREERTOS_AF_INET6. 1371 * @param[in] uxReadTimeOut_ticks The timeout in ticks for waiting. In case the user has supplied 1372 * a call-back function, this value should be zero. 1373 * @returns ip address or zero on error 1374 * 1375 */ prvGetHostByNameOp_WithRetry(const char * pcHostName,TickType_t uxIdentifier,Socket_t xDNSSocket,struct freertos_addrinfo ** ppxAddressInfo,BaseType_t xFamily,TickType_t uxReadTimeOut_ticks)1376 static uint32_t prvGetHostByNameOp_WithRetry( const char * pcHostName, 1377 TickType_t uxIdentifier, 1378 Socket_t xDNSSocket, 1379 struct freertos_addrinfo ** ppxAddressInfo, 1380 BaseType_t xFamily, 1381 TickType_t uxReadTimeOut_ticks ) 1382 { 1383 uint32_t ulIPAddress = 0; 1384 BaseType_t xAttempt; 1385 1386 for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ ) 1387 { 1388 ulIPAddress = prvGetHostByNameOp( pcHostName, 1389 uxIdentifier, 1390 xDNSSocket, 1391 ppxAddressInfo, 1392 xFamily, 1393 uxReadTimeOut_ticks ); 1394 1395 if( ulIPAddress != 0U ) 1396 { /* ip found, no need to retry */ 1397 break; 1398 } 1399 } 1400 1401 return ulIPAddress; 1402 } 1403 1404 1405 /** 1406 * @brief Prepare and send a message to a DNS server. 'uxReadTimeOut_ticks' will be passed as 1407 * zero, in case the user has supplied a call-back function. 1408 * 1409 * @param[in] pcHostName The hostname for which an IP address is required. 1410 * @param[in] uxIdentifier Identifier to match sent and received packets 1411 * @param[in] uxReadTimeOut_ticks The timeout in ticks for waiting. In case the user has supplied 1412 * a call-back function, this value should be zero. 1413 * @param[in,out] ppxAddressInfo A pointer to a pointer where the find results 1414 * will be stored. 1415 * @param[in] xFamily Either FREERTOS_AF_INET4 or FREERTOS_AF_INET6. 1416 * @return The IPv4 IP address for the hostname being queried. It will be zero if there is no reply. 1417 */ prvGetHostByName(const char * pcHostName,TickType_t uxIdentifier,TickType_t uxReadTimeOut_ticks,struct freertos_addrinfo ** ppxAddressInfo,BaseType_t xFamily)1418 static uint32_t prvGetHostByName( const char * pcHostName, 1419 TickType_t uxIdentifier, 1420 TickType_t uxReadTimeOut_ticks, 1421 struct freertos_addrinfo ** ppxAddressInfo, 1422 BaseType_t xFamily ) 1423 { 1424 Socket_t xDNSSocket; 1425 uint32_t ulIPAddress = 0U; 1426 1427 1428 xDNSSocket = DNS_CreateSocket( uxReadTimeOut_ticks ); 1429 1430 if( xDNSSocket != NULL ) 1431 { 1432 if( uxReadTimeOut_ticks == 0U ) 1433 { 1434 /* xRetryIndex is negative to tell that the socket is non-blocking. */ 1435 ulIPAddress = prvGetHostByNameOp( pcHostName, 1436 uxIdentifier, 1437 xDNSSocket, 1438 ppxAddressInfo, 1439 xFamily, 1440 uxReadTimeOut_ticks ); 1441 } 1442 else 1443 { 1444 ulIPAddress = prvGetHostByNameOp_WithRetry( pcHostName, 1445 uxIdentifier, 1446 xDNSSocket, 1447 ppxAddressInfo, 1448 xFamily, 1449 uxReadTimeOut_ticks ); 1450 } 1451 1452 /* Finished with the socket. */ 1453 DNS_CloseSocket( xDNSSocket ); 1454 } 1455 1456 return ulIPAddress; 1457 } 1458 /*-----------------------------------------------------------*/ 1459 1460 /** 1461 * @brief Create the DNS message in the zero copy buffer passed in the first parameter. 1462 * @param[in,out] pucUDPPayloadBuffer The zero copy buffer where the DNS message will be created. 1463 * @param[in] pcHostName Hostname to be looked up. 1464 * @param[in] uxIdentifier Identifier to match sent and received packets 1465 * @param[in] uxHostType dnsTYPE_A_HOST ( IPv4 ) or dnsTYPE_AAAA_HOST ( IPv6 ). 1466 * @return Total size of the generated message, which is the space from the last written byte 1467 * to the beginning of the buffer. 1468 */ prvCreateDNSMessage(uint8_t * pucUDPPayloadBuffer,const char * pcHostName,TickType_t uxIdentifier,UBaseType_t uxHostType)1469 static size_t prvCreateDNSMessage( uint8_t * pucUDPPayloadBuffer, 1470 const char * pcHostName, 1471 TickType_t uxIdentifier, 1472 UBaseType_t uxHostType ) 1473 { 1474 DNSMessage_t * pxDNSMessageHeader; 1475 size_t uxStart, uxIndex; 1476 DNSTail_t const * pxTail; 1477 static const DNSMessage_t xDefaultPartDNSHeader = 1478 { 1479 0, /* The identifier will be overwritten. */ 1480 dnsOUTGOING_FLAGS, /* Flags set for standard query. */ 1481 dnsONE_QUESTION, /* One question is being asked. */ 1482 0, /* No replies are included. */ 1483 0, /* No authorities. */ 1484 0 /* No additional authorities. */ 1485 }; 1486 1487 /* memcpy() helper variables for MISRA Rule 21.15 compliance*/ 1488 const void * pvCopySource; 1489 void * pvCopyDest; 1490 1491 ( void ) uxHostType; 1492 1493 /* Copy in the const part of the header. Intentionally using different 1494 * pointers with memcpy() to put the information in to correct place. */ 1495 1496 /* 1497 * Use helper variables for memcpy() to remain 1498 * compliant with MISRA Rule 21.15. These should be 1499 * optimized away. 1500 */ 1501 pvCopySource = &xDefaultPartDNSHeader; 1502 pvCopyDest = pucUDPPayloadBuffer; 1503 ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartDNSHeader ) ); 1504 1505 /* Write in a unique identifier. Cast the Payload Buffer to DNSMessage_t 1506 * to easily access fields of the DNS Message. */ 1507 1508 /* MISRA Ref 11.3.1 [Misaligned access] */ 1509 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1510 /* coverity[misra_c_2012_rule_11_3_violation] */ 1511 pxDNSMessageHeader = ( ( DNSMessage_t * ) pucUDPPayloadBuffer ); 1512 pxDNSMessageHeader->usIdentifier = ( uint16_t ) uxIdentifier; 1513 1514 /* Create the resource record at the end of the header. First 1515 * find the end of the header. */ 1516 uxStart = sizeof( xDefaultPartDNSHeader ); 1517 1518 /* Leave a gap for the first length byte. */ 1519 uxIndex = uxStart + 1U; 1520 1521 /* Copy in the host name. */ 1522 ( void ) strcpy( ( char * ) &( pucUDPPayloadBuffer[ uxIndex ] ), pcHostName ); 1523 1524 /* Walk through the string to replace the '.' characters with byte 1525 * counts. pucStart holds the address of the byte count. Walking the 1526 * string starts after the byte count position. */ 1527 uxIndex = uxStart; 1528 1529 do 1530 { 1531 size_t uxLength; 1532 1533 /* Skip the length byte. */ 1534 uxIndex++; 1535 1536 while( ( pucUDPPayloadBuffer[ uxIndex ] != ( uint8_t ) 0U ) && 1537 ( pucUDPPayloadBuffer[ uxIndex ] != ( uint8_t ) ASCII_BASELINE_DOT ) ) 1538 { 1539 uxIndex++; 1540 } 1541 1542 /* Fill in the byte count, then move the pucStart pointer up to 1543 * the found byte position. */ 1544 uxLength = uxIndex - ( uxStart + 1U ); 1545 pucUDPPayloadBuffer[ uxStart ] = ( uint8_t ) uxLength; 1546 1547 uxStart = uxIndex; 1548 } while( pucUDPPayloadBuffer[ uxIndex ] != ( uint8_t ) 0U ); 1549 1550 /* Finish off the record. Cast the record onto DNSTail_t structure to easily 1551 * access the fields of the DNS Message. */ 1552 1553 /* MISRA Ref 11.3.1 [Misaligned access] */ 1554 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 1555 /* coverity[misra_c_2012_rule_11_3_violation] */ 1556 pxTail = ( ( DNSTail_t * ) &( pucUDPPayloadBuffer[ uxStart + 1U ] ) ); 1557 1558 #if defined( _lint ) || defined( __COVERITY__ ) 1559 ( void ) pxTail; 1560 #else 1561 vSetField16( pxTail, DNSTail_t, usType, ( uint16_t ) uxHostType ); 1562 vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); 1563 #endif 1564 1565 /* Return the total size of the generated message, which is the space from 1566 * the last written byte to the beginning of the buffer. */ 1567 return uxIndex + sizeof( DNSTail_t ) + 1U; 1568 } 1569 1570 /*-----------------------------------------------------------*/ 1571 1572 /* The function below will only be called : 1573 * when ipconfigDNS_USE_CALLBACKS == 1 1574 * when ipconfigUSE_LLMNR == 1 1575 * for testing purposes, by the module test_freertos_tcp.c 1576 */ 1577 1578 /** 1579 * @brief Perform some preliminary checks and then parse the DNS packet. 1580 * @param[in] pxNetworkBuffer The network buffer to be parsed. 1581 * @return Always pdFAIL to indicate that the packet was not consumed and must 1582 * be released by the caller. 1583 */ ulDNSHandlePacket(const NetworkBufferDescriptor_t * pxNetworkBuffer)1584 uint32_t ulDNSHandlePacket( const NetworkBufferDescriptor_t * pxNetworkBuffer ) 1585 { 1586 uint8_t * pucPayLoadBuffer; 1587 size_t uxPayloadSize; 1588 size_t uxUDPPacketSize = ipSIZE_OF_ETH_HEADER + uxIPHeaderSizePacket( pxNetworkBuffer ) + ipSIZE_OF_UDP_HEADER; 1589 1590 /* Only proceed if the payload length indicated in the header 1591 * appears to be valid. */ 1592 if( pxNetworkBuffer->xDataLength >= uxUDPPacketSize ) 1593 { 1594 uxPayloadSize = pxNetworkBuffer->xDataLength - uxUDPPacketSize; 1595 1596 if( uxPayloadSize >= sizeof( DNSMessage_t ) ) 1597 { 1598 struct freertos_addrinfo * pxAddressInfo = NULL; 1599 pucPayLoadBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ uxUDPPacketSize ] ); 1600 1601 /* The parameter pdFALSE indicates that the reply was not expected. */ 1602 ( void ) DNS_ParseDNSReply( pucPayLoadBuffer, 1603 uxPayloadSize, 1604 &( pxAddressInfo ), 1605 pdFALSE, 1606 FreeRTOS_ntohs( pxNetworkBuffer->usPort ) ); 1607 1608 if( pxAddressInfo != NULL ) 1609 { 1610 FreeRTOS_freeaddrinfo( pxAddressInfo ); 1611 } 1612 } 1613 } 1614 1615 /* The packet was not consumed. */ 1616 return pdFAIL; 1617 } 1618 /*-----------------------------------------------------------*/ 1619 1620 1621 #if ( ipconfigUSE_NBNS == 1 ) 1622 1623 /** 1624 * @brief Handle an NBNS packet. 1625 * @param[in] pxNetworkBuffer The network buffer holding the NBNS packet. 1626 * @return pdFAIL to show that the packet was not consumed. 1627 */ ulNBNSHandlePacket(NetworkBufferDescriptor_t * pxNetworkBuffer)1628 uint32_t ulNBNSHandlePacket( NetworkBufferDescriptor_t * pxNetworkBuffer ) 1629 { 1630 UDPPacket_t * pxUDPPacket = ( ( UDPPacket_t * ) 1631 pxNetworkBuffer->pucEthernetBuffer ); 1632 uint8_t * pucUDPPayloadBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ sizeof( *pxUDPPacket ) ] ); 1633 1634 size_t uxBytesNeeded = sizeof( UDPPacket_t ) + sizeof( NBNSRequest_t ); 1635 1636 /* Check for minimum buffer size. */ 1637 if( pxNetworkBuffer->xDataLength >= uxBytesNeeded ) 1638 { 1639 DNS_TreatNBNS( pucUDPPayloadBuffer, 1640 pxNetworkBuffer->xDataLength, 1641 pxUDPPacket->xIPHeader.ulSourceIPAddress ); 1642 } 1643 1644 /* The packet was not consumed. */ 1645 return pdFAIL; 1646 } 1647 1648 #endif /* ipconfigUSE_NBNS */ 1649 1650 /*-----------------------------------------------------------*/ 1651 1652 #endif /* ipconfigUSE_DNS != 0 */ 1653 1654 /*-----------------------------------------------------------*/ 1655 1656 /* Provide access to private members for testing. */ 1657 #ifdef FREERTOS_ENABLE_UNIT_TESTS 1658 #include "freertos_tcp_test_access_dns_define.h" 1659 #endif 1660