2 * FreeRTOS+TCP V2.0.7
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
26 /* Standard includes. */
\r
29 /* FreeRTOS includes. */
\r
30 #include "FreeRTOS.h"
\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
46 /* Exclude the entire file if DNS is not enabled. */
\r
47 #if( ipconfigUSE_DNS != 0 )
\r
49 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
\r
50 #define dnsDNS_PORT 0x3500
\r
51 #define dnsONE_QUESTION 0x0100
\r
52 #define dnsOUTGOING_FLAGS 0x0001 /* Standard query. */
\r
53 #define dnsRX_FLAGS_MASK 0x0f80 /* The bits of interest in the flags field of incoming DNS messages. */
\r
54 #define dnsEXPECTED_RX_FLAGS 0x0080 /* Should be a response, without any errors. */
\r
56 #define dnsDNS_PORT 0x0035
\r
57 #define dnsONE_QUESTION 0x0001
\r
58 #define dnsOUTGOING_FLAGS 0x0100 /* Standard query. */
\r
59 #define dnsRX_FLAGS_MASK 0x800f /* The bits of interest in the flags field of incoming DNS messages. */
\r
60 #define dnsEXPECTED_RX_FLAGS 0x8000 /* Should be a response, without any errors. */
\r
62 #endif /* ipconfigBYTE_ORDER */
\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
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
75 #define dnsNBNS_FLAGS_RESPONSE 0x8000
\r
76 #define dnsNBNS_FLAGS_OPCODE_MASK 0x7800
\r
77 #define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000
\r
78 #define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800
\r
81 #define dnsTYPE_A_HOST 0x01
\r
82 #define dnsCLASS_IN 0x01
\r
84 /* LLMNR constants. */
\r
85 #define dnsLLMNR_TTL_VALUE 300000
\r
86 #define dnsLLMNR_FLAGS_IS_REPONSE 0x8000
\r
88 /* NBNS constants. */
\r
89 #define dnsNBNS_TTL_VALUE 3600 /* 1 hour valid */
\r
90 #define dnsNBNS_TYPE_NET_BIOS 0x0020
\r
91 #define dnsNBNS_CLASS_IN 0x01
\r
92 #define dnsNBNS_NAME_FLAGS 0x6000
\r
93 #define dnsNBNS_ENCODED_NAME_LENGTH 32
\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 ( 0x8500 )
\r
99 /* Flag DNS parsing errors in situations where an IPv4 address is the return
\r
101 #define dnsPARSE_ERROR 0UL
\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
107 static Socket_t prvCreateDNSSocket( void );
\r
110 * Create the DNS message in the zero copy buffer passed in the first parameter.
\r
112 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier );
\r
115 * Simple routine that jumps over the NAME field of a resource record.
\r
117 static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen );
\r
120 * Process a response packet from a DNS server.
\r
122 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier );
\r
125 * Prepare and send a message to a DNS server. 'xReadTimeOut_ms' will be passed as
\r
126 * zero, in case the user has supplied a call-back function.
\r
128 static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms );
\r
131 * The NBNS and the LLMNR protocol share this reply function.
\r
133 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
\r
134 static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength );
\r
137 #if( ipconfigUSE_NBNS == 1 )
\r
138 static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress );
\r
139 #endif /* ipconfigUSE_NBNS */
\r
141 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
142 static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xLen );
\r
143 static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp );
\r
145 typedef struct xDNS_CACHE_TABLE_ROW
\r
147 uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */
\r
148 char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ]; /* The name of the host */
\r
149 uint32_t ulTTL; /* Time-to-Live (in seconds) from the DNS server. */
\r
150 uint32_t ulTimeWhenAddedInSeconds;
\r
153 static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ];
\r
154 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
156 #if( ipconfigUSE_LLMNR == 1 )
\r
157 const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } };
\r
158 #endif /* ipconfigUSE_LLMNR == 1 */
\r
160 /*-----------------------------------------------------------*/
\r
162 #include "pack_struct_start.h"
\r
165 uint16_t usIdentifier;
\r
167 uint16_t usQuestions;
\r
168 uint16_t usAnswers;
\r
169 uint16_t usAuthorityRRs;
\r
170 uint16_t usAdditionalRRs;
\r
172 #include "pack_struct_end.h"
\r
173 typedef struct xDNSMessage DNSMessage_t;
\r
175 /* A DNS query consists of a header, as described in 'struct xDNSMessage'
\r
176 It is followed by 1 or more queries, each one consisting of a name and a tail,
\r
177 with two fields: type and class
\r
179 #include "pack_struct_start.h"
\r
185 #include "pack_struct_end.h"
\r
186 typedef struct xDNSTail DNSTail_t;
\r
188 /* DNS answer record header. */
\r
189 #include "pack_struct_start.h"
\r
190 struct xDNSAnswerRecord
\r
195 uint16_t usDataLength;
\r
197 #include "pack_struct_end.h"
\r
198 typedef struct xDNSAnswerRecord DNSAnswerRecord_t;
\r
200 #if( ipconfigUSE_LLMNR == 1 )
\r
202 #include "pack_struct_start.h"
\r
203 struct xLLMNRAnswer
\r
205 uint8_t ucNameCode;
\r
206 uint8_t ucNameOffset; /* The name is not repeated in the answer, only the offset is given with "0xc0 <offs>" */
\r
210 uint16_t usDataLength;
\r
211 uint32_t ulIPAddress;
\r
213 #include "pack_struct_end.h"
\r
214 typedef struct xLLMNRAnswer LLMNRAnswer_t;
\r
216 #endif /* ipconfigUSE_LLMNR == 1 */
\r
218 #if( ipconfigUSE_NBNS == 1 )
\r
220 #include "pack_struct_start.h"
\r
221 struct xNBNSRequest
\r
223 uint16_t usRequestId;
\r
225 uint16_t ulRequestCount;
\r
226 uint16_t usAnswerRSS;
\r
227 uint16_t usAuthRSS;
\r
228 uint16_t usAdditionalRSS;
\r
229 uint8_t ucNameSpace;
\r
230 uint8_t ucName[ dnsNBNS_ENCODED_NAME_LENGTH ];
\r
231 uint8_t ucNameZero;
\r
235 #include "pack_struct_end.h"
\r
236 typedef struct xNBNSRequest NBNSRequest_t;
\r
238 #include "pack_struct_start.h"
\r
244 uint16_t usDataLength;
\r
245 uint16_t usNbFlags; /* NetBIOS flags 0x6000 : IP-address, big-endian */
\r
246 uint32_t ulIPAddress;
\r
248 #include "pack_struct_end.h"
\r
249 typedef struct xNBNSAnswer NBNSAnswer_t;
\r
251 #endif /* ipconfigUSE_NBNS == 1 */
\r
253 /*-----------------------------------------------------------*/
\r
255 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
256 uint32_t FreeRTOS_dnslookup( const char *pcHostName )
\r
258 uint32_t ulIPAddress = 0UL;
\r
259 prvProcessDNSCache( pcHostName, &ulIPAddress, 0, pdTRUE );
\r
260 return ulIPAddress;
\r
262 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
263 /*-----------------------------------------------------------*/
\r
265 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
267 typedef struct xDNS_Callback {
\r
268 TickType_t xRemaningTime; /* Timeout in ms */
\r
269 FOnDNSEvent pCallbackFunction; /* Function to be called when the address has been found or when a timeout has beeen reached */
\r
270 TimeOut_t xTimeoutState;
\r
272 struct xLIST_ITEM xListItem;
\r
276 static List_t xCallbackList;
\r
278 /* Define FreeRTOS_gethostbyname() as a normal blocking call. */
\r
279 uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
\r
281 return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void* )NULL, 0 );
\r
283 /*-----------------------------------------------------------*/
\r
285 /* Initialise the list of call-back structures. */
\r
286 void vDNSInitialise( void );
\r
287 void vDNSInitialise( void )
\r
289 vListInitialise( &xCallbackList );
\r
291 /*-----------------------------------------------------------*/
\r
293 /* Iterate through the list of call-back structures and remove
\r
294 old entries which have reached a timeout.
\r
295 As soon as the list hase become empty, the DNS timer will be stopped
\r
296 In case pvSearchID is supplied, the user wants to cancel a DNS request
\r
298 void vDNSCheckCallBack( void *pvSearchID );
\r
299 void vDNSCheckCallBack( void *pvSearchID )
\r
301 const ListItem_t *pxIterator;
\r
302 const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
\r
306 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
\r
307 pxIterator != ( const ListItem_t * ) xEnd;
\r
310 DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
311 /* Move to the next item because we might remove this item */
\r
312 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
313 if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) )
\r
315 uxListRemove( &pxCallback->xListItem );
\r
316 vPortFree( pxCallback );
\r
318 else if( xTaskCheckForTimeOut( &pxCallback->xTimeoutState, &pxCallback->xRemaningTime ) != pdFALSE )
\r
320 pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 );
\r
321 uxListRemove( &pxCallback->xListItem );
\r
322 vPortFree( ( void * ) pxCallback );
\r
328 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
330 vIPSetDnsTimerEnableState( pdFALSE );
\r
333 /*-----------------------------------------------------------*/
\r
335 void FreeRTOS_gethostbyname_cancel( void *pvSearchID )
\r
337 /* _HT_ Should better become a new API call to have the IP-task remove the callback */
\r
338 vDNSCheckCallBack( pvSearchID );
\r
340 /*-----------------------------------------------------------*/
\r
342 /* FreeRTOS_gethostbyname_a() was called along with callback parameters.
\r
343 Store them in a list for later reference. */
\r
344 static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier );
\r
345 static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier )
\r
347 size_t lLength = strlen( pcHostName );
\r
348 DNSCallback_t *pxCallback = ( DNSCallback_t * )pvPortMalloc( sizeof( *pxCallback ) + lLength );
\r
350 /* Translate from ms to number of clock ticks. */
\r
351 xTimeout /= portTICK_PERIOD_MS;
\r
352 if( pxCallback != NULL )
\r
354 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
356 /* This is the first one, start the DNS timer to check for timeouts */
\r
357 vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, xTimeout ) );
\r
359 strcpy( pxCallback->pcName, pcHostName );
\r
360 pxCallback->pCallbackFunction = pCallbackFunction;
\r
361 pxCallback->pvSearchID = pvSearchID;
\r
362 pxCallback->xRemaningTime = xTimeout;
\r
363 vTaskSetTimeOutState( &pxCallback->xTimeoutState );
\r
364 listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void* ) pxCallback );
\r
365 listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), xIdentifier );
\r
368 vListInsertEnd( &xCallbackList, &pxCallback->xListItem );
\r
373 /*-----------------------------------------------------------*/
\r
375 /* A DNS reply was received, see if there is any matching entry and
\r
376 call the handler. */
\r
377 static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress );
\r
378 static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress )
\r
380 const ListItem_t *pxIterator;
\r
381 const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
\r
385 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
\r
386 pxIterator != ( const ListItem_t * ) xEnd;
\r
387 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
389 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xIdentifier )
\r
391 DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
392 pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID, ulIPAddress );
\r
393 uxListRemove( &pxCallback->xListItem );
\r
394 vPortFree( pxCallback );
\r
395 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
397 vIPSetDnsTimerEnableState( pdFALSE );
\r
406 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
\r
407 /*-----------------------------------------------------------*/
\r
409 #if( ipconfigDNS_USE_CALLBACKS == 0 )
\r
410 uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
\r
412 uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout )
\r
415 uint32_t ulIPAddress = 0UL;
\r
416 TickType_t xReadTimeOut_ms = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME;
\r
417 TickType_t xIdentifier = 0;
\r
419 /* If the supplied hostname is IP address, convert it to uint32_t
\r
421 #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 )
\r
423 ulIPAddress = FreeRTOS_inet_addr( pcHostName );
\r
425 #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */
\r
427 /* If a DNS cache is used then check the cache before issuing another DNS
\r
429 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
431 if( ulIPAddress == 0UL )
\r
433 ulIPAddress = FreeRTOS_dnslookup( pcHostName );
\r
434 if( ulIPAddress != 0 )
\r
436 FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );
\r
440 /* prvGetHostByName will be called to start a DNS lookup */
\r
444 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
446 /* Generate a unique identifier. */
\r
447 if( 0 == ulIPAddress )
\r
449 xIdentifier = ( TickType_t )ipconfigRAND32( );
\r
452 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
454 if( pCallback != NULL )
\r
456 if( ulIPAddress == 0UL )
\r
458 /* The user has provided a callback function, so do not block on recvfrom() */
\r
459 if( 0 != xIdentifier )
\r
461 xReadTimeOut_ms = 0;
\r
462 vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t )xIdentifier );
\r
467 /* The IP address is known, do the call-back now. */
\r
468 pCallback( pcHostName, pvSearchID, ulIPAddress );
\r
474 if( ( ulIPAddress == 0UL ) && ( 0 != xIdentifier ) )
\r
476 ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms );
\r
479 return ulIPAddress;
\r
481 /*-----------------------------------------------------------*/
\r
483 static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms )
\r
485 struct freertos_sockaddr xAddress;
\r
486 Socket_t xDNSSocket;
\r
487 uint32_t ulIPAddress = 0UL;
\r
488 uint8_t *pucUDPPayloadBuffer;
\r
489 uint32_t ulAddressLength = sizeof( struct freertos_sockaddr );
\r
490 BaseType_t xAttempt;
\r
492 size_t xPayloadLength, xExpectedPayloadLength;
\r
493 TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME;
\r
495 #if( ipconfigUSE_LLMNR == 1 )
\r
496 BaseType_t bHasDot = pdFALSE;
\r
497 #endif /* ipconfigUSE_LLMNR == 1 */
\r
499 /* If LLMNR is being used then determine if the host name includes a '.' -
\r
500 if not then LLMNR can be used as the lookup method. */
\r
501 #if( ipconfigUSE_LLMNR == 1 )
\r
503 const char *pucPtr;
\r
504 for( pucPtr = pcHostName; *pucPtr; pucPtr++ )
\r
506 if( *pucPtr == '.' )
\r
513 #endif /* ipconfigUSE_LLMNR == 1 */
\r
515 /* Two is added at the end for the count of characters in the first
\r
516 subdomain part and the string end byte. */
\r
517 xExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u;
\r
519 xDNSSocket = prvCreateDNSSocket();
\r
521 if( xDNSSocket != NULL )
\r
523 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xWriteTimeOut_ms, sizeof( TickType_t ) );
\r
524 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xReadTimeOut_ms, sizeof( TickType_t ) );
\r
526 for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ )
\r
528 /* Get a buffer. This uses a maximum delay, but the delay will be
\r
529 capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value
\r
530 still needs to be tested. */
\r
531 pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xExpectedPayloadLength, portMAX_DELAY );
\r
533 if( pucUDPPayloadBuffer != NULL )
\r
535 /* Create the message in the obtained buffer. */
\r
536 xPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, xIdentifier );
\r
538 iptraceSENDING_DNS_REQUEST();
\r
540 /* Obtain the DNS server address. */
\r
541 FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress );
\r
543 /* Send the DNS message. */
\r
544 #if( ipconfigUSE_LLMNR == 1 )
\r
545 if( bHasDot == pdFALSE )
\r
547 /* Use LLMNR addressing. */
\r
548 ( ( DNSMessage_t * ) pucUDPPayloadBuffer) -> usFlags = 0;
\r
549 xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */
\r
550 xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT );
\r
555 /* Use DNS server. */
\r
556 xAddress.sin_addr = ulIPAddress;
\r
557 xAddress.sin_port = dnsDNS_PORT;
\r
562 if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, xPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 )
\r
564 /* Wait for the reply. */
\r
565 lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength );
\r
569 /* The reply was received. Process it. */
\r
570 ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, lBytes, xIdentifier );
\r
572 /* Finished with the buffer. The zero copy interface
\r
573 is being used, so the buffer must be freed by the
\r
575 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
\r
577 if( ulIPAddress != 0UL )
\r
586 /* The message was not sent so the stack will not be
\r
587 releasing the zero copy - it must be released here. */
\r
588 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
\r
593 /* Finished with the socket. */
\r
594 FreeRTOS_closesocket( xDNSSocket );
\r
597 return ulIPAddress;
\r
599 /*-----------------------------------------------------------*/
\r
601 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier )
\r
603 DNSMessage_t *pxDNSMessageHeader;
\r
604 uint8_t *pucStart, *pucByte;
\r
606 static const DNSMessage_t xDefaultPartDNSHeader =
\r
608 0, /* The identifier will be overwritten. */
\r
609 dnsOUTGOING_FLAGS, /* Flags set for standard query. */
\r
610 dnsONE_QUESTION, /* One question is being asked. */
\r
611 0, /* No replies are included. */
\r
612 0, /* No authorities. */
\r
613 0 /* No additional authorities. */
\r
616 /* Copy in the const part of the header. */
\r
617 memcpy( ( void * ) pucUDPPayloadBuffer, ( void * ) &xDefaultPartDNSHeader, sizeof( xDefaultPartDNSHeader ) );
\r
619 /* Write in a unique identifier. */
\r
620 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
621 pxDNSMessageHeader->usIdentifier = ( uint16_t ) xIdentifier;
\r
623 /* Create the resource record at the end of the header. First
\r
624 find the end of the header. */
\r
625 pucStart = pucUDPPayloadBuffer + sizeof( xDefaultPartDNSHeader );
\r
627 /* Leave a gap for the first length bytes. */
\r
628 pucByte = pucStart + 1;
\r
630 /* Copy in the host name. */
\r
631 strcpy( ( char * ) pucByte, pcHostName );
\r
633 /* Mark the end of the string. */
\r
634 pucByte += strlen( pcHostName );
\r
637 /* Walk the string to replace the '.' characters with byte counts.
\r
638 pucStart holds the address of the byte count. Walking the string
\r
639 starts after the byte count position. */
\r
640 pucByte = pucStart;
\r
646 while( ( *pucByte != 0x00 ) && ( *pucByte != '.' ) )
\r
651 /* Fill in the byte count, then move the pucStart pointer up to
\r
652 the found byte position. */
\r
653 *pucStart = ( uint8_t ) ( ( uint32_t ) pucByte - ( uint32_t ) pucStart );
\r
656 pucStart = pucByte;
\r
658 } while( *pucByte != 0x00 );
\r
660 /* Finish off the record. */
\r
662 pxTail = (DNSTail_t *)( pucByte + 1 );
\r
664 vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
\r
665 vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
\r
667 /* Return the total size of the generated message, which is the space from
\r
668 the last written byte to the beginning of the buffer. */
\r
669 return ( ( uint32_t ) pucByte - ( uint32_t ) pucUDPPayloadBuffer + 1 ) + sizeof( *pxTail );
\r
671 /*-----------------------------------------------------------*/
\r
673 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
675 static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xDestLen )
\r
677 size_t xNameLen = 0;
\r
680 if( 0 == xSourceLen )
\r
685 /* Determine if the name is the fully coded name, or an offset to the name
\r
686 elsewhere in the message. */
\r
687 if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
\r
689 /* Jump over the two byte offset. */
\r
690 if( xSourceLen > sizeof( uint16_t ) )
\r
692 pucByte += sizeof( uint16_t );
\r
701 /* pucByte points to the full name. Walk over the string. */
\r
702 while( ( NULL != pucByte ) && ( *pucByte != 0x00 ) && ( xSourceLen > 1 ) )
\r
704 /* If this is not the first time through the loop, then add a
\r
705 separator in the output. */
\r
706 if( ( xNameLen > 0 ) && ( xNameLen < ( xDestLen - 1 ) ) )
\r
708 pcName[ xNameLen++ ] = '.';
\r
711 /* Process the first/next sub-string. */
\r
712 for( xCount = *(pucByte++), xSourceLen--;
\r
713 xCount-- && xSourceLen > 1;
\r
714 pucByte++, xSourceLen-- )
\r
716 if( xNameLen < xDestLen - 1 )
\r
718 pcName[ xNameLen++ ] = *( ( char * )pucByte );
\r
722 /* DNS name is too big for the provided buffer. */
\r
729 /* Confirm that a fully formed name was found. */
\r
730 if( NULL != pucByte )
\r
732 if( 0x00 == *pucByte )
\r
736 pcName[ xNameLen++ ] = '\0';
\r
747 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
748 /*-----------------------------------------------------------*/
\r
750 static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen )
\r
752 size_t xChunkLength;
\r
754 if( 0 == xSourceLen )
\r
759 /* Determine if the name is the fully coded name, or an offset to the name
\r
760 elsewhere in the message. */
\r
761 if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
\r
763 /* Jump over the two byte offset. */
\r
764 if( xSourceLen > sizeof( uint16_t ) )
\r
766 pucByte += sizeof( uint16_t );
\r
775 /* pucByte points to the full name. Walk over the string. */
\r
776 while( ( *pucByte != 0x00 ) && ( xSourceLen > 1 ) )
\r
778 xChunkLength = *pucByte + 1;
\r
780 if( xSourceLen > xChunkLength )
\r
782 xSourceLen -= xChunkLength;
\r
783 pucByte += xChunkLength;
\r
792 /* Confirm that a fully formed name was found. */
\r
793 if( NULL != pucByte )
\r
795 if( 0x00 == *pucByte )
\r
808 /*-----------------------------------------------------------*/
\r
810 uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
812 uint8_t *pucUDPPayloadBuffer;
\r
813 size_t xPlayloadBufferLength;
\r
814 DNSMessage_t *pxDNSMessageHeader;
\r
816 xPlayloadBufferLength = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
\r
817 if ( xPlayloadBufferLength < sizeof( DNSMessage_t ) )
\r
822 pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
\r
823 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
825 if( pxNetworkBuffer->xDataLength > sizeof( UDPPacket_t ) )
\r
827 prvParseDNSReply( pucUDPPayloadBuffer,
\r
828 xPlayloadBufferLength,
\r
829 ( uint32_t )pxDNSMessageHeader->usIdentifier );
\r
832 /* The packet was not consumed. */
\r
835 /*-----------------------------------------------------------*/
\r
837 #if( ipconfigUSE_NBNS == 1 )
\r
839 uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
841 UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
842 uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
\r
844 if( pxNetworkBuffer->xDataLength > sizeof( UDPPacket_t) )
\r
846 prvTreatNBNS( pucUDPPayloadBuffer,
\r
847 pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ),
\r
848 pxUDPPacket->xIPHeader.ulSourceIPAddress );
\r
851 /* The packet was not consumed. */
\r
855 #endif /* ipconfigUSE_NBNS */
\r
856 /*-----------------------------------------------------------*/
\r
858 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier )
\r
860 DNSMessage_t *pxDNSMessageHeader;
\r
861 DNSAnswerRecord_t *pxDNSAnswerRecord;
\r
862 uint32_t ulIPAddress = 0UL;
\r
863 #if( ipconfigUSE_LLMNR == 1 )
\r
864 char *pcRequestedName = NULL;
\r
867 size_t xSourceBytesRemaining;
\r
868 uint16_t x, usDataLength, usQuestions;
\r
869 #if( ipconfigUSE_LLMNR == 1 )
\r
870 uint16_t usType = 0, usClass = 0;
\r
872 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
873 char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ] = "";
\r
876 /* Ensure that the buffer is of at least minimal DNS message length. */
\r
877 if( xBufferLength < sizeof( DNSMessage_t ) )
\r
879 return dnsPARSE_ERROR;
\r
883 xSourceBytesRemaining = xBufferLength;
\r
886 /* Parse the DNS message header. */
\r
887 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
889 if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier )
\r
891 /* Start at the first byte after the header. */
\r
892 pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t );
\r
893 xSourceBytesRemaining -= sizeof( DNSMessage_t );
\r
895 /* Skip any question records. */
\r
896 usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions );
\r
897 for( x = 0; x < usQuestions; x++ )
\r
899 #if( ipconfigUSE_LLMNR == 1 )
\r
903 pcRequestedName = ( char * ) pucByte;
\r
908 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
911 pucByte = prvReadNameField( pucByte,
\r
912 xSourceBytesRemaining,
\r
914 sizeof( pcName ) );
\r
916 /* Check for a malformed response. */
\r
917 if( NULL == pucByte )
\r
919 return dnsPARSE_ERROR;
\r
923 xSourceBytesRemaining = ( pucUDPPayloadBuffer + xBufferLength ) - pucByte;
\r
927 #endif /* ipconfigUSE_DNS_CACHE */
\r
929 /* Skip the variable length pcName field. */
\r
930 pucByte = prvSkipNameField( pucByte,
\r
931 xSourceBytesRemaining );
\r
933 /* Check for a malformed response. */
\r
934 if( NULL == pucByte )
\r
936 return dnsPARSE_ERROR;
\r
940 xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte;
\r
944 /* Check the remaining buffer size. */
\r
945 if( xSourceBytesRemaining >= sizeof( uint32_t ) )
\r
947 #if( ipconfigUSE_LLMNR == 1 )
\r
949 /* usChar2u16 returns value in host endianness */
\r
950 usType = usChar2u16( pucByte );
\r
951 usClass = usChar2u16( pucByte + 2 );
\r
953 #endif /* ipconfigUSE_LLMNR */
\r
955 /* Skip the type and class fields. */
\r
956 pucByte += sizeof( uint32_t );
\r
957 xSourceBytesRemaining -= sizeof( uint32_t );
\r
961 /* Malformed response. */
\r
962 return dnsPARSE_ERROR;
\r
966 /* Search through the answer records. */
\r
967 pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers );
\r
969 if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS )
\r
971 for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ )
\r
973 pucByte = prvSkipNameField( pucByte,
\r
974 xSourceBytesRemaining );
\r
976 /* Check for a malformed response. */
\r
977 if( NULL == pucByte )
\r
979 return dnsPARSE_ERROR;
\r
983 xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte;
\r
986 /* Is there enough data for an IPv4 A record answer and, if so,
\r
987 is this an A record? */
\r
988 if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) &&
\r
989 usChar2u16( pucByte ) == dnsTYPE_A_HOST )
\r
991 /* This is the required record type and is of sufficient size. */
\r
992 pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte;
\r
994 /* Sanity check the data length of an IPv4 answer. */
\r
995 if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) == sizeof( uint32_t ) )
\r
997 /* Copy the IP address out of the record. */
\r
998 memcpy( &ulIPAddress,
\r
999 pucByte + sizeof( DNSAnswerRecord_t ),
\r
1000 sizeof( uint32_t ) );
\r
1002 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
1004 prvProcessDNSCache( pcName, &ulIPAddress, pxDNSAnswerRecord->ulTTL, pdFALSE );
\r
1006 #endif /* ipconfigUSE_DNS_CACHE */
\r
1007 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
1009 /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */
\r
1010 vDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress );
\r
1012 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
\r
1015 pucByte += sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t );
\r
1016 xSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) );
\r
1019 else if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) )
\r
1021 /* It's not an A record, so skip it. Get the header location
\r
1022 and then jump over the header. */
\r
1023 pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte;
\r
1024 pucByte += sizeof( DNSAnswerRecord_t );
\r
1025 xSourceBytesRemaining -= sizeof( DNSAnswerRecord_t );
\r
1027 /* Determine the length of the answer data from the header. */
\r
1028 usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength );
\r
1030 /* Jump over the answer. */
\r
1031 if( xSourceBytesRemaining >= usDataLength )
\r
1033 pucByte += usDataLength;
\r
1034 xSourceBytesRemaining -= usDataLength;
\r
1038 /* Malformed response. */
\r
1039 return dnsPARSE_ERROR;
\r
1044 #if( ipconfigUSE_LLMNR == 1 )
\r
1045 else if( usQuestions && ( usType == dnsTYPE_A_HOST ) && ( usClass == dnsCLASS_IN ) )
\r
1047 /* If this is not a reply to our DNS request, it might an LLMNR
\r
1049 if( xApplicationDNSQueryHook ( ( pcRequestedName + 1 ) ) )
\r
1052 NetworkBufferDescriptor_t *pxNewBuffer = NULL;
\r
1053 NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
\r
1054 LLMNRAnswer_t *pxAnswer;
\r
1056 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
\r
1058 BaseType_t xDataLength = xBufferLength + sizeof( UDPHeader_t ) + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
\r
1060 /* The field xDataLength was set to the length of the UDP payload.
\r
1061 The answer (reply) will be longer than the request, so the packet
\r
1062 must be duplicaed into a bigger buffer */
\r
1063 pxNetworkBuffer->xDataLength = xDataLength;
\r
1064 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
\r
1065 if( pxNewBuffer != NULL )
\r
1067 BaseType_t xOffset1, xOffset2;
\r
1069 xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer );
\r
1070 xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer );
\r
1072 pxNetworkBuffer = pxNewBuffer;
\r
1073 pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + ipUDP_PAYLOAD_OFFSET_IPv4;
\r
1075 pucByte = pucUDPPayloadBuffer + xOffset1;
\r
1076 pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 );
\r
1077 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
1082 /* Just to indicate that the message may not be answered. */
\r
1083 pxNetworkBuffer = NULL;
\r
1086 if( pxNetworkBuffer != NULL )
\r
1088 pxAnswer = (LLMNRAnswer_t *)pucByte;
\r
1090 /* We leave 'usIdentifier' and 'usQuestions' untouched */
\r
1091 vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */
\r
1092 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
\r
1093 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
\r
1094 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */
\r
1096 pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
\r
1097 pxAnswer->ucNameOffset = ( uint8_t )( pcRequestedName - ( char * ) pucUDPPayloadBuffer );
\r
1099 vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
\r
1100 vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
\r
1101 vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE );
\r
1102 vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 );
\r
1103 vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
\r
1105 usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucUDPPayloadBuffer ) );
\r
1107 prvReplyDNSMessage( pxNetworkBuffer, usLength );
\r
1109 if( pxNewBuffer != NULL )
\r
1111 vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
\r
1116 #endif /* ipconfigUSE_LLMNR == 1 */
\r
1119 return ulIPAddress;
\r
1121 /*-----------------------------------------------------------*/
\r
1123 #if( ipconfigUSE_NBNS == 1 )
\r
1125 static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress )
\r
1127 uint16_t usFlags, usType, usClass;
\r
1128 uint8_t *pucSource, *pucTarget;
\r
1130 uint8_t ucNBNSName[ 17 ];
\r
1132 /* Check for minimum buffer size. */
\r
1133 if( xBufferLength < sizeof( NBNSRequest_t ) )
\r
1138 /* Read the request flags in host endianness. */
\r
1139 usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) );
\r
1141 if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )
\r
1143 usType = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
\r
1144 usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) );
\r
1146 /* Not used for now */
\r
1148 /* For NBNS a name is 16 bytes long, written with capitals only.
\r
1149 Make sure that the copy is terminated with a zero. */
\r
1150 pucTarget = ucNBNSName + sizeof(ucNBNSName ) - 2;
\r
1151 pucTarget[ 1 ] = '\0';
\r
1153 /* Start with decoding the last 2 bytes. */
\r
1154 pucSource = pucUDPPayloadBuffer + ( offsetof( NBNSRequest_t, ucName ) + ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) );
\r
1158 ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - 0x41 ) << 4 ) | ( pucSource[ 1 ] - 0x41 ) );
\r
1160 /* Make sure there are no trailing spaces in the name. */
\r
1161 if( ( ucByte == ' ' ) && ( pucTarget[ 1 ] == '\0' ) )
\r
1166 *pucTarget = ucByte;
\r
1168 if( pucTarget == ucNBNSName )
\r
1177 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
1179 if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0 )
\r
1181 /* If this is a response from another device,
\r
1182 add the name to the DNS cache */
\r
1183 prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, 0, pdFALSE );
\r
1188 /* Avoid compiler warnings. */
\r
1189 ( void ) ulIPAddress;
\r
1191 #endif /* ipconfigUSE_DNS_CACHE */
\r
1193 if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0 ) &&
\r
1194 ( usType == dnsNBNS_TYPE_NET_BIOS ) &&
\r
1195 ( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) )
\r
1197 uint16_t usLength;
\r
1198 DNSMessage_t *pxMessage;
\r
1199 NBNSAnswer_t *pxAnswer;
\r
1201 /* Someone is looking for a device with ucNBNSName,
\r
1202 prepare a positive reply. */
\r
1203 NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
\r
1205 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
\r
1207 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1208 BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +
\r
1209 sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
\r
1211 /* The field xDataLength was set to the length of the UDP payload.
\r
1212 The answer (reply) will be longer than the request, so the packet
\r
1213 must be duplicated into a bigger buffer */
\r
1214 pxNetworkBuffer->xDataLength = xDataLength;
\r
1215 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
\r
1216 if( pxNewBuffer != NULL )
\r
1218 pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
\r
1219 pxNetworkBuffer = pxNewBuffer;
\r
1223 /* Just prevent that a reply will be sent */
\r
1224 pxNetworkBuffer = NULL;
\r
1228 /* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */
\r
1229 if( pxNetworkBuffer != NULL )
\r
1231 pxMessage = (DNSMessage_t *)pucUDPPayloadBuffer;
\r
1233 /* As the fields in the structures are not word-aligned, we have to
\r
1234 copy the values byte-by-byte using macro's vSetField16() and vSetField32() */
\r
1235 vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */
\r
1236 vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 );
\r
1237 vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 );
\r
1238 vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 );
\r
1239 vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 );
\r
1241 pxAnswer = (NBNSAnswer_t *)( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
\r
1243 vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */
\r
1244 vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */
\r
1245 vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE );
\r
1246 vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */
\r
1247 vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS );
\r
1248 vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
\r
1250 usLength = ( uint16_t ) ( offsetof( NBNSRequest_t, usType ) + sizeof( NBNSAnswer_t ) );
\r
1252 prvReplyDNSMessage( pxNetworkBuffer, usLength );
\r
1258 #endif /* ipconfigUSE_NBNS */
\r
1259 /*-----------------------------------------------------------*/
\r
1261 static Socket_t prvCreateDNSSocket( void )
\r
1263 Socket_t xSocket = NULL;
\r
1264 struct freertos_sockaddr xAddress;
\r
1265 BaseType_t xReturn;
\r
1266 TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
\r
1268 /* This must be the first time this function has been called. Create
\r
1270 xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
\r
1272 /* Auto bind the port. */
\r
1273 xAddress.sin_port = 0u;
\r
1274 xReturn = FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
\r
1276 /* Check the bind was successful, and clean up if not. */
\r
1277 if( xReturn != 0 )
\r
1279 FreeRTOS_closesocket( xSocket );
\r
1284 /* Set the send and receive timeouts. */
\r
1285 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
1286 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
1291 /*-----------------------------------------------------------*/
\r
1293 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
\r
1295 static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength )
\r
1297 UDPPacket_t *pxUDPPacket;
\r
1298 IPHeader_t *pxIPHeader;
\r
1299 UDPHeader_t *pxUDPHeader;
\r
1301 pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer;
\r
1302 pxIPHeader = &pxUDPPacket->xIPHeader;
\r
1303 pxUDPHeader = &pxUDPPacket->xUDPHeader;
\r
1304 /* HT: started using defines like 'ipSIZE_OF_xxx' */
\r
1305 pxIPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER );
\r
1306 /* HT:endian: should not be translated, copying from packet to packet */
\r
1307 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
1308 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1309 pxIPHeader->ucTimeToLive = ipconfigUDP_TIME_TO_LIVE;
\r
1310 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
1311 usPacketIdentifier++;
\r
1312 pxUDPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_UDP_HEADER );
\r
1313 vFlip_16( pxUDPPacket->xUDPHeader.usSourcePort, pxUDPPacket->xUDPHeader.usDestinationPort );
\r
1315 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
1317 /* calculate the IP header checksum */
\r
1318 pxIPHeader->usHeaderChecksum = 0x00;
\r
1319 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
1320 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
1322 /* calculate the UDP checksum for outgoing package */
\r
1323 usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, lNetLength, pdTRUE );
\r
1327 /* Important: tell NIC driver how many bytes must be sent */
\r
1328 pxNetworkBuffer->xDataLength = ( size_t ) ( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER );
\r
1330 /* This function will fill in the eth addresses and send the packet */
\r
1331 vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
\r
1334 #endif /* ipconfigUSE_NBNS == 1 || ipconfigUSE_LLMNR == 1 */
\r
1335 /*-----------------------------------------------------------*/
\r
1337 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
1339 static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp )
\r
1342 BaseType_t xFound = pdFALSE;
\r
1343 uint32_t ulCurrentTimeSeconds = ( xTaskGetTickCount() / portTICK_PERIOD_MS ) / 1000;
\r
1344 static BaseType_t xFreeEntry = 0;
\r
1346 /* For each entry in the DNS cache table. */
\r
1347 for( x = 0; x < ipconfigDNS_CACHE_ENTRIES; x++ )
\r
1349 if( xDNSCache[ x ].pcName[ 0 ] == 0 )
\r
1354 if( 0 == strcmp( xDNSCache[ x ].pcName, pcName ) )
\r
1356 /* Is this function called for a lookup or to add/update an IP address? */
\r
1357 if( xLookUp != pdFALSE )
\r
1359 /* Confirm that the record is still fresh. */
\r
1360 if( ulCurrentTimeSeconds < ( xDNSCache[ x ].ulTimeWhenAddedInSeconds + FreeRTOS_ntohl( xDNSCache[ x ].ulTTL ) ) )
\r
1362 *pulIP = xDNSCache[ x ].ulIPAddress;
\r
1366 /* Age out the old cached record. */
\r
1367 xDNSCache[ x ].pcName[ 0 ] = 0;
\r
1372 xDNSCache[ x ].ulIPAddress = *pulIP;
\r
1373 xDNSCache[ x ].ulTTL = ulTTL;
\r
1374 xDNSCache[ x ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;
\r
1382 if( xFound == pdFALSE )
\r
1384 if( xLookUp != pdFALSE )
\r
1390 /* Add or update the item. */
\r
1391 if( strlen( pcName ) < ipconfigDNS_CACHE_NAME_LENGTH )
\r
1393 strcpy( xDNSCache[ xFreeEntry ].pcName, pcName );
\r
1395 xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP;
\r
1396 xDNSCache[ xFreeEntry ].ulTTL = ulTTL;
\r
1397 xDNSCache[ xFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;
\r
1400 if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES )
\r
1408 if( ( xLookUp == 0 ) || ( *pulIP != 0 ) )
\r
1410 FreeRTOS_debug_printf( ( "prvProcessDNSCache: %s: '%s' @ %lxip\n", xLookUp ? "look-up" : "add", pcName, FreeRTOS_ntohl( *pulIP ) ) );
\r
1414 #endif /* ipconfigUSE_DNS_CACHE */
\r
1416 #endif /* ipconfigUSE_DNS != 0 */
\r
1418 /*-----------------------------------------------------------*/
\r
1420 /* Provide access to private members for testing. */
\r
1421 #ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS
\r
1422 #include "aws_freertos_tcp_test_access_dns_define.h"
\r