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