2 * FreeRTOS+TCP V2.0.0
\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. If you wish to use our Amazon
\r
14 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
\r
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
18 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
19 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* Standard includes. */
\r
32 /* FreeRTOS includes. */
\r
33 #include "FreeRTOS.h"
\r
39 /* FreeRTOS+TCP includes. */
\r
40 #include "FreeRTOS_IP.h"
\r
41 #include "FreeRTOS_Sockets.h"
\r
42 #include "FreeRTOS_IP_Private.h"
\r
43 #include "FreeRTOS_UDP_IP.h"
\r
44 #include "FreeRTOS_DNS.h"
\r
45 #include "NetworkBufferManagement.h"
\r
46 #include "NetworkInterface.h"
\r
47 #include "IPTraceMacroDefaults.h"
\r
49 /* Exclude the entire file if DNS is not enabled. */
\r
50 #if( ipconfigUSE_DNS != 0 )
\r
52 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
\r
53 #define dnsDNS_PORT 0x3500u
\r
54 #define dnsONE_QUESTION 0x0100u
\r
55 #define dnsOUTGOING_FLAGS 0x0001u /* Standard query. */
\r
56 #define dnsRX_FLAGS_MASK 0x0f80u /* The bits of interest in the flags field of incoming DNS messages. */
\r
57 #define dnsEXPECTED_RX_FLAGS 0x0080u /* Should be a response, without any errors. */
\r
59 #define dnsDNS_PORT 0x0035u
\r
60 #define dnsONE_QUESTION 0x0001u
\r
61 #define dnsOUTGOING_FLAGS 0x0100u /* Standard query. */
\r
62 #define dnsRX_FLAGS_MASK 0x800fu /* The bits of interest in the flags field of incoming DNS messages. */
\r
63 #define dnsEXPECTED_RX_FLAGS 0x8000u /* Should be a response, without any errors. */
\r
65 #endif /* ipconfigBYTE_ORDER */
\r
67 /* The maximum number of times a DNS request should be sent out if a response
\r
68 is not received, before giving up. */
\r
69 #ifndef ipconfigDNS_REQUEST_ATTEMPTS
\r
70 #define ipconfigDNS_REQUEST_ATTEMPTS 5
\r
73 /* If the top two bits in the first character of a name field are set then the
\r
74 name field is an offset to the string, rather than the string itself. */
\r
75 #define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 )
\r
78 #define dnsNBNS_FLAGS_RESPONSE 0x8000u
\r
79 #define dnsNBNS_FLAGS_OPCODE_MASK 0x7800u
\r
80 #define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000u
\r
81 #define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800u
\r
84 #define dnsTYPE_A_HOST 0x0001u
\r
85 #define dnsCLASS_IN 0x0001u
\r
87 /* LLMNR constants. */
\r
88 #define dnsLLMNR_TTL_VALUE 300000u
\r
89 #define dnsLLMNR_FLAGS_IS_REPONSE 0x8000u
\r
91 /* NBNS constants. */
\r
92 #define dnsNBNS_TTL_VALUE 3600u /* 1 hour valid */
\r
93 #define dnsNBNS_TYPE_NET_BIOS 0x0020u
\r
94 #define dnsNBNS_CLASS_IN 0x0001u
\r
95 #define dnsNBNS_NAME_FLAGS 0x6000u
\r
96 #define dnsNBNS_ENCODED_NAME_LENGTH 32
\r
98 /* If the queried NBNS name matches with the device's name,
\r
99 the query will be responded to with these flags: */
\r
100 #define dnsNBNS_QUERY_RESPONSE_FLAGS 0x8500u
\r
103 * Create a socket and bind it to the standard DNS port number. Return the
\r
104 * the created socket - or NULL if the socket could not be created or bound.
\r
106 static Socket_t prvCreateDNSSocket( void );
\r
109 * Create the DNS message in the zero copy buffer passed in the first parameter.
\r
111 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier );
\r
114 * Simple routine that jumps over the NAME field of a resource record.
\r
116 static uint8_t *prvSkipNameField( uint8_t *pucByte );
\r
119 * Process a response packet from a DNS server.
\r
121 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier );
\r
124 * Prepare and send a message to a DNS server. 'xReadTimeOut_ms' will be passed as
\r
125 * zero, in case the user has supplied a call-back function.
\r
127 static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms );
\r
130 * The NBNS and the LLMNR protocol share this reply function.
\r
132 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
\r
133 static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength );
\r
136 #if( ipconfigUSE_NBNS == 1 )
\r
137 static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress );
\r
138 #endif /* ipconfigUSE_NBNS */
\r
140 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
141 static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen );
\r
142 static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp );
\r
144 typedef struct xDNS_CACHE_TABLE_ROW
\r
146 uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */
\r
147 char pcName[ipconfigDNS_CACHE_NAME_LENGTH]; /* The name of the host */
\r
148 uint8_t ucAge; /* A value that is periodically decremented but can also be refreshed by active communication. The ARP cache entry is removed if the value reaches zero. */
\r
151 static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ];
\r
152 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
154 #if( ipconfigUSE_LLMNR == 1 )
\r
155 const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } };
\r
156 #endif /* ipconfigUSE_LLMNR == 1 */
\r
158 /*-----------------------------------------------------------*/
\r
160 #include "pack_struct_start.h"
\r
163 uint16_t usIdentifier;
\r
165 uint16_t usQuestions;
\r
166 uint16_t usAnswers;
\r
167 uint16_t usAuthorityRRs;
\r
168 uint16_t usAdditionalRRs;
\r
170 #include "pack_struct_end.h"
\r
171 typedef struct xDNSMessage DNSMessage_t;
\r
173 /* A DNS query consists of a header, as described in 'struct xDNSMessage'
\r
174 It is followed by 1 or more queries, each one consisting of a name and a tail,
\r
175 with two fields: type and class
\r
177 #include "pack_struct_start.h"
\r
183 #include "pack_struct_end.h"
\r
184 typedef struct xDNSTail DNSTail_t;
\r
186 #if( ipconfigUSE_LLMNR == 1 )
\r
188 #include "pack_struct_start.h"
\r
189 struct xLLMNRAnswer
\r
191 uint8_t ucNameCode;
\r
192 uint8_t ucNameOffset; /* The name is not repeated in the answer, only the offset is given with "0xc0 <offs>" */
\r
196 uint16_t usDataLength;
\r
197 uint32_t ulIPAddress;
\r
199 #include "pack_struct_end.h"
\r
200 typedef struct xLLMNRAnswer LLMNRAnswer_t;
\r
202 #endif /* ipconfigUSE_LLMNR == 1 */
\r
204 #if( ipconfigUSE_NBNS == 1 )
\r
206 #include "pack_struct_start.h"
\r
207 struct xNBNSRequest
\r
209 uint16_t usRequestId;
\r
211 uint16_t ulRequestCount;
\r
212 uint16_t usAnswerRSS;
\r
213 uint16_t usAuthRSS;
\r
214 uint16_t usAdditionalRSS;
\r
215 uint8_t ucNameSpace;
\r
216 uint8_t ucName[ dnsNBNS_ENCODED_NAME_LENGTH ];
\r
217 uint8_t ucNameZero;
\r
221 #include "pack_struct_end.h"
\r
222 typedef struct xNBNSRequest NBNSRequest_t;
\r
224 #include "pack_struct_start.h"
\r
230 uint16_t usDataLength;
\r
231 uint16_t usNbFlags; /* NetBIOS flags 0x6000 : IP-address, big-endian */
\r
232 uint32_t ulIPAddress;
\r
234 #include "pack_struct_end.h"
\r
235 typedef struct xNBNSAnswer NBNSAnswer_t;
\r
237 #endif /* ipconfigUSE_NBNS == 1 */
\r
239 /*-----------------------------------------------------------*/
\r
241 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
242 uint32_t FreeRTOS_dnslookup( const char *pcHostName )
\r
244 uint32_t ulIPAddress = 0UL;
\r
245 prvProcessDNSCache( pcHostName, &ulIPAddress, pdTRUE );
\r
246 return ulIPAddress;
\r
248 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
249 /*-----------------------------------------------------------*/
\r
251 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
253 typedef struct xDNS_Callback {
\r
254 TickType_t xRemaningTime; /* Timeout in ms */
\r
255 FOnDNSEvent pCallbackFunction; /* Function to be called when the address has been found or when a timeout has beeen reached */
\r
256 TimeOut_t xTimeoutState;
\r
258 struct xLIST_ITEM xListItem;
\r
262 static List_t xCallbackList;
\r
264 /* Define FreeRTOS_gethostbyname() as a normal blocking call. */
\r
265 uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
\r
267 return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void* )NULL, 0 );
\r
269 /*-----------------------------------------------------------*/
\r
271 /* Initialise the list of call-back structures. */
\r
272 void vDNSInitialise( void );
\r
273 void vDNSInitialise( void )
\r
275 vListInitialise( &xCallbackList );
\r
277 /*-----------------------------------------------------------*/
\r
279 /* Iterate through the list of call-back structures and remove
\r
280 old entries which have reached a timeout.
\r
281 As soon as the list hase become empty, the DNS timer will be stopped
\r
282 In case pvSearchID is supplied, the user wants to cancel a DNS request
\r
284 void vDNSCheckCallBack( void *pvSearchID );
\r
285 void vDNSCheckCallBack( void *pvSearchID )
\r
287 const ListItem_t *pxIterator;
\r
288 const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
\r
292 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
\r
293 pxIterator != ( const ListItem_t * ) xEnd;
\r
296 DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
297 /* Move to the next item because we might remove this item */
\r
298 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
299 if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) )
\r
301 uxListRemove( &pxCallback->xListItem );
\r
302 vPortFree( pxCallback );
\r
304 else if( xTaskCheckForTimeOut( &pxCallback->xTimeoutState, &pxCallback->xRemaningTime ) != pdFALSE )
\r
306 pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 );
\r
307 uxListRemove( &pxCallback->xListItem );
\r
308 vPortFree( ( void * ) pxCallback );
\r
314 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
316 vIPSetDnsTimerEnableState( pdFALSE );
\r
319 /*-----------------------------------------------------------*/
\r
321 void FreeRTOS_gethostbyname_cancel( void *pvSearchID )
\r
323 /* _HT_ Should better become a new API call to have the IP-task remove the callback */
\r
324 vDNSCheckCallBack( pvSearchID );
\r
326 /*-----------------------------------------------------------*/
\r
328 /* FreeRTOS_gethostbyname_a() was called along with callback parameters.
\r
329 Store them in a list for later reference. */
\r
330 static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier );
\r
331 static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier )
\r
333 size_t lLength = strlen( pcHostName );
\r
334 DNSCallback_t *pxCallback = ( DNSCallback_t * )pvPortMalloc( sizeof( *pxCallback ) + lLength );
\r
336 /* Translate from ms to number of clock ticks. */
\r
337 xTimeout /= portTICK_PERIOD_MS;
\r
338 if( pxCallback != NULL )
\r
340 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
342 /* This is the first one, start the DNS timer to check for timeouts */
\r
343 vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, xTimeout ) );
\r
345 strcpy( pxCallback->pcName, pcHostName );
\r
346 pxCallback->pCallbackFunction = pCallbackFunction;
\r
347 pxCallback->pvSearchID = pvSearchID;
\r
348 pxCallback->xRemaningTime = xTimeout;
\r
349 vTaskSetTimeOutState( &pxCallback->xTimeoutState );
\r
350 listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void* ) pxCallback );
\r
351 listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), xIdentifier );
\r
354 vListInsertEnd( &xCallbackList, &pxCallback->xListItem );
\r
359 /*-----------------------------------------------------------*/
\r
361 /* A DNS reply was received, see if there is any matching entry and
\r
362 call the handler. */
\r
363 static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress );
\r
364 static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress )
\r
366 const ListItem_t *pxIterator;
\r
367 const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
\r
371 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
\r
372 pxIterator != ( const ListItem_t * ) xEnd;
\r
373 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
375 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xIdentifier )
\r
377 DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
378 pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID, ulIPAddress );
\r
379 uxListRemove( &pxCallback->xListItem );
\r
380 vPortFree( pxCallback );
\r
381 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
383 vIPSetDnsTimerEnableState( pdFALSE );
\r
392 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
\r
393 /*-----------------------------------------------------------*/
\r
395 #if( ipconfigDNS_USE_CALLBACKS == 0 )
\r
396 uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
\r
398 uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout )
\r
401 uint32_t ulIPAddress = 0UL;
\r
402 static uint16_t usIdentifier = 0u;
\r
403 TickType_t xReadTimeOut_ms = 1200U;
\r
404 /* Generate a unique identifier for this query. Keep it in a local variable
\r
405 as gethostbyname() may be called from different threads */
\r
406 TickType_t xIdentifier = ( TickType_t )usIdentifier++;
\r
408 /* If a DNS cache is used then check the cache before issuing another DNS
\r
410 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
412 ulIPAddress = FreeRTOS_dnslookup( pcHostName );
\r
413 if( ulIPAddress != 0 )
\r
415 FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );
\r
419 /* prvGetHostByName will be called to start a DNS lookup. */
\r
422 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
424 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
426 if( pCallback != NULL )
\r
428 if( ulIPAddress == 0UL )
\r
430 /* The user has provided a callback function, so do not block on recvfrom() */
\r
431 xReadTimeOut_ms = 0;
\r
432 vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t ) xIdentifier );
\r
436 /* The IP address is known, do the call-back now. */
\r
437 pCallback( pcHostName, pvSearchID, ulIPAddress );
\r
443 if( ulIPAddress == 0UL)
\r
445 ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms );
\r
448 return ulIPAddress;
\r
450 /*-----------------------------------------------------------*/
\r
452 static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms )
\r
454 struct freertos_sockaddr xAddress;
\r
455 Socket_t xDNSSocket;
\r
456 uint32_t ulIPAddress = 0UL;
\r
457 uint8_t *pucUDPPayloadBuffer;
\r
458 static uint32_t ulAddressLength;
\r
459 BaseType_t xAttempt;
\r
461 size_t xPayloadLength, xExpectedPayloadLength;
\r
462 TickType_t xWriteTimeOut_ms = 100U;
\r
464 #if( ipconfigUSE_LLMNR == 1 )
\r
465 BaseType_t bHasDot = pdFALSE;
\r
466 #endif /* ipconfigUSE_LLMNR == 1 */
\r
468 /* If LLMNR is being used then determine if the host name includes a '.' -
\r
469 if not then LLMNR can be used as the lookup method. */
\r
470 #if( ipconfigUSE_LLMNR == 1 )
\r
472 const char *pucPtr;
\r
473 for( pucPtr = pcHostName; *pucPtr; pucPtr++ )
\r
475 if( *pucPtr == '.' )
\r
482 #endif /* ipconfigUSE_LLMNR == 1 */
\r
484 /* Two is added at the end for the count of characters in the first
\r
485 subdomain part and the string end byte. */
\r
486 xExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u;
\r
488 xDNSSocket = prvCreateDNSSocket();
\r
490 if( xDNSSocket != NULL )
\r
492 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xWriteTimeOut_ms, sizeof( TickType_t ) );
\r
493 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xReadTimeOut_ms, sizeof( TickType_t ) );
\r
495 for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ )
\r
497 /* Get a buffer. This uses a maximum delay, but the delay will be
\r
498 capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value
\r
499 still needs to be tested. */
\r
500 pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xExpectedPayloadLength, portMAX_DELAY );
\r
502 if( pucUDPPayloadBuffer != NULL )
\r
504 /* Create the message in the obtained buffer. */
\r
505 xPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, xIdentifier );
\r
507 iptraceSENDING_DNS_REQUEST();
\r
509 /* Obtain the DNS server address. */
\r
510 FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress );
\r
512 /* Send the DNS message. */
\r
513 #if( ipconfigUSE_LLMNR == 1 )
\r
514 if( bHasDot == pdFALSE )
\r
516 /* Use LLMNR addressing. */
\r
517 ( ( DNSMessage_t * ) pucUDPPayloadBuffer) -> usFlags = 0;
\r
518 xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */
\r
519 xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT );
\r
524 /* Use DNS server. */
\r
525 xAddress.sin_addr = ulIPAddress;
\r
526 xAddress.sin_port = dnsDNS_PORT;
\r
531 if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, xPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 )
\r
533 /* Wait for the reply. */
\r
534 lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength );
\r
538 /* The reply was received. Process it. */
\r
539 ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, xIdentifier );
\r
541 /* Finished with the buffer. The zero copy interface
\r
542 is being used, so the buffer must be freed by the
\r
544 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
\r
546 if( ulIPAddress != 0UL )
\r
555 /* The message was not sent so the stack will not be
\r
556 releasing the zero copy - it must be released here. */
\r
557 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
\r
562 /* Finished with the socket. */
\r
563 FreeRTOS_closesocket( xDNSSocket );
\r
566 return ulIPAddress;
\r
568 /*-----------------------------------------------------------*/
\r
570 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier )
\r
572 DNSMessage_t *pxDNSMessageHeader;
\r
573 uint8_t *pucStart, *pucByte;
\r
575 static const DNSMessage_t xDefaultPartDNSHeader =
\r
577 0, /* The identifier will be overwritten. */
\r
578 dnsOUTGOING_FLAGS, /* Flags set for standard query. */
\r
579 dnsONE_QUESTION, /* One question is being asked. */
\r
580 0, /* No replies are included. */
\r
581 0, /* No authorities. */
\r
582 0 /* No additional authorities. */
\r
585 /* Copy in the const part of the header. */
\r
586 memcpy( ( void * ) pucUDPPayloadBuffer, ( void * ) &xDefaultPartDNSHeader, sizeof( xDefaultPartDNSHeader ) );
\r
588 /* Write in a unique identifier. */
\r
589 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
590 pxDNSMessageHeader->usIdentifier = ( uint16_t ) xIdentifier;
\r
592 /* Create the resource record at the end of the header. First
\r
593 find the end of the header. */
\r
594 pucStart = pucUDPPayloadBuffer + sizeof( xDefaultPartDNSHeader );
\r
596 /* Leave a gap for the first length bytes. */
\r
597 pucByte = pucStart + 1;
\r
599 /* Copy in the host name. */
\r
600 strcpy( ( char * ) pucByte, pcHostName );
\r
602 /* Mark the end of the string. */
\r
603 pucByte += strlen( pcHostName );
\r
606 /* Walk the string to replace the '.' characters with byte counts.
\r
607 pucStart holds the address of the byte count. Walking the string
\r
608 starts after the byte count position. */
\r
609 pucByte = pucStart;
\r
615 while( ( *pucByte != 0x00 ) && ( *pucByte != '.' ) )
\r
620 /* Fill in the byte count, then move the pucStart pointer up to
\r
621 the found byte position. */
\r
622 *pucStart = ( uint8_t ) ( ( uint32_t ) pucByte - ( uint32_t ) pucStart );
\r
625 pucStart = pucByte;
\r
627 } while( *pucByte != 0x00 );
\r
629 /* Finish off the record. */
\r
631 pxTail = (DNSTail_t *)( pucByte + 1 );
\r
633 vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
\r
634 vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
\r
636 /* Return the total size of the generated message, which is the space from
\r
637 the last written byte to the beginning of the buffer. */
\r
638 return ( ( uint32_t ) pucByte - ( uint32_t ) pucUDPPayloadBuffer + 1 ) + sizeof( *pxTail );
\r
640 /*-----------------------------------------------------------*/
\r
642 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
644 static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen )
\r
646 BaseType_t xNameLen = 0;
\r
647 /* Determine if the name is the fully coded name, or an offset to the name
\r
648 elsewhere in the message. */
\r
649 if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
\r
651 /* Jump over the two byte offset. */
\r
652 pucByte += sizeof( uint16_t );
\r
657 /* pucByte points to the full name. Walk over the string. */
\r
658 while( *pucByte != 0x00 )
\r
661 if( xNameLen && xNameLen < xLen - 1 )
\r
662 pcName[xNameLen++] = '.';
\r
663 for( xCount = *(pucByte++); xCount--; pucByte++ )
\r
665 if( xNameLen < xLen - 1 )
\r
666 pcName[xNameLen++] = *( ( char * ) pucByte );
\r
675 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
676 /*-----------------------------------------------------------*/
\r
678 static uint8_t *prvSkipNameField( uint8_t *pucByte )
\r
680 /* Determine if the name is the fully coded name, or an offset to the name
\r
681 elsewhere in the message. */
\r
682 if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
\r
684 /* Jump over the two byte offset. */
\r
685 pucByte += sizeof( uint16_t );
\r
690 /* pucByte points to the full name. Walk over the string. */
\r
691 while( *pucByte != 0x00 )
\r
693 /* The number of bytes to jump for each name section is stored in the byte
\r
694 before the name section. */
\r
695 pucByte += ( *pucByte + 1 );
\r
703 /*-----------------------------------------------------------*/
\r
705 uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
707 uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
\r
708 DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
710 prvParseDNSReply( pucUDPPayloadBuffer, ( uint32_t ) pxDNSMessageHeader->usIdentifier );
\r
712 /* The packet was not consumed. */
\r
715 /*-----------------------------------------------------------*/
\r
717 #if( ipconfigUSE_NBNS == 1 )
\r
719 uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
721 UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
722 uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( *pxUDPPacket );
\r
724 prvTreatNBNS( pucUDPPayloadBuffer, pxUDPPacket->xIPHeader.ulSourceIPAddress );
\r
726 /* The packet was not consumed. */
\r
730 #endif /* ipconfigUSE_NBNS */
\r
731 /*-----------------------------------------------------------*/
\r
733 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier )
\r
735 DNSMessage_t *pxDNSMessageHeader;
\r
736 uint32_t ulIPAddress = 0UL;
\r
737 #if( ipconfigUSE_LLMNR == 1 )
\r
738 char *pcRequestedName = NULL;
\r
741 uint16_t x, usDataLength, usQuestions;
\r
742 #if( ipconfigUSE_LLMNR == 1 )
\r
743 uint16_t usType = 0, usClass = 0;
\r
745 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
746 char pcName[128] = ""; /*_RB_ What is the significance of 128? Probably too big to go on the stack for a small MCU but don't know how else it could be made re-entrant. Might be necessary. */
\r
749 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
751 if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier )
\r
753 /* Start at the first byte after the header. */
\r
754 pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t );
\r
756 /* Skip any question records. */
\r
757 usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions );
\r
758 for( x = 0; x < usQuestions; x++ )
\r
760 #if( ipconfigUSE_LLMNR == 1 )
\r
764 pcRequestedName = ( char * ) pucByte;
\r
769 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
772 pucByte = prvReadNameField( pucByte, pcName, sizeof( pcName ) );
\r
775 #endif /* ipconfigUSE_DNS_CACHE */
\r
777 /* Skip the variable length pcName field. */
\r
778 pucByte = prvSkipNameField( pucByte );
\r
781 #if( ipconfigUSE_LLMNR == 1 )
\r
783 /* usChar2u16 returns value in host endianness. */
\r
784 usType = usChar2u16( pucByte );
\r
785 usClass = usChar2u16( pucByte + 2 );
\r
787 #endif /* ipconfigUSE_LLMNR */
\r
789 /* Skip the type and class fields. */
\r
790 pucByte += sizeof( uint32_t );
\r
793 /* Search through the answers records. */
\r
794 pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers );
\r
796 if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS )
\r
798 for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ )
\r
800 pucByte = prvSkipNameField( pucByte );
\r
802 /* Is the type field that of an A record? */
\r
803 if( usChar2u16( pucByte ) == dnsTYPE_A_HOST )
\r
805 /* This is the required record. Skip the type, class, and
\r
806 time to live fields, plus the first byte of the data
\r
808 pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) + sizeof( uint8_t ) );
\r
810 /* Sanity check the data length. */
\r
811 if( ( size_t ) *pucByte == sizeof( uint32_t ) )
\r
813 /* Skip the second byte of the length. */
\r
816 /* Copy the IP address out of the record. */
\r
817 memcpy( ( void * ) &ulIPAddress, ( void * ) pucByte, sizeof( uint32_t ) );
\r
819 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
821 prvProcessDNSCache( pcName, &ulIPAddress, pdFALSE );
\r
823 #endif /* ipconfigUSE_DNS_CACHE */
\r
824 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
826 /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */
\r
827 vDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress );
\r
829 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
\r
836 /* Skip the type, class and time to live fields. */
\r
837 pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) );
\r
839 /* Determine the length of the data in the field. */
\r
840 memcpy( ( void * ) &usDataLength, ( void * ) pucByte, sizeof( uint16_t ) );
\r
841 usDataLength = FreeRTOS_ntohs( usDataLength );
\r
843 /* Jump over the data length bytes, and the data itself. */
\r
844 pucByte += usDataLength + sizeof( uint16_t );
\r
848 #if( ipconfigUSE_LLMNR == 1 )
\r
849 else if( ( usQuestions != ( uint16_t )0u ) && ( usType == ( uint16_t )dnsTYPE_A_HOST ) && ( usClass == ( uint16_t )dnsCLASS_IN ) )
\r
851 /* If this is not a reply to our DNS request, it might an LLMNR
\r
853 if( xApplicationDNSQueryHook ( ( pcRequestedName + 1 ) ) )
\r
856 NetworkBufferDescriptor_t *pxNewBuffer = NULL;
\r
857 NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
\r
858 LLMNRAnswer_t *pxAnswer;
\r
860 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
\r
862 BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +
\r
863 sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
\r
865 /* The field xDataLength was set to the length of the UDP payload.
\r
866 The answer (reply) will be longer than the request, so the packet
\r
867 must be duplicaed into a bigger buffer */
\r
868 pxNetworkBuffer->xDataLength = xDataLength;
\r
869 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
\r
870 if( pxNewBuffer != NULL )
\r
872 BaseType_t xOffset1, xOffset2;
\r
874 xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer );
\r
875 xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer );
\r
877 pxNetworkBuffer = pxNewBuffer;
\r
878 pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + ipUDP_PAYLOAD_OFFSET_IPv4;
\r
880 pucByte = pucUDPPayloadBuffer + xOffset1;
\r
881 pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 );
\r
882 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
887 /* Just to indicate that the message may not be answered. */
\r
888 pxNetworkBuffer = NULL;
\r
891 if( pxNetworkBuffer != NULL )
\r
893 pxAnswer = (LLMNRAnswer_t *)pucByte;
\r
895 /* Leave 'usIdentifier' and 'usQuestions' untouched. */
\r
896 vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */
\r
897 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
\r
898 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
\r
899 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */
\r
901 pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
\r
902 pxAnswer->ucNameOffset = ( uint8_t )( pcRequestedName - ( char * ) pucUDPPayloadBuffer );
\r
904 vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
\r
905 vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
\r
906 vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE );
\r
907 vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 );
\r
908 vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
\r
910 usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucUDPPayloadBuffer ) );
\r
912 prvReplyDNSMessage( pxNetworkBuffer, usLength );
\r
914 if( pxNewBuffer != NULL )
\r
916 vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
\r
921 #endif /* ipconfigUSE_LLMNR == 1 */
\r
924 return ulIPAddress;
\r
926 /*-----------------------------------------------------------*/
\r
928 #if( ipconfigUSE_NBNS == 1 )
\r
930 static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress )
\r
932 uint16_t usFlags, usType, usClass;
\r
933 uint8_t *pucSource, *pucTarget;
\r
935 uint8_t ucNBNSName[ 17 ];
\r
937 usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) );
\r
939 if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )
\r
941 usType = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
\r
942 usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) );
\r
944 /* Not used for now */
\r
946 /* For NBNS a name is 16 bytes long, written with capitals only.
\r
947 Make sure that the copy is terminated with a zero. */
\r
948 pucTarget = ucNBNSName + sizeof(ucNBNSName ) - 2;
\r
949 pucTarget[ 1 ] = '\0';
\r
951 /* Start with decoding the last 2 bytes. */
\r
952 pucSource = pucUDPPayloadBuffer + ( offsetof( NBNSRequest_t, ucName ) + ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) );
\r
956 ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - 0x41 ) << 4 ) | ( pucSource[ 1 ] - 0x41 ) );
\r
958 /* Make sure there are no trailing spaces in the name. */
\r
959 if( ( ucByte == ' ' ) && ( pucTarget[ 1 ] == '\0' ) )
\r
964 *pucTarget = ucByte;
\r
966 if( pucTarget == ucNBNSName )
\r
975 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
977 if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0 )
\r
979 /* If this is a response from another device,
\r
980 add the name to the DNS cache */
\r
981 prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, pdFALSE );
\r
986 /* Avoid compiler warnings. */
\r
987 ( void ) ulIPAddress;
\r
989 #endif /* ipconfigUSE_DNS_CACHE */
\r
991 if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0 ) &&
\r
992 ( usType == dnsNBNS_TYPE_NET_BIOS ) &&
\r
993 ( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) )
\r
996 DNSMessage_t *pxMessage;
\r
997 NBNSAnswer_t *pxAnswer;
\r
999 /* Someone is looking for a device with ucNBNSName,
\r
1000 prepare a positive reply. */
\r
1001 NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
\r
1003 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
\r
1005 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1006 BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +
\r
1008 sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
\r
1010 /* The field xDataLength was set to the length of the UDP payload.
\r
1011 The answer (reply) will be longer than the request, so the packet
\r
1012 must be duplicated into a bigger buffer */
\r
1013 pxNetworkBuffer->xDataLength = xDataLength;
\r
1014 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
\r
1015 if( pxNewBuffer != NULL )
\r
1017 pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
\r
1018 pxNetworkBuffer = pxNewBuffer;
\r
1022 /* Just prevent that a reply will be sent */
\r
1023 pxNetworkBuffer = NULL;
\r
1027 /* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */
\r
1028 if( pxNetworkBuffer != NULL )
\r
1030 pxMessage = (DNSMessage_t *)pucUDPPayloadBuffer;
\r
1032 /* As the fields in the structures are not word-aligned, we have to
\r
1033 copy the values byte-by-byte using macro's vSetField16() and vSetField32() */
\r
1034 vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */
\r
1035 vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 );
\r
1036 vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 );
\r
1037 vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 );
\r
1038 vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 );
\r
1040 pxAnswer = (NBNSAnswer_t *)( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
\r
1042 vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */
\r
1043 vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */
\r
1044 vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE );
\r
1045 vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */
\r
1046 vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS );
\r
1047 vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
\r
1049 usLength = ( uint16_t ) ( offsetof( NBNSRequest_t, usType ) + sizeof( NBNSAnswer_t ) );
\r
1051 prvReplyDNSMessage( pxNetworkBuffer, usLength );
\r
1057 #endif /* ipconfigUSE_NBNS */
\r
1058 /*-----------------------------------------------------------*/
\r
1060 static Socket_t prvCreateDNSSocket( void )
\r
1062 static Socket_t xSocket = NULL;
\r
1063 struct freertos_sockaddr xAddress;
\r
1064 BaseType_t xReturn;
\r
1065 TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
\r
1067 /* This must be the first time this function has been called. Create
\r
1069 xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
\r
1071 /* Auto bind the port. */
\r
1072 xAddress.sin_port = 0u;
\r
1073 xReturn = FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
\r
1075 /* Check the bind was successful, and clean up if not. */
\r
1076 if( xReturn != 0 )
\r
1078 FreeRTOS_closesocket( xSocket );
\r
1083 /* Set the send and receive timeouts. */
\r
1084 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
1085 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
1090 /*-----------------------------------------------------------*/
\r
1092 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
\r
1094 static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength )
\r
1096 UDPPacket_t *pxUDPPacket;
\r
1097 IPHeader_t *pxIPHeader;
\r
1098 UDPHeader_t *pxUDPHeader;
\r
1100 pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer;
\r
1101 pxIPHeader = &pxUDPPacket->xIPHeader;
\r
1102 pxUDPHeader = &pxUDPPacket->xUDPHeader;
\r
1103 /* HT: started using defines like 'ipSIZE_OF_xxx' */
\r
1104 pxIPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER );
\r
1105 /* HT:endian: should not be translated, copying from packet to packet */
\r
1106 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
1107 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1108 pxIPHeader->ucTimeToLive = ipconfigUDP_TIME_TO_LIVE;
\r
1109 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
1110 usPacketIdentifier++;
\r
1111 pxUDPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_UDP_HEADER );
\r
1112 vFlip_16( pxUDPPacket->xUDPHeader.usSourcePort, pxUDPPacket->xUDPHeader.usDestinationPort );
\r
1114 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
1116 /* calculate the IP header checksum */
\r
1117 pxIPHeader->usHeaderChecksum = 0x00;
\r
1118 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
1119 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
1121 /* calculate the UDP checksum for outgoing package */
\r
1122 usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pdTRUE );
\r
1126 /* Important: tell NIC driver how many bytes must be sent */
\r
1127 pxNetworkBuffer->xDataLength = ( size_t ) ( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER );
\r
1129 /* This function will fill in the eth addresses and send the packet */
\r
1130 vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
\r
1133 #endif /* ipconfigUSE_NBNS == 1 || ipconfigUSE_LLMNR == 1 */
\r
1134 /*-----------------------------------------------------------*/
\r
1136 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
1138 static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp )
\r
1141 BaseType_t xFound = pdFALSE;
\r
1142 static BaseType_t xFreeEntry = 0;
\r
1144 /* For each entry in the DNS cache table. */
\r
1145 for( x = 0; x < ipconfigDNS_CACHE_ENTRIES; x++ )
\r
1147 if( xDNSCache[ x ].pcName[ 0 ] == 0 )
\r
1152 if( strncmp( xDNSCache[ x ].pcName, pcName, sizeof( xDNSCache[ x ].pcName ) ) == 0 )
\r
1154 /* Is this function called for a lookup or to add/update an IP address? */
\r
1155 if( xLookUp != pdFALSE )
\r
1157 *pulIP = xDNSCache[ x ].ulIPAddress;
\r
1161 xDNSCache[ x ].ulIPAddress = *pulIP;
\r
1169 if( xFound == pdFALSE )
\r
1171 if( xLookUp != pdFALSE )
\r
1177 /* Called to add or update an item */
\r
1178 strncpy( xDNSCache[ xFreeEntry ].pcName, pcName, sizeof( xDNSCache[ xFreeEntry ].pcName ) );
\r
1179 xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP;
\r
1182 if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES )
\r
1189 if( ( xLookUp == 0 ) || ( *pulIP != 0 ) )
\r
1191 FreeRTOS_debug_printf( ( "prvProcessDNSCache: %s: '%s' @ %lxip\n", xLookUp ? "look-up" : "add", pcName, FreeRTOS_ntohl( *pulIP ) ) );
\r
1195 #endif /* ipconfigUSE_DNS_CACHE */
\r
1197 #endif /* ipconfigUSE_DNS != 0 */
\r