]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c
43b246d26dd9be2d5aba76625fa103621dbed623
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-TCP / FreeRTOS_DNS.c
1 /*\r
2  * FreeRTOS+TCP V2.2.0\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /* Standard includes. */\r
27 #include <stdint.h>\r
28 \r
29 /* FreeRTOS includes. */\r
30 #include "FreeRTOS.h"\r
31 #include "task.h"\r
32 #include "queue.h"\r
33 #include "list.h"\r
34 #include "semphr.h"\r
35 \r
36 /* FreeRTOS+TCP includes. */\r
37 #include "FreeRTOS_IP.h"\r
38 #include "FreeRTOS_Sockets.h"\r
39 #include "FreeRTOS_IP_Private.h"\r
40 #include "FreeRTOS_UDP_IP.h"\r
41 #include "FreeRTOS_DNS.h"\r
42 #include "NetworkBufferManagement.h"\r
43 #include "NetworkInterface.h"\r
44 #include "IPTraceMacroDefaults.h"\r
45 \r
46 /* Exclude the entire file if DNS is not enabled. */\r
47 #if( ipconfigUSE_DNS != 0 )\r
48 \r
49 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )\r
50         #define dnsDNS_PORT                             0x3500u\r
51         #define dnsONE_QUESTION                 0x0100u\r
52         #define dnsOUTGOING_FLAGS               0x0001u     /* Standard query. */\r
53         #define dnsRX_FLAGS_MASK                0x0f80u     /* The bits of interest in the flags field of incoming DNS messages. */\r
54         #define dnsEXPECTED_RX_FLAGS    0x0080u     /* Should be a response, without any errors. */\r
55 #else\r
56         #define dnsDNS_PORT                             0x0035u\r
57         #define dnsONE_QUESTION                 0x0001u\r
58         #define dnsOUTGOING_FLAGS               0x0100u     /* Standard query. */\r
59         #define dnsRX_FLAGS_MASK                0x800fu     /* The bits of interest in the flags field of incoming DNS messages. */\r
60         #define dnsEXPECTED_RX_FLAGS    0x8000u     /* Should be a response, without any errors. */\r
61 \r
62 #endif /* ipconfigBYTE_ORDER */\r
63 \r
64 /* The maximum number of times a DNS request should be sent out if a response\r
65 is not received, before giving up. */\r
66 #ifndef ipconfigDNS_REQUEST_ATTEMPTS\r
67         #define ipconfigDNS_REQUEST_ATTEMPTS    5\r
68 #endif\r
69 \r
70 /* If the top two bits in the first character of a name field are set then the\r
71 name field is an offset to the string, rather than the string itself. */\r
72 #define dnsNAME_IS_OFFSET                                        ( ( uint8_t ) 0xc0 )\r
73 \r
74 /* NBNS flags. */\r
75 #define dnsNBNS_FLAGS_RESPONSE                           0x8000u\r
76 #define dnsNBNS_FLAGS_OPCODE_MASK                        0x7800u\r
77 #define dnsNBNS_FLAGS_OPCODE_QUERY                       0x0000u\r
78 #define dnsNBNS_FLAGS_OPCODE_REGISTRATION        0x2800u\r
79 \r
80 /* Host types. */\r
81 #define dnsTYPE_A_HOST                                           0x01u\r
82 #define dnsCLASS_IN                                                      0x01u\r
83 \r
84 /* LLMNR constants. */\r
85 #define dnsLLMNR_TTL_VALUE                                       300000uL\r
86 #define dnsLLMNR_FLAGS_IS_REPONSE                        0x8000u\r
87 \r
88 /* NBNS constants. */\r
89 #define dnsNBNS_TTL_VALUE                                        3600uL /* 1 hour valid */\r
90 #define dnsNBNS_TYPE_NET_BIOS                            0x0020u\r
91 #define dnsNBNS_CLASS_IN                                         0x01u\r
92 #define dnsNBNS_NAME_FLAGS                                       0x6000u\r
93 #define dnsNBNS_ENCODED_NAME_LENGTH                      32\r
94 \r
95 /* If the queried NBNS name matches with the device's name,\r
96 the query will be responded to with these flags: */\r
97 #define dnsNBNS_QUERY_RESPONSE_FLAGS             ( 0x8500u )\r
98 \r
99 /* Flag DNS parsing errors in situations where an IPv4 address is the return\r
100 type. */\r
101 #define dnsPARSE_ERROR                                           0uL\r
102 \r
103 /*\r
104  * Create a socket and bind it to the standard DNS port number.  Return the\r
105  * the created socket - or NULL if the socket could not be created or bound.\r
106  */\r
107 static Socket_t prvCreateDNSSocket( void );\r
108 \r
109 /*\r
110  * Create the DNS message in the zero copy buffer passed in the first parameter.\r
111  */\r
112 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer,\r
113                                                                    const char *pcHostName,\r
114                                                                    TickType_t uxIdentifier );\r
115 \r
116 /*\r
117  * Simple routine that jumps over the NAME field of a resource record.\r
118  */\r
119 static uint8_t * prvSkipNameField( uint8_t *pucByte,\r
120                                                                    size_t uxSourceLen );\r
121 \r
122 /*\r
123  * Process a response packet from a DNS server.\r
124  * The parameter 'xExpected' indicates whether the identifier in the reply\r
125  * was expected, and thus if the DNS cache may be updated with the reply.\r
126  */\r
127 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer,\r
128                                                                   size_t uxBufferLength,\r
129                                                                   BaseType_t xExpected );\r
130 \r
131 /*\r
132  * Prepare and send a message to a DNS server.  'uxReadTimeOut_ticks' will be passed as\r
133  * zero, in case the user has supplied a call-back function.\r
134  */\r
135 static uint32_t prvGetHostByName( const char *pcHostName,\r
136                                                                   TickType_t uxIdentifier,\r
137                                                                   TickType_t uxReadTimeOut_ticks );\r
138 \r
139 /*\r
140  * The NBNS and the LLMNR protocol share this reply function.\r
141  */\r
142 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )\r
143         static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer,\r
144                                                                         BaseType_t lNetLength );\r
145 #endif\r
146 \r
147 #if( ipconfigUSE_NBNS == 1 )\r
148         static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer,\r
149                                                                                  size_t uxBufferLength,\r
150                                                                                  uint32_t ulIPAddress );\r
151 #endif /* ipconfigUSE_NBNS */\r
152 \r
153 \r
154 #if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )\r
155         static uint8_t * prvReadNameField( uint8_t *pucByte,\r
156                                                                            size_t uxSourceLen,\r
157                                                                            char *pcName,\r
158                                                                            size_t uxLen );\r
159 #endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */\r
160 \r
161 #if( ipconfigUSE_DNS_CACHE == 1 )\r
162         static void prvProcessDNSCache( const char *pcName,\r
163                                                                         uint32_t *pulIP,\r
164                                                                         uint32_t ulTTL,\r
165                                                                         BaseType_t xLookUp );\r
166 \r
167         typedef struct xDNS_CACHE_TABLE_ROW\r
168         {\r
169                 uint32_t ulIPAddress;                         /* The IP address of an ARP cache entry. */\r
170                 char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ]; /* The name of the host */\r
171                 uint32_t ulTTL;                               /* Time-to-Live (in seconds) from the DNS server. */\r
172                 uint32_t ulTimeWhenAddedInSeconds;\r
173         } DNSCacheRow_t;\r
174 \r
175         static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ];\r
176 \r
177         void FreeRTOS_dnsclear()\r
178         {\r
179                 memset( xDNSCache, 0x0, sizeof( xDNSCache ) );\r
180         }\r
181 #endif /* ipconfigUSE_DNS_CACHE == 1 */\r
182 \r
183 #if( ipconfigUSE_LLMNR == 1 )\r
184         const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } };\r
185 #endif /* ipconfigUSE_LLMNR == 1 */\r
186 \r
187 /*-----------------------------------------------------------*/\r
188 \r
189 #include "pack_struct_start.h"\r
190 struct xDNSMessage\r
191 {\r
192         uint16_t usIdentifier;\r
193         uint16_t usFlags;\r
194         uint16_t usQuestions;\r
195         uint16_t usAnswers;\r
196         uint16_t usAuthorityRRs;\r
197         uint16_t usAdditionalRRs;\r
198 }\r
199 #include "pack_struct_end.h"\r
200 typedef struct xDNSMessage DNSMessage_t;\r
201 \r
202 /* A DNS query consists of a header, as described in 'struct xDNSMessage'\r
203 It is followed by 1 or more queries, each one consisting of a name and a tail,\r
204 with two fields: type and class\r
205 */\r
206 #include "pack_struct_start.h"\r
207 struct xDNSTail\r
208 {\r
209         uint16_t usType;\r
210         uint16_t usClass;\r
211 }\r
212 #include "pack_struct_end.h"\r
213 typedef struct xDNSTail DNSTail_t;\r
214 \r
215 /* DNS answer record header. */\r
216 #include "pack_struct_start.h"\r
217 struct xDNSAnswerRecord\r
218 {\r
219         uint16_t usType;\r
220         uint16_t usClass;\r
221         uint32_t ulTTL;\r
222         uint16_t usDataLength;\r
223 }\r
224 #include "pack_struct_end.h"\r
225 typedef struct xDNSAnswerRecord DNSAnswerRecord_t;\r
226 \r
227 #if( ipconfigUSE_LLMNR == 1 )\r
228 \r
229         #include "pack_struct_start.h"\r
230         struct xLLMNRAnswer\r
231         {\r
232                 uint8_t ucNameCode;\r
233                 uint8_t ucNameOffset;   /* The name is not repeated in the answer, only the offset is given with "0xc0 <offs>" */\r
234                 uint16_t usType;\r
235                 uint16_t usClass;\r
236                 uint32_t ulTTL;\r
237                 uint16_t usDataLength;\r
238                 uint32_t ulIPAddress;\r
239         }\r
240         #include "pack_struct_end.h"\r
241         typedef struct xLLMNRAnswer LLMNRAnswer_t;\r
242 \r
243 #endif /* ipconfigUSE_LLMNR == 1 */\r
244 \r
245 #if( ipconfigUSE_NBNS == 1 )\r
246 \r
247         #include "pack_struct_start.h"\r
248         struct xNBNSRequest\r
249         {\r
250                 uint16_t usRequestId;\r
251                 uint16_t usFlags;\r
252                 uint16_t ulRequestCount;\r
253                 uint16_t usAnswerRSS;\r
254                 uint16_t usAuthRSS;\r
255                 uint16_t usAdditionalRSS;\r
256                 uint8_t ucNameSpace;\r
257                 uint8_t ucName[ dnsNBNS_ENCODED_NAME_LENGTH ];\r
258                 uint8_t ucNameZero;\r
259                 uint16_t usType;\r
260                 uint16_t usClass;\r
261         }\r
262         #include "pack_struct_end.h"\r
263         typedef struct xNBNSRequest NBNSRequest_t;\r
264 \r
265         #include "pack_struct_start.h"\r
266         struct xNBNSAnswer\r
267         {\r
268                 uint16_t usType;\r
269                 uint16_t usClass;\r
270                 uint32_t ulTTL;\r
271                 uint16_t usDataLength;\r
272                 uint16_t usNbFlags;     /* NetBIOS flags 0x6000 : IP-address, big-endian */\r
273                 uint32_t ulIPAddress;\r
274         }\r
275         #include "pack_struct_end.h"\r
276         typedef struct xNBNSAnswer NBNSAnswer_t;\r
277 \r
278         #endif /* ipconfigUSE_NBNS == 1 */\r
279 \r
280 /*-----------------------------------------------------------*/\r
281 \r
282 #if( ipconfigUSE_DNS_CACHE == 1 )\r
283         uint32_t FreeRTOS_dnslookup( const char *pcHostName )\r
284         {\r
285         uint32_t ulIPAddress = 0uL;\r
286 \r
287                 prvProcessDNSCache( pcHostName, &ulIPAddress, 0, pdTRUE );\r
288                 return ulIPAddress;\r
289         }\r
290 #endif /* ipconfigUSE_DNS_CACHE == 1 */\r
291 /*-----------------------------------------------------------*/\r
292 \r
293 #if( ipconfigDNS_USE_CALLBACKS == 1 )\r
294 \r
295         typedef struct xDNS_Callback\r
296         {\r
297                 TickType_t uxRemaningTime;              /* Timeout in ms */\r
298                 FOnDNSEvent pCallbackFunction;  /* Function to be called when the address has been found or when a timeout has beeen reached */\r
299                 TimeOut_t uxTimeoutState;\r
300                 void *pvSearchID;\r
301                 struct xLIST_ITEM xListItem;\r
302                 char pcName[ 1 ];\r
303         } DNSCallback_t;\r
304 \r
305         static List_t xCallbackList;\r
306 \r
307         /* Define FreeRTOS_gethostbyname() as a normal blocking call. */\r
308         uint32_t FreeRTOS_gethostbyname( const char *pcHostName )\r
309         {\r
310                 return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void * ) NULL, 0 );\r
311         }\r
312         /*-----------------------------------------------------------*/\r
313 \r
314         /* Initialise the list of call-back structures. */\r
315         void vDNSInitialise( void );\r
316         void vDNSInitialise( void )\r
317         {\r
318                 vListInitialise( &xCallbackList );\r
319         }\r
320         /*-----------------------------------------------------------*/\r
321 \r
322         /* Iterate through the list of call-back structures and remove\r
323         old entries which have reached a timeout.\r
324         As soon as the list hase become empty, the DNS timer will be stopped\r
325         In case pvSearchID is supplied, the user wants to cancel a DNS request\r
326         */\r
327         void vDNSCheckCallBack( void *pvSearchID );\r
328         void vDNSCheckCallBack( void *pvSearchID )\r
329         {\r
330         const ListItem_t *pxIterator;\r
331         const MiniListItem_t * xEnd = ( const MiniListItem_t * ) listGET_END_MARKER( &xCallbackList );\r
332 \r
333                 vTaskSuspendAll();\r
334                 {\r
335                         for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( xEnd );\r
336                                  pxIterator != ( const ListItem_t * ) xEnd;\r
337                                  )\r
338                         {\r
339                         DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
340 \r
341                                 /* Move to the next item because we might remove this item */\r
342                                 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );\r
343 \r
344                                 if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) )\r
345                                 {\r
346                                         uxListRemove( &pxCallback->xListItem );\r
347                                         vPortFree( pxCallback );\r
348                                 }\r
349                                 else if( xTaskCheckForTimeOut( &pxCallback->uxTimeoutState, &pxCallback->uxRemaningTime ) != pdFALSE )\r
350                                 {\r
351                                         pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 );\r
352                                         uxListRemove( &pxCallback->xListItem );\r
353                                         vPortFree( ( void * ) pxCallback );\r
354                                 }\r
355                         }\r
356                 }\r
357                 xTaskResumeAll();\r
358 \r
359                 if( listLIST_IS_EMPTY( &xCallbackList ) )\r
360                 {\r
361                         vIPSetDnsTimerEnableState( pdFALSE );\r
362                 }\r
363         }\r
364         /*-----------------------------------------------------------*/\r
365 \r
366         void FreeRTOS_gethostbyname_cancel( void *pvSearchID )\r
367         {\r
368                 /* _HT_ Should better become a new API call to have the IP-task remove the callback */\r
369                 vDNSCheckCallBack( pvSearchID );\r
370         }\r
371         /*-----------------------------------------------------------*/\r
372 \r
373         /* FreeRTOS_gethostbyname_a() was called along with callback parameters.\r
374         Store them in a list for later reference. */\r
375         static void vDNSSetCallBack( const char *pcHostName,\r
376                                                                  void *pvSearchID,\r
377                                                                  FOnDNSEvent pCallbackFunction,\r
378                                                                  TickType_t uxTimeout,\r
379                                                                  TickType_t uxIdentifier );\r
380         static void vDNSSetCallBack( const char *pcHostName,\r
381                                                                  void *pvSearchID,\r
382                                                                  FOnDNSEvent pCallbackFunction,\r
383                                                                  TickType_t uxTimeout,\r
384                                                                  TickType_t uxIdentifier )\r
385         {\r
386         size_t lLength = strlen( pcHostName );\r
387         DNSCallback_t *pxCallback = ( DNSCallback_t * ) pvPortMalloc( sizeof( *pxCallback ) + lLength );\r
388 \r
389                 /* Translate from ms to number of clock ticks. */\r
390                 uxTimeout /= portTICK_PERIOD_MS;\r
391 \r
392                 if( pxCallback != NULL )\r
393                 {\r
394                         if( listLIST_IS_EMPTY( &xCallbackList ) )\r
395                         {\r
396                                 /* This is the first one, start the DNS timer to check for timeouts */\r
397                                 vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, uxTimeout ) );\r
398                         }\r
399 \r
400                         strcpy( pxCallback->pcName, pcHostName );\r
401                         pxCallback->pCallbackFunction = pCallbackFunction;\r
402                         pxCallback->pvSearchID = pvSearchID;\r
403                         pxCallback->uxRemaningTime = uxTimeout;\r
404                         vTaskSetTimeOutState( &pxCallback->uxTimeoutState );\r
405                         listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void * ) pxCallback );\r
406                         listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), uxIdentifier );\r
407                         vTaskSuspendAll();\r
408                         {\r
409                                 vListInsertEnd( &xCallbackList, &pxCallback->xListItem );\r
410                         }\r
411                         xTaskResumeAll();\r
412                 }\r
413         }\r
414         /*-----------------------------------------------------------*/\r
415 \r
416         /* A DNS reply was received, see if there is any matching entry and\r
417         call the handler.  Returns pdTRUE if uxIdentifier was recognised. */\r
418         static BaseType_t xDNSDoCallback( TickType_t uxIdentifier,\r
419                                                                           const char *pcName,\r
420                                                                           uint32_t ulIPAddress );\r
421         static BaseType_t xDNSDoCallback( TickType_t uxIdentifier,\r
422                                                                           const char *pcName,\r
423                                                                           uint32_t ulIPAddress )\r
424         {\r
425         BaseType_t xResult = pdFALSE;\r
426         const ListItem_t *pxIterator;\r
427         const MiniListItem_t * xEnd = ( const MiniListItem_t * ) listGET_END_MARKER( &xCallbackList );\r
428 \r
429                 vTaskSuspendAll();\r
430                 {\r
431                         for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( xEnd );\r
432                                  pxIterator != ( const ListItem_t * ) xEnd;\r
433                                  pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )\r
434                         {\r
435                                 /* The cast will take away the 'configLIST_VOLATILE' */\r
436                                 if( uxIdentifier == ( TickType_t ) listGET_LIST_ITEM_VALUE( pxIterator ) )\r
437                                 {\r
438                                 DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );\r
439 \r
440                                         pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID, ulIPAddress );\r
441                                         uxListRemove( &pxCallback->xListItem );\r
442                                         vPortFree( pxCallback );\r
443 \r
444                                         if( listLIST_IS_EMPTY( &xCallbackList ) )\r
445                                         {\r
446                                                 /* The list of outstanding requests is empty. No need for periodic polling. */\r
447                                                 vIPSetDnsTimerEnableState( pdFALSE );\r
448                                         }\r
449 \r
450                                         xResult = pdTRUE;\r
451                                         break;\r
452                                 }\r
453                         }\r
454                 }\r
455                 xTaskResumeAll();\r
456                 return xResult;\r
457         }\r
458 \r
459 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */\r
460 /*-----------------------------------------------------------*/\r
461 \r
462 #if( ipconfigDNS_USE_CALLBACKS == 0 )\r
463         uint32_t FreeRTOS_gethostbyname( const char *pcHostName )\r
464 #else\r
465         uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName,\r
466                                                                            FOnDNSEvent pCallback,\r
467                                                                            void *pvSearchID,\r
468                                                                            TickType_t uxTimeout )\r
469 #endif\r
470 {\r
471 uint32_t ulIPAddress = 0uL;\r
472 TickType_t uxReadTimeOut_ticks = ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS;\r
473 TickType_t uxIdentifier = 0u;\r
474 BaseType_t xHasRandom = pdFALSE;\r
475 \r
476         if( pcHostName != NULL )\r
477         {\r
478                 /* If the supplied hostname is IP address, convert it to uint32_t\r
479                 and return. */\r
480                 #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 )\r
481                 {\r
482                         ulIPAddress = FreeRTOS_inet_addr( pcHostName );\r
483                 }\r
484                 #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */\r
485 \r
486                 /* If a DNS cache is used then check the cache before issuing another DNS\r
487                 request. */\r
488                 #if( ipconfigUSE_DNS_CACHE == 1 )\r
489                 {\r
490                         if( ulIPAddress == 0uL )\r
491                         {\r
492                                 ulIPAddress = FreeRTOS_dnslookup( pcHostName );\r
493 \r
494                                 if( ulIPAddress != 0 )\r
495                                 {\r
496                                         FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );\r
497                                 }\r
498                                 else\r
499                                 {\r
500                                         /* prvGetHostByName will be called to start a DNS lookup. */\r
501                                 }\r
502                         }\r
503                 }\r
504                 #endif /* ipconfigUSE_DNS_CACHE == 1 */\r
505 \r
506                 /* Generate a unique identifier. */\r
507                 if( ulIPAddress == 0uL )\r
508                 {\r
509                 uint32_t ulNumber;\r
510 \r
511                         xHasRandom = xApplicationGetRandomNumber( &( ulNumber ) );\r
512                         /* DNS identifiers are 16-bit. */\r
513                         uxIdentifier = ( TickType_t ) ( ulNumber & 0xffffu );\r
514                         /* ipconfigRAND32() may not return a non-zero value. */\r
515                 }\r
516 \r
517                 #if( ipconfigDNS_USE_CALLBACKS == 1 )\r
518                 {\r
519                         if( pCallback != NULL )\r
520                         {\r
521                                 if( ulIPAddress == 0uL )\r
522                                 {\r
523                                         /* The user has provided a callback function, so do not block on recvfrom() */\r
524                                         if( xHasRandom != pdFALSE )\r
525                                         {\r
526                                                 uxReadTimeOut_ticks = 0u;\r
527                                                 vDNSSetCallBack( pcHostName, pvSearchID, pCallback, uxTimeout, uxIdentifier );\r
528                                         }\r
529                                 }\r
530                                 else\r
531                                 {\r
532                                         /* The IP address is known, do the call-back now. */\r
533                                         pCallback( pcHostName, pvSearchID, ulIPAddress );\r
534                                 }\r
535                         }\r
536                 }\r
537                 #endif /* if ( ipconfigDNS_USE_CALLBACKS == 1 ) */\r
538 \r
539                 if( ( ulIPAddress == 0uL ) && ( xHasRandom != pdFALSE ) )\r
540                 {\r
541                         ulIPAddress = prvGetHostByName( pcHostName, uxIdentifier, uxReadTimeOut_ticks );\r
542                 }\r
543         }\r
544         return ulIPAddress;\r
545 }\r
546 /*-----------------------------------------------------------*/\r
547 \r
548 static uint32_t prvGetHostByName( const char *pcHostName,\r
549                                                                   TickType_t uxIdentifier,\r
550                                                                   TickType_t uxReadTimeOut_ticks )\r
551 {\r
552 struct freertos_sockaddr xAddress;\r
553 Socket_t xDNSSocket;\r
554 uint32_t ulIPAddress = 0uL;\r
555 uint8_t *pucUDPPayloadBuffer;\r
556 uint32_t ulAddressLength = sizeof( struct freertos_sockaddr );\r
557 BaseType_t xAttempt;\r
558 int32_t lBytes;\r
559 size_t uxPayloadLength, uxExpectedPayloadLength;\r
560 TickType_t uxWriteTimeOut_ticks = ipconfigDNS_SEND_BLOCK_TIME_TICKS;\r
561 \r
562 #if( ipconfigUSE_LLMNR == 1 )\r
563         BaseType_t bHasDot = pdFALSE;\r
564 #endif /* ipconfigUSE_LLMNR == 1 */\r
565 \r
566         /* If LLMNR is being used then determine if the host name includes a '.' -\r
567         if not then LLMNR can be used as the lookup method. */\r
568         #if( ipconfigUSE_LLMNR == 1 )\r
569         {\r
570         const char *pucPtr;\r
571 \r
572                 for( pucPtr = pcHostName; *pucPtr; pucPtr++ )\r
573                 {\r
574                         if( *pucPtr == '.' )\r
575                         {\r
576                                 bHasDot = pdTRUE;\r
577                                 break;\r
578                         }\r
579                 }\r
580         }\r
581         #endif /* ipconfigUSE_LLMNR == 1 */\r
582 \r
583         /* Two is added at the end for the count of characters in the first\r
584         subdomain part and the string end byte. */\r
585         uxExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u;\r
586 \r
587         xDNSSocket = prvCreateDNSSocket();\r
588 \r
589         if( xDNSSocket != NULL )\r
590         {\r
591                 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &uxWriteTimeOut_ticks, sizeof( TickType_t ) );\r
592                 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &uxReadTimeOut_ticks,  sizeof( TickType_t ) );\r
593 \r
594                 for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ )\r
595                 {\r
596                         /* Get a buffer.  This uses a maximum delay, but the delay will be\r
597                         capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value\r
598                         still needs to be tested. */\r
599                         pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( uxExpectedPayloadLength, portMAX_DELAY );\r
600 \r
601                         if( pucUDPPayloadBuffer != NULL )\r
602                         {\r
603                                 /* Create the message in the obtained buffer. */\r
604                                 uxPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, uxIdentifier );\r
605 \r
606                                 iptraceSENDING_DNS_REQUEST();\r
607 \r
608                                 /* Obtain the DNS server address. */\r
609                                 FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress );\r
610 \r
611                                 /* Send the DNS message. */\r
612 #if( ipconfigUSE_LLMNR == 1 )\r
613                                 if( bHasDot == pdFALSE )\r
614                                 {\r
615                                         /* Use LLMNR addressing. */\r
616                                         ( ( DNSMessage_t * ) pucUDPPayloadBuffer )->usFlags = 0;\r
617                                         xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */\r
618                                         xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT );\r
619                                 }\r
620                                 else\r
621 #endif\r
622                                 {\r
623                                         /* Use DNS server. */\r
624                                         xAddress.sin_addr = ulIPAddress;\r
625                                         xAddress.sin_port = dnsDNS_PORT;\r
626                                 }\r
627 \r
628                                 ulIPAddress = 0uL;\r
629 \r
630                                 if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, uxPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 )\r
631                                 {\r
632                                         /* Wait for the reply. */\r
633                                         lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength );\r
634 \r
635                                         if( lBytes > 0 )\r
636                                         {\r
637                                         BaseType_t xExpected;\r
638                                         DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
639 \r
640                                                 /* See if the identifiers match. */\r
641                                                 if( uxIdentifier == ( TickType_t ) pxDNSMessageHeader->usIdentifier )\r
642                                                 {\r
643                                                         xExpected = pdTRUE;\r
644                                                 }\r
645                                                 else\r
646                                                 {\r
647                                                         /* The reply was not expected. */\r
648                                                         xExpected = pdFALSE;\r
649                                                 }\r
650 \r
651                                                 /* The reply was received.  Process it. */\r
652                                         #if( ipconfigDNS_USE_CALLBACKS == 0 )\r
653                                                 /* It is useless to analyse the unexpected reply\r
654                                                 unless asynchronous look-ups are enabled. */\r
655                                                 if( xExpected != pdFALSE )\r
656                                         #endif /* ipconfigDNS_USE_CALLBACKS == 0 */\r
657                                                 {\r
658                                                         ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, ( size_t ) lBytes, xExpected );\r
659                                                 }\r
660 \r
661                                                 /* Finished with the buffer.  The zero copy interface\r
662                                                 is being used, so the buffer must be freed by the\r
663                                                 task. */\r
664                                                 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );\r
665 \r
666                                                 if( ulIPAddress != 0uL )\r
667                                                 {\r
668                                                         /* All done. */\r
669                                                         break;\r
670                                                 }\r
671                                         }\r
672                                 }\r
673                                 else\r
674                                 {\r
675                                         /* The message was not sent so the stack will not be\r
676                                         releasing the zero copy - it must be released here. */\r
677                                         FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );\r
678                                 }\r
679                         }\r
680 \r
681                         if( uxReadTimeOut_ticks == 0u )\r
682                         {\r
683                                 /* This DNS lookup is asynchronous, using a call-back:\r
684                                 send the request only once. */\r
685                                 break;\r
686                         }\r
687                 }\r
688 \r
689                 /* Finished with the socket. */\r
690                 FreeRTOS_closesocket( xDNSSocket );\r
691         }\r
692 \r
693         return ulIPAddress;\r
694 }\r
695 /*-----------------------------------------------------------*/\r
696 \r
697 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer,\r
698                                                                    const char *pcHostName,\r
699                                                                    TickType_t uxIdentifier )\r
700 {\r
701 DNSMessage_t *pxDNSMessageHeader;\r
702 uint8_t *pucStart, *pucByte;\r
703 DNSTail_t *pxTail;\r
704 static const DNSMessage_t xDefaultPartDNSHeader =\r
705 {\r
706         0,                 /* The identifier will be overwritten. */\r
707         dnsOUTGOING_FLAGS, /* Flags set for standard query. */\r
708         dnsONE_QUESTION,   /* One question is being asked. */\r
709         0,                 /* No replies are included. */\r
710         0,                 /* No authorities. */\r
711         0                  /* No additional authorities. */\r
712 };\r
713 \r
714         /* Copy in the const part of the header. */\r
715         memcpy( ( void * ) pucUDPPayloadBuffer, ( void * ) &xDefaultPartDNSHeader, sizeof( xDefaultPartDNSHeader ) );\r
716 \r
717         /* Write in a unique identifier. */\r
718         pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
719         pxDNSMessageHeader->usIdentifier = ( uint16_t ) uxIdentifier;\r
720 \r
721         /* Create the resource record at the end of the header.  First\r
722         find the end of the header. */\r
723         pucStart = pucUDPPayloadBuffer + sizeof( xDefaultPartDNSHeader );\r
724 \r
725         /* Leave a gap for the first length bytes. */\r
726         pucByte = pucStart + 1;\r
727 \r
728         /* Copy in the host name. */\r
729         strcpy( ( char * ) pucByte, pcHostName );\r
730 \r
731         /* Mark the end of the string. */\r
732         pucByte += strlen( pcHostName );\r
733         *pucByte = 0x00u;\r
734 \r
735         /* Walk the string to replace the '.' characters with byte counts.\r
736         pucStart holds the address of the byte count.  Walking the string\r
737         starts after the byte count position. */\r
738         pucByte = pucStart;\r
739 \r
740         do\r
741         {\r
742                 pucByte++;\r
743 \r
744                 while( ( *pucByte != 0x00 ) && ( *pucByte != '.' ) )\r
745                 {\r
746                         pucByte++;\r
747                 }\r
748 \r
749                 /* Fill in the byte count, then move the pucStart pointer up to\r
750                 the found byte position. */\r
751                 *pucStart = ( uint8_t ) ( ( uint32_t ) pucByte - ( uint32_t ) pucStart );\r
752                 ( *pucStart )--;\r
753 \r
754                 pucStart = pucByte;\r
755         } while( *pucByte != 0x00 );\r
756 \r
757         /* Finish off the record. */\r
758 \r
759         pxTail = ( DNSTail_t * ) ( pucByte + 1 );\r
760 \r
761         vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */\r
762         vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN );   /* 1: Class IN */\r
763 \r
764         /* Return the total size of the generated message, which is the space from\r
765         the last written byte to the beginning of the buffer. */\r
766         return ( ( uint32_t ) pucByte - ( uint32_t ) pucUDPPayloadBuffer + 1 ) + sizeof( *pxTail );\r
767 }\r
768 /*-----------------------------------------------------------*/\r
769 \r
770 #if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )\r
771 \r
772         static uint8_t * prvReadNameField( uint8_t *pucByte,\r
773                                                                            size_t uxSourceLen,\r
774                                                                            char *pcName,\r
775                                                                            size_t uxDestLen )\r
776         {\r
777         size_t uxNameLen = 0;\r
778         BaseType_t xCount;\r
779 \r
780                 if( 0 == uxSourceLen )\r
781                 {\r
782                         return NULL;\r
783                 }\r
784 \r
785                 /* Determine if the name is the fully coded name, or an offset to the name\r
786                 elsewhere in the message. */\r
787                 if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )\r
788                 {\r
789                         /* Jump over the two byte offset. */\r
790                         if( uxSourceLen > sizeof( uint16_t ) )\r
791                         {\r
792                                 pucByte += sizeof( uint16_t );\r
793                         }\r
794                         else\r
795                         {\r
796                                 pucByte = NULL;\r
797                         }\r
798                 }\r
799                 else\r
800                 {\r
801                         /* pucByte points to the full name. Walk over the string. */\r
802                         while( ( NULL != pucByte ) && ( *pucByte != 0x00u ) && ( uxSourceLen > 1u ) )\r
803                         {\r
804                                 /* If this is not the first time through the loop, then add a\r
805                                 separator in the output. */\r
806                                 if( ( uxNameLen > 0 ) && ( uxNameLen < ( uxDestLen - 1u ) ) )\r
807                                 {\r
808                                         pcName[ uxNameLen++ ] = '.';\r
809                                 }\r
810 \r
811                                 /* Process the first/next sub-string. */\r
812                                 for( xCount = *( pucByte++ ), uxSourceLen--;\r
813                                          xCount-- && uxSourceLen > 1u;\r
814                                          pucByte++, uxSourceLen-- )\r
815                                 {\r
816                                         if( uxNameLen < uxDestLen - 1u )\r
817                                         {\r
818                                                 pcName[ uxNameLen++ ] = *( ( char * ) pucByte );\r
819                                         }\r
820                                         else\r
821                                         {\r
822                                                 /* DNS name is too big for the provided buffer. */\r
823                                                 pucByte = NULL;\r
824                                                 break;\r
825                                         }\r
826                                 }\r
827                         }\r
828 \r
829                         /* Confirm that a fully formed name was found. */\r
830                         if( NULL != pucByte )\r
831                         {\r
832                                 if( 0x00 == *pucByte )\r
833                                 {\r
834                                         pucByte++;\r
835                                         uxSourceLen--;\r
836                                         pcName[ uxNameLen++ ] = '\0';\r
837                                 }\r
838                                 else\r
839                                 {\r
840                                         pucByte = NULL;\r
841                                 }\r
842                         }\r
843                 }\r
844 \r
845                 return pucByte;\r
846         }\r
847 #endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */\r
848 /*-----------------------------------------------------------*/\r
849 \r
850 static uint8_t * prvSkipNameField( uint8_t *pucByte,\r
851                                                                    size_t uxSourceLen )\r
852 {\r
853 size_t uxChunkLength;\r
854 \r
855         if( 0u == uxSourceLen )\r
856         {\r
857                 return NULL;\r
858         }\r
859 \r
860         /* Determine if the name is the fully coded name, or an offset to the name\r
861         elsewhere in the message. */\r
862         if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )\r
863         {\r
864                 /* Jump over the two byte offset. */\r
865                 if( uxSourceLen > sizeof( uint16_t ) )\r
866                 {\r
867                         pucByte += sizeof( uint16_t );\r
868                 }\r
869                 else\r
870                 {\r
871                         pucByte = NULL;\r
872                 }\r
873         }\r
874         else\r
875         {\r
876                 /* pucByte points to the full name. Walk over the string. */\r
877                 while( ( *pucByte != 0x00u ) && ( uxSourceLen > 1u ) )\r
878                 {\r
879                         uxChunkLength = *pucByte + 1u;\r
880 \r
881                         if( uxSourceLen > uxChunkLength )\r
882                         {\r
883                                 uxSourceLen -= uxChunkLength;\r
884                                 pucByte += uxChunkLength;\r
885                         }\r
886                         else\r
887                         {\r
888                                 pucByte = NULL;\r
889                                 break;\r
890                         }\r
891                 }\r
892 \r
893                 /* Confirm that a fully formed name was found. */\r
894                 if( NULL != pucByte )\r
895                 {\r
896                         if( 0x00u == *pucByte )\r
897                         {\r
898                                 pucByte++;\r
899                         }\r
900                         else\r
901                         {\r
902                                 pucByte = NULL;\r
903                         }\r
904                 }\r
905         }\r
906 \r
907         return pucByte;\r
908 }\r
909 /*-----------------------------------------------------------*/\r
910 \r
911 /* The function below will only be called :\r
912 when ipconfigDNS_USE_CALLBACKS == 1\r
913 when ipconfigUSE_LLMNR == 1\r
914 for testing purposes, by the module iot_test_freertos_tcp.c\r
915 */\r
916 uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
917 {\r
918 DNSMessage_t *pxDNSMessageHeader;\r
919 size_t uxPayloadSize;\r
920 \r
921     /* Only proceed if the payload length indicated in the header\r
922     appears to be valid. */\r
923     if( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) )\r
924     {\r
925         uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );\r
926 \r
927         if( uxPayloadSize >= sizeof( DNSMessage_t ) )\r
928         {\r
929             pxDNSMessageHeader =\r
930                 ( DNSMessage_t * ) ( pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ) );\r
931 \r
932             /* The parameter pdFALSE indicates that the reply was not expected. */\r
933             prvParseDNSReply( ( uint8_t * ) pxDNSMessageHeader,\r
934                 uxPayloadSize,\r
935                 pdFALSE );\r
936         }\r
937     }\r
938 \r
939         /* The packet was not consumed. */\r
940         return pdFAIL;\r
941 }\r
942 /*-----------------------------------------------------------*/\r
943 \r
944 #if( ipconfigUSE_NBNS == 1 )\r
945 \r
946         uint32_t ulNBNSHandlePacket( NetworkBufferDescriptor_t * pxNetworkBuffer )\r
947         {\r
948         UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
949         uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );\r
950         size_t uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );\r
951 \r
952                 /* The network buffer data length has already been set to the\r
953                 length of the UDP payload. */\r
954                 prvTreatNBNS( pucUDPPayloadBuffer,\r
955                                           uxPayloadSize,\r
956                                           pxUDPPacket->xIPHeader.ulSourceIPAddress );\r
957 \r
958                 /* The packet was not consumed. */\r
959                 return pdFAIL;\r
960         }\r
961 \r
962 #endif /* ipconfigUSE_NBNS */\r
963 /*-----------------------------------------------------------*/\r
964 \r
965 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer,\r
966                                                                   size_t uxBufferLength,\r
967                                                                   BaseType_t xExpected )\r
968 {\r
969 DNSMessage_t *pxDNSMessageHeader;\r
970 DNSAnswerRecord_t *pxDNSAnswerRecord;\r
971 uint32_t ulIPAddress = 0uL;\r
972 #if( ipconfigUSE_LLMNR == 1 )\r
973         char *pcRequestedName = NULL;\r
974 #endif\r
975 uint8_t *pucByte;\r
976 size_t uxSourceBytesRemaining;\r
977 uint16_t x, usDataLength, usQuestions;\r
978 BaseType_t xDoStore = xExpected;\r
979 #if( ipconfigUSE_LLMNR == 1 )\r
980         uint16_t usType = 0, usClass = 0;\r
981 #endif\r
982 #if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )\r
983         char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ] = "";\r
984 #endif\r
985 \r
986         /* Ensure that the buffer is of at least minimal DNS message length. */\r
987         if( uxBufferLength < sizeof( DNSMessage_t ) )\r
988         {\r
989                 return dnsPARSE_ERROR;\r
990         }\r
991 \r
992         uxSourceBytesRemaining = uxBufferLength;\r
993 \r
994         /* Parse the DNS message header. */\r
995         pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
996 \r
997         /* Introduce a do {} while (0) to allow the use of breaks. */\r
998         do\r
999         {\r
1000                 /* Start at the first byte after the header. */\r
1001                 pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t );\r
1002                 uxSourceBytesRemaining -= sizeof( DNSMessage_t );\r
1003 \r
1004                 /* Skip any question records. */\r
1005                 usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions );\r
1006 \r
1007                 for( x = 0; x < usQuestions; x++ )\r
1008                 {\r
1009                         #if( ipconfigUSE_LLMNR == 1 )\r
1010                         {\r
1011                                 if( x == 0 )\r
1012                                 {\r
1013                                         pcRequestedName = ( char * ) pucByte;\r
1014                                 }\r
1015                         }\r
1016                         #endif\r
1017 \r
1018 #if( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 )\r
1019                         if( x == 0 )\r
1020                         {\r
1021                                 pucByte = prvReadNameField( pucByte,\r
1022                                                                                         uxSourceBytesRemaining,\r
1023                                                                                         pcName,\r
1024                                                                                         sizeof( pcName ) );\r
1025 \r
1026                                 /* Check for a malformed response. */\r
1027                                 if( NULL == pucByte )\r
1028                                 {\r
1029                                         return dnsPARSE_ERROR;\r
1030                                 }\r
1031 \r
1032                                 uxSourceBytesRemaining = ( pucUDPPayloadBuffer + uxBufferLength ) - pucByte;\r
1033                         }\r
1034                         else\r
1035 #endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */\r
1036                         {\r
1037                                 /* Skip the variable length pcName field. */\r
1038                                 pucByte = prvSkipNameField( pucByte,\r
1039                                                                                         uxSourceBytesRemaining );\r
1040 \r
1041                                 /* Check for a malformed response. */\r
1042                                 if( NULL == pucByte )\r
1043                                 {\r
1044                                         return dnsPARSE_ERROR;\r
1045                                 }\r
1046 \r
1047                                 uxSourceBytesRemaining = ( size_t )\r
1048                                         ( pucUDPPayloadBuffer + uxBufferLength - pucByte );\r
1049                         }\r
1050 \r
1051                         /* Check the remaining buffer size. */\r
1052                         if( uxSourceBytesRemaining >= sizeof( uint32_t ) )\r
1053                         {\r
1054                                 #if( ipconfigUSE_LLMNR == 1 )\r
1055                                 {\r
1056                                         /* usChar2u16 returns value in host endianness. */\r
1057                                         usType = usChar2u16( pucByte );\r
1058                                         usClass = usChar2u16( pucByte + 2 );\r
1059                                 }\r
1060                                 #endif /* ipconfigUSE_LLMNR */\r
1061 \r
1062                                 /* Skip the type and class fields. */\r
1063                                 pucByte += sizeof( uint32_t );\r
1064                                 uxSourceBytesRemaining -= sizeof( uint32_t );\r
1065                         }\r
1066                         else\r
1067                         {\r
1068                                 /* Malformed response. */\r
1069                                 return dnsPARSE_ERROR;\r
1070                         }\r
1071                 }\r
1072 \r
1073                 /* Search through the answer records. */\r
1074                 pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers );\r
1075 \r
1076                 if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS )\r
1077                 {\r
1078                         for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ )\r
1079                         {\r
1080                                 pucByte = prvSkipNameField( pucByte,\r
1081                                                                                         uxSourceBytesRemaining );\r
1082 \r
1083                                 /* Check for a malformed response. */\r
1084                                 if( NULL == pucByte )\r
1085                                 {\r
1086                                         return dnsPARSE_ERROR;\r
1087                                 }\r
1088 \r
1089                                 uxSourceBytesRemaining = ( size_t )\r
1090                                         ( pucUDPPayloadBuffer + uxBufferLength - pucByte );\r
1091 \r
1092                                 /* Is there enough data for an IPv4 A record answer and, if so,\r
1093                                 is this an A record? */\r
1094                                 if( ( uxSourceBytesRemaining >= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) ) ) &&\r
1095                                         ( usChar2u16( pucByte ) == dnsTYPE_A_HOST ) )\r
1096                                 {\r
1097                                         /* This is the required record type and is of sufficient size. */\r
1098                                         pxDNSAnswerRecord = ( DNSAnswerRecord_t * ) pucByte;\r
1099 \r
1100                                         /* Sanity check the data length of an IPv4 answer. */\r
1101                                         if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) == sizeof( uint32_t ) )\r
1102                                         {\r
1103                                                 /* Copy the IP address out of the record. */\r
1104                                                 memcpy( &ulIPAddress,\r
1105                                                                 pucByte + sizeof( DNSAnswerRecord_t ),\r
1106                                                                 sizeof( uint32_t ) );\r
1107 \r
1108                                                 #if( ipconfigDNS_USE_CALLBACKS == 1 )\r
1109                                                 {\r
1110                                                         /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */\r
1111                                                         if( xDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress ) != pdFALSE )\r
1112                                                         {\r
1113                                                                 /* This device has requested this DNS look-up.\r
1114                                                                 The result may be stored in the DNS cache. */\r
1115                                                                 xDoStore = pdTRUE;\r
1116                                                         }\r
1117                                                 }\r
1118                                                 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */\r
1119                                                 #if( ipconfigUSE_DNS_CACHE == 1 )\r
1120                                                 {\r
1121                                                         /* The reply will only be stored in the DNS cache when the\r
1122                                                         request was issued by this device. */\r
1123                                                         if( xDoStore != pdFALSE )\r
1124                                                         {\r
1125                                                                 prvProcessDNSCache( pcName, &ulIPAddress, pxDNSAnswerRecord->ulTTL, pdFALSE );\r
1126                                                         }\r
1127 \r
1128                                                         /* Show what has happened. */\r
1129                                                         FreeRTOS_printf( ( "DNS[0x%04X]: The answer to '%s' (%xip) will%s be stored\n",\r
1130                                                                                            ( unsigned ) pxDNSMessageHeader->usIdentifier,\r
1131                                                                                            pcName,\r
1132                                                                                            ( unsigned ) FreeRTOS_ntohl( ulIPAddress ),\r
1133                                                                                            ( xDoStore != 0 ) ? "" : " NOT" ) );\r
1134                                                 }\r
1135                                                 #endif /* ipconfigUSE_DNS_CACHE */\r
1136                                         }\r
1137 \r
1138                                         pucByte += sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t );\r
1139                                         uxSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) );\r
1140                                         break;\r
1141                                 }\r
1142                                 else if( uxSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) )\r
1143                                 {\r
1144                                         /* It's not an A record, so skip it. Get the header location\r
1145                                         and then jump over the header. */\r
1146                                         pxDNSAnswerRecord = ( DNSAnswerRecord_t * ) pucByte;\r
1147                                         pucByte += sizeof( DNSAnswerRecord_t );\r
1148                                         uxSourceBytesRemaining -= sizeof( DNSAnswerRecord_t );\r
1149 \r
1150                                         /* Determine the length of the answer data from the header. */\r
1151                                         usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength );\r
1152 \r
1153                                         /* Jump over the answer. */\r
1154                                         if( uxSourceBytesRemaining >= usDataLength )\r
1155                                         {\r
1156                                                 pucByte += usDataLength;\r
1157                                                 uxSourceBytesRemaining -= usDataLength;\r
1158                                         }\r
1159                                         else\r
1160                                         {\r
1161                                                 /* Malformed response. */\r
1162                                                 return dnsPARSE_ERROR;\r
1163                                         }\r
1164                                 }\r
1165                         }\r
1166                 }\r
1167 \r
1168 #if( ipconfigUSE_LLMNR == 1 )\r
1169                 else if( usQuestions && ( usType == dnsTYPE_A_HOST ) && ( usClass == dnsCLASS_IN ) )\r
1170                 {\r
1171                         /* If this is not a reply to our DNS request, it might an LLMNR\r
1172                         request. */\r
1173                         if( xApplicationDNSQueryHook( ( pcRequestedName + 1 ) ) )\r
1174                         {\r
1175                         int16_t usLength;\r
1176                         NetworkBufferDescriptor_t *pxNewBuffer = NULL;\r
1177                         NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );\r
1178                         LLMNRAnswer_t *pxAnswer;\r
1179 \r
1180                                 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )\r
1181                                 {\r
1182                                 BaseType_t xDataLength = uxBufferLength + sizeof( UDPHeader_t ) + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );\r
1183 \r
1184                                         /* Set the size of the outgoing packet. */\r
1185                                         pxNetworkBuffer->xDataLength = xDataLength;\r
1186                                         pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + sizeof( LLMNRAnswer_t ) );\r
1187 \r
1188                                         if( pxNewBuffer != NULL )\r
1189                                         {\r
1190                                         BaseType_t xOffset1, xOffset2;\r
1191 \r
1192                                                 xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer );\r
1193                                                 xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer );\r
1194 \r
1195                                                 pxNetworkBuffer = pxNewBuffer;\r
1196                                                 pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + ipUDP_PAYLOAD_OFFSET_IPv4;\r
1197 \r
1198                                                 pucByte = pucUDPPayloadBuffer + xOffset1;\r
1199                                                 pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 );\r
1200                                                 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
1201                                         }\r
1202                                         else\r
1203                                         {\r
1204                                                 /* Just to indicate that the message may not be answered. */\r
1205                                                 pxNetworkBuffer = NULL;\r
1206                                         }\r
1207                                 }\r
1208 \r
1209                                 if( pxNetworkBuffer != NULL )\r
1210                                 {\r
1211                                         pxAnswer = ( LLMNRAnswer_t * ) pucByte;\r
1212 \r
1213                                         /* We leave 'usIdentifier' and 'usQuestions' untouched */\r
1214                                         vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */\r
1215                                         vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 );                       /* Provide a single answer */\r
1216                                         vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 );                  /* No authority */\r
1217                                         vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 );                 /* No additional info */\r
1218 \r
1219                                         pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;\r
1220                                         pxAnswer->ucNameOffset = ( uint8_t ) ( pcRequestedName - ( char * ) pucUDPPayloadBuffer );\r
1221 \r
1222                                         vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */\r
1223                                         vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN );   /* 1: Class IN */\r
1224                                         vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE );\r
1225                                         vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 );\r
1226                                         vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );\r
1227 \r
1228                                         usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucUDPPayloadBuffer ) );\r
1229 \r
1230                                         prvReplyDNSMessage( pxNetworkBuffer, usLength );\r
1231 \r
1232                                         if( pxNewBuffer != NULL )\r
1233                                         {\r
1234                                                 vReleaseNetworkBufferAndDescriptor( pxNewBuffer );\r
1235                                         }\r
1236                                 }\r
1237                         }\r
1238                 }\r
1239 #endif /* ipconfigUSE_LLMNR == 1 */\r
1240         } while( 0 );\r
1241 \r
1242         if( xExpected == pdFALSE )\r
1243         {\r
1244                 /* Do not return a valid IP-address in case the reply was not expected. */\r
1245                 ulIPAddress = 0uL;\r
1246         }\r
1247 \r
1248         return ulIPAddress;\r
1249 }\r
1250 /*-----------------------------------------------------------*/\r
1251 \r
1252 #if( ipconfigUSE_NBNS == 1 )\r
1253 \r
1254         static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer,\r
1255                                                           size_t uxBufferLength,\r
1256                                                           uint32_t ulIPAddress )\r
1257         {\r
1258         uint16_t usFlags, usType, usClass;\r
1259         uint8_t *pucSource, *pucTarget;\r
1260         uint8_t ucByte;\r
1261         uint8_t ucNBNSName[ 17 ];\r
1262 \r
1263                 /* Check for minimum buffer size. */\r
1264                 if( uxBufferLength < sizeof( NBNSRequest_t ) )\r
1265                 {\r
1266                         return;\r
1267                 }\r
1268 \r
1269                 /* Read the request flags in host endianness. */\r
1270                 usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) );\r
1271 \r
1272                 if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )\r
1273                 {\r
1274                         usType  = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );\r
1275                         usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) );\r
1276 \r
1277                         /* Not used for now */\r
1278                         ( void ) usClass;\r
1279 \r
1280                         /* For NBNS a name is 16 bytes long, written with capitals only.\r
1281                         Make sure that the copy is terminated with a zero. */\r
1282                         pucTarget = ucNBNSName + sizeof( ucNBNSName ) - 2;\r
1283                         pucTarget[ 1 ] = '\0';\r
1284 \r
1285                         /* Start with decoding the last 2 bytes. */\r
1286                         pucSource = pucUDPPayloadBuffer + ( offsetof( NBNSRequest_t, ucName ) + ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) );\r
1287 \r
1288                         for( ;; )\r
1289                         {\r
1290                                 ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - 0x41 ) << 4 ) | ( pucSource[ 1 ] - 0x41 ) );\r
1291 \r
1292                                 /* Make sure there are no trailing spaces in the name. */\r
1293                                 if( ( ucByte == ' ' ) && ( pucTarget[ 1 ] == '\0' ) )\r
1294                                 {\r
1295                                         ucByte = '\0';\r
1296                                 }\r
1297 \r
1298                                 *pucTarget = ucByte;\r
1299 \r
1300                                 if( pucTarget == ucNBNSName )\r
1301                                 {\r
1302                                         break;\r
1303                                 }\r
1304 \r
1305                                 pucTarget -= 1;\r
1306                                 pucSource -= 2;\r
1307                         }\r
1308 \r
1309                         #if( ipconfigUSE_DNS_CACHE == 1 )\r
1310                         {\r
1311                                 if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0 )\r
1312                                 {\r
1313                                         /* If this is a response from another device,\r
1314                                         add the name to the DNS cache */\r
1315                                         prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, 0, pdFALSE );\r
1316                                 }\r
1317                         }\r
1318                         #else\r
1319                         {\r
1320                                 /* Avoid compiler warnings. */\r
1321                                 ( void ) ulIPAddress;\r
1322                         }\r
1323                         #endif /* ipconfigUSE_DNS_CACHE */\r
1324 \r
1325                         if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0 ) &&\r
1326                                 ( usType == dnsNBNS_TYPE_NET_BIOS ) &&\r
1327                                 ( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) )\r
1328                         {\r
1329                         uint16_t usLength;\r
1330                         DNSMessage_t *pxMessage;\r
1331                         NBNSAnswer_t *pxAnswer;\r
1332 \r
1333                                 /* Someone is looking for a device with ucNBNSName,\r
1334                                 prepare a positive reply. */\r
1335                                 NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );\r
1336 \r
1337                                 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )\r
1338                                 {\r
1339                                 NetworkBufferDescriptor_t *pxNewBuffer;\r
1340 \r
1341                                         /* The field xDataLength was set to the total length of the UDP packet,\r
1342                                         i.e. the payload size plus sizeof( UDPPacket_t ). */\r
1343                                         pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, pxNetworkBuffer->xDataLength + sizeof( NBNSAnswer_t ) );\r
1344 \r
1345                                         if( pxNewBuffer != NULL )\r
1346                                         {\r
1347                                                 pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );\r
1348                                                 pxNetworkBuffer = pxNewBuffer;\r
1349                                         }\r
1350                                         else\r
1351                                         {\r
1352                                                 /* Just prevent that a reply will be sent */\r
1353                                                 pxNetworkBuffer = NULL;\r
1354                                         }\r
1355                                 }\r
1356 \r
1357                                 /* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */\r
1358                                 if( pxNetworkBuffer != NULL )\r
1359                                 {\r
1360                                         pxMessage = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
1361 \r
1362                                         /* As the fields in the structures are not word-aligned, we have to\r
1363                                         copy the values byte-by-byte using macro's vSetField16() and vSetField32() */\r
1364                                         vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */\r
1365                                         vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 );\r
1366                                         vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 );\r
1367                                         vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 );\r
1368                                         vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 );\r
1369 \r
1370                                         pxAnswer = ( NBNSAnswer_t * ) ( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );\r
1371 \r
1372                                         vSetField16( pxAnswer, NBNSAnswer_t, usType, usType );            /* Type */\r
1373                                         vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */\r
1374                                         vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE );\r
1375                                         vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 );           /* 6 bytes including the length field */\r
1376                                         vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS );\r
1377                                         vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );\r
1378 \r
1379                                         usLength = ( uint16_t ) ( offsetof( NBNSRequest_t, usType ) + sizeof( NBNSAnswer_t ) );\r
1380 \r
1381                                         prvReplyDNSMessage( pxNetworkBuffer, usLength );\r
1382                                 }\r
1383                         }\r
1384                 }\r
1385         }\r
1386 \r
1387 #endif /* ipconfigUSE_NBNS */\r
1388 /*-----------------------------------------------------------*/\r
1389 \r
1390 static Socket_t prvCreateDNSSocket( void )\r
1391 {\r
1392 Socket_t xSocket = NULL;\r
1393 struct freertos_sockaddr xAddress;\r
1394 BaseType_t xReturn;\r
1395 \r
1396         /* This must be the first time this function has been called.  Create\r
1397         the socket. */\r
1398         xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );\r
1399 \r
1400         /* Auto bind the port. */\r
1401         xAddress.sin_port = 0u;\r
1402         xReturn = FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );\r
1403 \r
1404         /* Check the bind was successful, and clean up if not. */\r
1405         if( xReturn != 0 )\r
1406         {\r
1407                 FreeRTOS_closesocket( xSocket );\r
1408                 xSocket = NULL;\r
1409         }\r
1410         else\r
1411         {\r
1412                 /* The send and receive timeouts will be set later on. */\r
1413         }\r
1414 \r
1415         return xSocket;\r
1416 }\r
1417 /*-----------------------------------------------------------*/\r
1418 \r
1419 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )\r
1420 \r
1421         static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer,\r
1422                                                                         BaseType_t lNetLength )\r
1423         {\r
1424         UDPPacket_t *pxUDPPacket;\r
1425         IPHeader_t *pxIPHeader;\r
1426         UDPHeader_t *pxUDPHeader;\r
1427 \r
1428                 pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
1429                 pxIPHeader = &pxUDPPacket->xIPHeader;\r
1430                 pxUDPHeader = &pxUDPPacket->xUDPHeader;\r
1431                 /* HT: started using defines like 'ipSIZE_OF_xxx' */\r
1432                 pxIPHeader->usLength                       = FreeRTOS_htons( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER );\r
1433                 /* HT:endian: should not be translated, copying from packet to packet */\r
1434                 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;\r
1435                 pxIPHeader->ulSourceIPAddress      = *ipLOCAL_IP_ADDRESS_POINTER;\r
1436                 pxIPHeader->ucTimeToLive                   = ipconfigUDP_TIME_TO_LIVE;\r
1437                 pxIPHeader->usIdentification       = FreeRTOS_htons( usPacketIdentifier );\r
1438                 usPacketIdentifier++;\r
1439                 pxUDPHeader->usLength                      = FreeRTOS_htons( lNetLength + ipSIZE_OF_UDP_HEADER );\r
1440                 vFlip_16( pxUDPPacket->xUDPHeader.usSourcePort, pxUDPPacket->xUDPHeader.usDestinationPort );\r
1441 \r
1442                 /* Important: tell NIC driver how many bytes must be sent */\r
1443                 pxNetworkBuffer->xDataLength = ( size_t ) ( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER );\r
1444 \r
1445                 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )\r
1446                 {\r
1447                         /* calculate the IP header checksum */\r
1448                         pxIPHeader->usHeaderChecksum = 0x00;\r
1449                         pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0uL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );\r
1450                         pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );\r
1451 \r
1452                         /* calculate the UDP checksum for outgoing package */\r
1453                         usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE );\r
1454                 }\r
1455                 #endif\r
1456 \r
1457                 /* This function will fill in the eth addresses and send the packet */\r
1458                 vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );\r
1459         }\r
1460 \r
1461 #endif /* ipconfigUSE_NBNS == 1 || ipconfigUSE_LLMNR == 1 */\r
1462 /*-----------------------------------------------------------*/\r
1463 \r
1464 #if( ipconfigUSE_DNS_CACHE == 1 )\r
1465 \r
1466         static void prvProcessDNSCache( const char *pcName,\r
1467                                                                         uint32_t *pulIP,\r
1468                                                                         uint32_t ulTTL,\r
1469                                                                         BaseType_t xLookUp )\r
1470         {\r
1471         BaseType_t x;\r
1472         BaseType_t xFound = pdFALSE;\r
1473         uint32_t ulCurrentTimeSeconds = ( xTaskGetTickCount() / portTICK_PERIOD_MS ) / 1000;\r
1474         static BaseType_t xFreeEntry = 0;\r
1475                 configASSERT(pcName);\r
1476 \r
1477                 /* For each entry in the DNS cache table. */\r
1478                 for( x = 0; x < ipconfigDNS_CACHE_ENTRIES; x++ )\r
1479                 {\r
1480                         if( xDNSCache[ x ].pcName[ 0 ] == 0 )\r
1481                         {\r
1482                                 continue;\r
1483                         }\r
1484 \r
1485                         if( 0 == strcmp( xDNSCache[ x ].pcName, pcName ) )\r
1486                         {\r
1487                                 /* Is this function called for a lookup or to add/update an IP address? */\r
1488                                 if( xLookUp != pdFALSE )\r
1489                                 {\r
1490                                         /* Confirm that the record is still fresh. */\r
1491                                         if( ulCurrentTimeSeconds < ( xDNSCache[ x ].ulTimeWhenAddedInSeconds + FreeRTOS_ntohl( xDNSCache[ x ].ulTTL ) ) )\r
1492                                         {\r
1493                                                 *pulIP = xDNSCache[ x ].ulIPAddress;\r
1494                                         }\r
1495                                         else\r
1496                                         {\r
1497                                                 /* Age out the old cached record. */\r
1498                                                 xDNSCache[ x ].pcName[ 0 ] = 0;\r
1499                                         }\r
1500                                 }\r
1501                                 else\r
1502                                 {\r
1503                                         xDNSCache[ x ].ulIPAddress = *pulIP;\r
1504                                         xDNSCache[ x ].ulTTL = ulTTL;\r
1505                                         xDNSCache[ x ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;\r
1506                                 }\r
1507 \r
1508                                 xFound = pdTRUE;\r
1509                                 break;\r
1510                         }\r
1511                 }\r
1512 \r
1513                 if( xFound == pdFALSE )\r
1514                 {\r
1515                         if( xLookUp != pdFALSE )\r
1516                         {\r
1517                                 *pulIP = 0;\r
1518                         }\r
1519                         else\r
1520                         {\r
1521                                 /* Add or update the item. */\r
1522                                 if( strlen( pcName ) < ipconfigDNS_CACHE_NAME_LENGTH )\r
1523                                 {\r
1524                                         strcpy( xDNSCache[ xFreeEntry ].pcName, pcName );\r
1525 \r
1526                                         xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP;\r
1527                                         xDNSCache[ xFreeEntry ].ulTTL = ulTTL;\r
1528                                         xDNSCache[ xFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;\r
1529 \r
1530                                         xFreeEntry++;\r
1531 \r
1532                                         if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES )\r
1533                                         {\r
1534                                                 xFreeEntry = 0;\r
1535                                         }\r
1536                                 }\r
1537                         }\r
1538                 }\r
1539 \r
1540                 if( ( xLookUp == 0 ) || ( *pulIP != 0 ) )\r
1541                 {\r
1542                         FreeRTOS_debug_printf( ( "prvProcessDNSCache: %s: '%s' @ %lxip\n", xLookUp ? "look-up" : "add", pcName, FreeRTOS_ntohl( *pulIP ) ) );\r
1543                 }\r
1544         }\r
1545 \r
1546 #endif /* ipconfigUSE_DNS_CACHE */\r
1547 \r
1548 #endif /* ipconfigUSE_DNS != 0 */\r
1549 \r
1550 /*-----------------------------------------------------------*/\r
1551 \r
1552 /* Provide access to private members for testing. */\r
1553 #ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS\r
1554         #include "iot_freertos_tcp_test_access_dns_define.h"\r
1555 #endif\r
1556 \r