2 * FreeRTOS+TCP V2.0.1
\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://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* Standard includes. */
\r
31 /* FreeRTOS includes. */
\r
32 #include "FreeRTOS.h"
\r
38 /* FreeRTOS+TCP includes. */
\r
39 #include "FreeRTOS_IP.h"
\r
40 #include "FreeRTOS_Sockets.h"
\r
41 #include "FreeRTOS_IP_Private.h"
\r
42 #include "FreeRTOS_UDP_IP.h"
\r
43 #include "FreeRTOS_DNS.h"
\r
44 #include "NetworkBufferManagement.h"
\r
45 #include "NetworkInterface.h"
\r
46 #include "IPTraceMacroDefaults.h"
\r
48 /* Exclude the entire file if DNS is not enabled. */
\r
49 #if( ipconfigUSE_DNS != 0 )
\r
51 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
\r
52 #define dnsDNS_PORT 0x3500u
\r
53 #define dnsONE_QUESTION 0x0100u
\r
54 #define dnsOUTGOING_FLAGS 0x0001u /* Standard query. */
\r
55 #define dnsRX_FLAGS_MASK 0x0f80u /* The bits of interest in the flags field of incoming DNS messages. */
\r
56 #define dnsEXPECTED_RX_FLAGS 0x0080u /* Should be a response, without any errors. */
\r
58 #define dnsDNS_PORT 0x0035u
\r
59 #define dnsONE_QUESTION 0x0001u
\r
60 #define dnsOUTGOING_FLAGS 0x0100u /* Standard query. */
\r
61 #define dnsRX_FLAGS_MASK 0x800fu /* The bits of interest in the flags field of incoming DNS messages. */
\r
62 #define dnsEXPECTED_RX_FLAGS 0x8000u /* Should be a response, without any errors. */
\r
64 #endif /* ipconfigBYTE_ORDER */
\r
66 /* The maximum number of times a DNS request should be sent out if a response
\r
67 is not received, before giving up. */
\r
68 #ifndef ipconfigDNS_REQUEST_ATTEMPTS
\r
69 #define ipconfigDNS_REQUEST_ATTEMPTS 5
\r
72 /* If the top two bits in the first character of a name field are set then the
\r
73 name field is an offset to the string, rather than the string itself. */
\r
74 #define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 )
\r
77 #define dnsNBNS_FLAGS_RESPONSE 0x8000u
\r
78 #define dnsNBNS_FLAGS_OPCODE_MASK 0x7800u
\r
79 #define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000u
\r
80 #define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800u
\r
83 #define dnsTYPE_A_HOST 0x0001u
\r
84 #define dnsCLASS_IN 0x0001u
\r
86 /* LLMNR constants. */
\r
87 #define dnsLLMNR_TTL_VALUE 300000u
\r
88 #define dnsLLMNR_FLAGS_IS_REPONSE 0x8000u
\r
90 /* NBNS constants. */
\r
91 #define dnsNBNS_TTL_VALUE 3600u /* 1 hour valid */
\r
92 #define dnsNBNS_TYPE_NET_BIOS 0x0020u
\r
93 #define dnsNBNS_CLASS_IN 0x0001u
\r
94 #define dnsNBNS_NAME_FLAGS 0x6000u
\r
95 #define dnsNBNS_ENCODED_NAME_LENGTH 32
\r
97 /* If the queried NBNS name matches with the device's name,
\r
98 the query will be responded to with these flags: */
\r
99 #define dnsNBNS_QUERY_RESPONSE_FLAGS 0x8500u
\r
102 * Create a socket and bind it to the standard DNS port number. Return the
\r
103 * the created socket - or NULL if the socket could not be created or bound.
\r
105 static Socket_t prvCreateDNSSocket( void );
\r
108 * Create the DNS message in the zero copy buffer passed in the first parameter.
\r
110 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier );
\r
113 * Simple routine that jumps over the NAME field of a resource record.
\r
115 static uint8_t *prvSkipNameField( uint8_t *pucByte );
\r
118 * Process a response packet from a DNS server.
\r
120 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier );
\r
123 * Prepare and send a message to a DNS server. 'xReadTimeOut_ms' will be passed as
\r
124 * zero, in case the user has supplied a call-back function.
\r
126 static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms );
\r
129 * The NBNS and the LLMNR protocol share this reply function.
\r
131 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
\r
132 static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength );
\r
135 #if( ipconfigUSE_NBNS == 1 )
\r
136 static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress );
\r
137 #endif /* ipconfigUSE_NBNS */
\r
139 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
140 static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen );
\r
141 static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp );
\r
143 typedef struct xDNS_CACHE_TABLE_ROW
\r
145 uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */
\r
146 char pcName[ipconfigDNS_CACHE_NAME_LENGTH]; /* The name of the host */
\r
147 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
150 static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ];
\r
151 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
153 #if( ipconfigUSE_LLMNR == 1 )
\r
154 const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } };
\r
155 #endif /* ipconfigUSE_LLMNR == 1 */
\r
157 /*-----------------------------------------------------------*/
\r
159 #include "pack_struct_start.h"
\r
162 uint16_t usIdentifier;
\r
164 uint16_t usQuestions;
\r
165 uint16_t usAnswers;
\r
166 uint16_t usAuthorityRRs;
\r
167 uint16_t usAdditionalRRs;
\r
169 #include "pack_struct_end.h"
\r
170 typedef struct xDNSMessage DNSMessage_t;
\r
172 /* A DNS query consists of a header, as described in 'struct xDNSMessage'
\r
173 It is followed by 1 or more queries, each one consisting of a name and a tail,
\r
174 with two fields: type and class
\r
176 #include "pack_struct_start.h"
\r
182 #include "pack_struct_end.h"
\r
183 typedef struct xDNSTail DNSTail_t;
\r
185 #if( ipconfigUSE_LLMNR == 1 )
\r
187 #include "pack_struct_start.h"
\r
188 struct xLLMNRAnswer
\r
190 uint8_t ucNameCode;
\r
191 uint8_t ucNameOffset; /* The name is not repeated in the answer, only the offset is given with "0xc0 <offs>" */
\r
195 uint16_t usDataLength;
\r
196 uint32_t ulIPAddress;
\r
198 #include "pack_struct_end.h"
\r
199 typedef struct xLLMNRAnswer LLMNRAnswer_t;
\r
201 #endif /* ipconfigUSE_LLMNR == 1 */
\r
203 #if( ipconfigUSE_NBNS == 1 )
\r
205 #include "pack_struct_start.h"
\r
206 struct xNBNSRequest
\r
208 uint16_t usRequestId;
\r
210 uint16_t ulRequestCount;
\r
211 uint16_t usAnswerRSS;
\r
212 uint16_t usAuthRSS;
\r
213 uint16_t usAdditionalRSS;
\r
214 uint8_t ucNameSpace;
\r
215 uint8_t ucName[ dnsNBNS_ENCODED_NAME_LENGTH ];
\r
216 uint8_t ucNameZero;
\r
220 #include "pack_struct_end.h"
\r
221 typedef struct xNBNSRequest NBNSRequest_t;
\r
223 #include "pack_struct_start.h"
\r
229 uint16_t usDataLength;
\r
230 uint16_t usNbFlags; /* NetBIOS flags 0x6000 : IP-address, big-endian */
\r
231 uint32_t ulIPAddress;
\r
233 #include "pack_struct_end.h"
\r
234 typedef struct xNBNSAnswer NBNSAnswer_t;
\r
236 #endif /* ipconfigUSE_NBNS == 1 */
\r
238 /*-----------------------------------------------------------*/
\r
240 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
241 uint32_t FreeRTOS_dnslookup( const char *pcHostName )
\r
243 uint32_t ulIPAddress = 0UL;
\r
244 prvProcessDNSCache( pcHostName, &ulIPAddress, pdTRUE );
\r
245 return ulIPAddress;
\r
247 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
248 /*-----------------------------------------------------------*/
\r
250 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
252 typedef struct xDNS_Callback {
\r
253 TickType_t xRemaningTime; /* Timeout in ms */
\r
254 FOnDNSEvent pCallbackFunction; /* Function to be called when the address has been found or when a timeout has beeen reached */
\r
255 TimeOut_t xTimeoutState;
\r
257 struct xLIST_ITEM xListItem;
\r
261 static List_t xCallbackList;
\r
263 /* Define FreeRTOS_gethostbyname() as a normal blocking call. */
\r
264 uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
\r
266 return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void* )NULL, 0 );
\r
268 /*-----------------------------------------------------------*/
\r
270 /* Initialise the list of call-back structures. */
\r
271 void vDNSInitialise( void );
\r
272 void vDNSInitialise( void )
\r
274 vListInitialise( &xCallbackList );
\r
276 /*-----------------------------------------------------------*/
\r
278 /* Iterate through the list of call-back structures and remove
\r
279 old entries which have reached a timeout.
\r
280 As soon as the list hase become empty, the DNS timer will be stopped
\r
281 In case pvSearchID is supplied, the user wants to cancel a DNS request
\r
283 void vDNSCheckCallBack( void *pvSearchID );
\r
284 void vDNSCheckCallBack( void *pvSearchID )
\r
286 const ListItem_t *pxIterator;
\r
287 const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
\r
291 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
\r
292 pxIterator != ( const ListItem_t * ) xEnd;
\r
295 DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
296 /* Move to the next item because we might remove this item */
\r
297 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator );
\r
298 if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) )
\r
300 uxListRemove( &pxCallback->xListItem );
\r
301 vPortFree( pxCallback );
\r
303 else if( xTaskCheckForTimeOut( &pxCallback->xTimeoutState, &pxCallback->xRemaningTime ) != pdFALSE )
\r
305 pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 );
\r
306 uxListRemove( &pxCallback->xListItem );
\r
307 vPortFree( ( void * ) pxCallback );
\r
313 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
315 vIPSetDnsTimerEnableState( pdFALSE );
\r
318 /*-----------------------------------------------------------*/
\r
320 void FreeRTOS_gethostbyname_cancel( void *pvSearchID )
\r
322 /* _HT_ Should better become a new API call to have the IP-task remove the callback */
\r
323 vDNSCheckCallBack( pvSearchID );
\r
325 /*-----------------------------------------------------------*/
\r
327 /* FreeRTOS_gethostbyname_a() was called along with callback parameters.
\r
328 Store them in a list for later reference. */
\r
329 static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier );
\r
330 static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier )
\r
332 size_t lLength = strlen( pcHostName );
\r
333 DNSCallback_t *pxCallback = ( DNSCallback_t * )pvPortMalloc( sizeof( *pxCallback ) + lLength );
\r
335 /* Translate from ms to number of clock ticks. */
\r
336 xTimeout /= portTICK_PERIOD_MS;
\r
337 if( pxCallback != NULL )
\r
339 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
341 /* This is the first one, start the DNS timer to check for timeouts */
\r
342 vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, xTimeout ) );
\r
344 strcpy( pxCallback->pcName, pcHostName );
\r
345 pxCallback->pCallbackFunction = pCallbackFunction;
\r
346 pxCallback->pvSearchID = pvSearchID;
\r
347 pxCallback->xRemaningTime = xTimeout;
\r
348 vTaskSetTimeOutState( &pxCallback->xTimeoutState );
\r
349 listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void* ) pxCallback );
\r
350 listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), xIdentifier );
\r
353 vListInsertEnd( &xCallbackList, &pxCallback->xListItem );
\r
358 /*-----------------------------------------------------------*/
\r
360 /* A DNS reply was received, see if there is any matching entry and
\r
361 call the handler. */
\r
362 static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress );
\r
363 static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress )
\r
365 const ListItem_t *pxIterator;
\r
366 const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList );
\r
370 for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd );
\r
371 pxIterator != ( const ListItem_t * ) xEnd;
\r
372 pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
\r
374 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xIdentifier )
\r
376 DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
\r
377 pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID, ulIPAddress );
\r
378 uxListRemove( &pxCallback->xListItem );
\r
379 vPortFree( pxCallback );
\r
380 if( listLIST_IS_EMPTY( &xCallbackList ) )
\r
382 vIPSetDnsTimerEnableState( pdFALSE );
\r
391 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
\r
392 /*-----------------------------------------------------------*/
\r
394 #if( ipconfigDNS_USE_CALLBACKS == 0 )
\r
395 uint32_t FreeRTOS_gethostbyname( const char *pcHostName )
\r
397 uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout )
\r
400 uint32_t ulIPAddress = 0UL;
\r
401 static uint16_t usIdentifier = 0u;
\r
402 TickType_t xReadTimeOut_ms = 1200U;
\r
403 /* Generate a unique identifier for this query. Keep it in a local variable
\r
404 as gethostbyname() may be called from different threads */
\r
405 TickType_t xIdentifier = ( TickType_t )usIdentifier++;
\r
407 /* If a DNS cache is used then check the cache before issuing another DNS
\r
409 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
411 ulIPAddress = FreeRTOS_dnslookup( pcHostName );
\r
412 if( ulIPAddress != 0 )
\r
414 FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );
\r
418 /* prvGetHostByName will be called to start a DNS lookup. */
\r
421 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
423 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
425 if( pCallback != NULL )
\r
427 if( ulIPAddress == 0UL )
\r
429 /* The user has provided a callback function, so do not block on recvfrom() */
\r
430 xReadTimeOut_ms = 0;
\r
431 vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t ) xIdentifier );
\r
435 /* The IP address is known, do the call-back now. */
\r
436 pCallback( pcHostName, pvSearchID, ulIPAddress );
\r
442 if( ulIPAddress == 0UL)
\r
444 ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms );
\r
447 return ulIPAddress;
\r
449 /*-----------------------------------------------------------*/
\r
451 static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms )
\r
453 struct freertos_sockaddr xAddress;
\r
454 Socket_t xDNSSocket;
\r
455 uint32_t ulIPAddress = 0UL;
\r
456 uint8_t *pucUDPPayloadBuffer;
\r
457 static uint32_t ulAddressLength;
\r
458 BaseType_t xAttempt;
\r
460 size_t xPayloadLength, xExpectedPayloadLength;
\r
461 TickType_t xWriteTimeOut_ms = 100U;
\r
463 #if( ipconfigUSE_LLMNR == 1 )
\r
464 BaseType_t bHasDot = pdFALSE;
\r
465 #endif /* ipconfigUSE_LLMNR == 1 */
\r
467 /* If LLMNR is being used then determine if the host name includes a '.' -
\r
468 if not then LLMNR can be used as the lookup method. */
\r
469 #if( ipconfigUSE_LLMNR == 1 )
\r
471 const char *pucPtr;
\r
472 for( pucPtr = pcHostName; *pucPtr; pucPtr++ )
\r
474 if( *pucPtr == '.' )
\r
481 #endif /* ipconfigUSE_LLMNR == 1 */
\r
483 /* Two is added at the end for the count of characters in the first
\r
484 subdomain part and the string end byte. */
\r
485 xExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u;
\r
487 xDNSSocket = prvCreateDNSSocket();
\r
489 if( xDNSSocket != NULL )
\r
491 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xWriteTimeOut_ms, sizeof( TickType_t ) );
\r
492 FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xReadTimeOut_ms, sizeof( TickType_t ) );
\r
494 for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ )
\r
496 /* Get a buffer. This uses a maximum delay, but the delay will be
\r
497 capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value
\r
498 still needs to be tested. */
\r
499 pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xExpectedPayloadLength, portMAX_DELAY );
\r
501 if( pucUDPPayloadBuffer != NULL )
\r
503 /* Create the message in the obtained buffer. */
\r
504 xPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, xIdentifier );
\r
506 iptraceSENDING_DNS_REQUEST();
\r
508 /* Obtain the DNS server address. */
\r
509 FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress );
\r
511 /* Send the DNS message. */
\r
512 #if( ipconfigUSE_LLMNR == 1 )
\r
513 if( bHasDot == pdFALSE )
\r
515 /* Use LLMNR addressing. */
\r
516 ( ( DNSMessage_t * ) pucUDPPayloadBuffer) -> usFlags = 0;
\r
517 xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */
\r
518 xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT );
\r
523 /* Use DNS server. */
\r
524 xAddress.sin_addr = ulIPAddress;
\r
525 xAddress.sin_port = dnsDNS_PORT;
\r
530 if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, xPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 )
\r
532 /* Wait for the reply. */
\r
533 lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength );
\r
537 /* The reply was received. Process it. */
\r
538 ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, xIdentifier );
\r
540 /* Finished with the buffer. The zero copy interface
\r
541 is being used, so the buffer must be freed by the
\r
543 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
\r
545 if( ulIPAddress != 0UL )
\r
554 /* The message was not sent so the stack will not be
\r
555 releasing the zero copy - it must be released here. */
\r
556 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer );
\r
561 /* Finished with the socket. */
\r
562 FreeRTOS_closesocket( xDNSSocket );
\r
565 return ulIPAddress;
\r
567 /*-----------------------------------------------------------*/
\r
569 static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier )
\r
571 DNSMessage_t *pxDNSMessageHeader;
\r
572 uint8_t *pucStart, *pucByte;
\r
574 static const DNSMessage_t xDefaultPartDNSHeader =
\r
576 0, /* The identifier will be overwritten. */
\r
577 dnsOUTGOING_FLAGS, /* Flags set for standard query. */
\r
578 dnsONE_QUESTION, /* One question is being asked. */
\r
579 0, /* No replies are included. */
\r
580 0, /* No authorities. */
\r
581 0 /* No additional authorities. */
\r
584 /* Copy in the const part of the header. */
\r
585 memcpy( ( void * ) pucUDPPayloadBuffer, ( void * ) &xDefaultPartDNSHeader, sizeof( xDefaultPartDNSHeader ) );
\r
587 /* Write in a unique identifier. */
\r
588 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
589 pxDNSMessageHeader->usIdentifier = ( uint16_t ) xIdentifier;
\r
591 /* Create the resource record at the end of the header. First
\r
592 find the end of the header. */
\r
593 pucStart = pucUDPPayloadBuffer + sizeof( xDefaultPartDNSHeader );
\r
595 /* Leave a gap for the first length bytes. */
\r
596 pucByte = pucStart + 1;
\r
598 /* Copy in the host name. */
\r
599 strcpy( ( char * ) pucByte, pcHostName );
\r
601 /* Mark the end of the string. */
\r
602 pucByte += strlen( pcHostName );
\r
605 /* Walk the string to replace the '.' characters with byte counts.
\r
606 pucStart holds the address of the byte count. Walking the string
\r
607 starts after the byte count position. */
\r
608 pucByte = pucStart;
\r
614 while( ( *pucByte != 0x00 ) && ( *pucByte != '.' ) )
\r
619 /* Fill in the byte count, then move the pucStart pointer up to
\r
620 the found byte position. */
\r
621 *pucStart = ( uint8_t ) ( ( uint32_t ) pucByte - ( uint32_t ) pucStart );
\r
624 pucStart = pucByte;
\r
626 } while( *pucByte != 0x00 );
\r
628 /* Finish off the record. */
\r
630 pxTail = (DNSTail_t *)( pucByte + 1 );
\r
632 vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
\r
633 vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
\r
635 /* Return the total size of the generated message, which is the space from
\r
636 the last written byte to the beginning of the buffer. */
\r
637 return ( ( uint32_t ) pucByte - ( uint32_t ) pucUDPPayloadBuffer + 1 ) + sizeof( *pxTail );
\r
639 /*-----------------------------------------------------------*/
\r
641 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
643 static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen )
\r
645 BaseType_t xNameLen = 0;
\r
646 /* Determine if the name is the fully coded name, or an offset to the name
\r
647 elsewhere in the message. */
\r
648 if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
\r
650 /* Jump over the two byte offset. */
\r
651 pucByte += sizeof( uint16_t );
\r
656 /* pucByte points to the full name. Walk over the string. */
\r
657 while( *pucByte != 0x00 )
\r
660 if( xNameLen && xNameLen < xLen - 1 )
\r
661 pcName[xNameLen++] = '.';
\r
662 for( xCount = *(pucByte++); xCount--; pucByte++ )
\r
664 if( xNameLen < xLen - 1 )
\r
665 pcName[xNameLen++] = *( ( char * ) pucByte );
\r
674 #endif /* ipconfigUSE_DNS_CACHE == 1 */
\r
675 /*-----------------------------------------------------------*/
\r
677 static uint8_t *prvSkipNameField( uint8_t *pucByte )
\r
679 /* Determine if the name is the fully coded name, or an offset to the name
\r
680 elsewhere in the message. */
\r
681 if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
\r
683 /* Jump over the two byte offset. */
\r
684 pucByte += sizeof( uint16_t );
\r
689 /* pucByte points to the full name. Walk over the string. */
\r
690 while( *pucByte != 0x00 )
\r
692 /* The number of bytes to jump for each name section is stored in the byte
\r
693 before the name section. */
\r
694 pucByte += ( *pucByte + 1 );
\r
702 /*-----------------------------------------------------------*/
\r
704 uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
706 uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
\r
707 DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
709 prvParseDNSReply( pucUDPPayloadBuffer, ( uint32_t ) pxDNSMessageHeader->usIdentifier );
\r
711 /* The packet was not consumed. */
\r
714 /*-----------------------------------------------------------*/
\r
716 #if( ipconfigUSE_NBNS == 1 )
\r
718 uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer )
\r
720 UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
721 uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( *pxUDPPacket );
\r
723 prvTreatNBNS( pucUDPPayloadBuffer, pxUDPPacket->xIPHeader.ulSourceIPAddress );
\r
725 /* The packet was not consumed. */
\r
729 #endif /* ipconfigUSE_NBNS */
\r
730 /*-----------------------------------------------------------*/
\r
732 static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier )
\r
734 DNSMessage_t *pxDNSMessageHeader;
\r
735 uint32_t ulIPAddress = 0UL;
\r
736 #if( ipconfigUSE_LLMNR == 1 )
\r
737 char *pcRequestedName = NULL;
\r
740 uint16_t x, usDataLength, usQuestions;
\r
741 #if( ipconfigUSE_LLMNR == 1 )
\r
742 uint16_t usType = 0, usClass = 0;
\r
744 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
745 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
748 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
750 if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier )
\r
752 /* Start at the first byte after the header. */
\r
753 pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t );
\r
755 /* Skip any question records. */
\r
756 usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions );
\r
757 for( x = 0; x < usQuestions; x++ )
\r
759 #if( ipconfigUSE_LLMNR == 1 )
\r
763 pcRequestedName = ( char * ) pucByte;
\r
768 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
771 pucByte = prvReadNameField( pucByte, pcName, sizeof( pcName ) );
\r
774 #endif /* ipconfigUSE_DNS_CACHE */
\r
776 /* Skip the variable length pcName field. */
\r
777 pucByte = prvSkipNameField( pucByte );
\r
780 #if( ipconfigUSE_LLMNR == 1 )
\r
782 /* usChar2u16 returns value in host endianness. */
\r
783 usType = usChar2u16( pucByte );
\r
784 usClass = usChar2u16( pucByte + 2 );
\r
786 #endif /* ipconfigUSE_LLMNR */
\r
788 /* Skip the type and class fields. */
\r
789 pucByte += sizeof( uint32_t );
\r
792 /* Search through the answers records. */
\r
793 pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers );
\r
795 if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS )
\r
797 for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ )
\r
799 pucByte = prvSkipNameField( pucByte );
\r
801 /* Is the type field that of an A record? */
\r
802 if( usChar2u16( pucByte ) == dnsTYPE_A_HOST )
\r
804 /* This is the required record. Skip the type, class, and
\r
805 time to live fields, plus the first byte of the data
\r
807 pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) + sizeof( uint8_t ) );
\r
809 /* Sanity check the data length. */
\r
810 if( ( size_t ) *pucByte == sizeof( uint32_t ) )
\r
812 /* Skip the second byte of the length. */
\r
815 /* Copy the IP address out of the record. */
\r
816 memcpy( ( void * ) &ulIPAddress, ( void * ) pucByte, sizeof( uint32_t ) );
\r
818 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
820 prvProcessDNSCache( pcName, &ulIPAddress, pdFALSE );
\r
822 #endif /* ipconfigUSE_DNS_CACHE */
\r
823 #if( ipconfigDNS_USE_CALLBACKS != 0 )
\r
825 /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */
\r
826 vDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress );
\r
828 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
\r
835 /* Skip the type, class and time to live fields. */
\r
836 pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) );
\r
838 /* Determine the length of the data in the field. */
\r
839 memcpy( ( void * ) &usDataLength, ( void * ) pucByte, sizeof( uint16_t ) );
\r
840 usDataLength = FreeRTOS_ntohs( usDataLength );
\r
842 /* Jump over the data length bytes, and the data itself. */
\r
843 pucByte += usDataLength + sizeof( uint16_t );
\r
847 #if( ipconfigUSE_LLMNR == 1 )
\r
848 else if( ( usQuestions != ( uint16_t )0u ) && ( usType == ( uint16_t )dnsTYPE_A_HOST ) && ( usClass == ( uint16_t )dnsCLASS_IN ) )
\r
850 /* If this is not a reply to our DNS request, it might an LLMNR
\r
852 if( xApplicationDNSQueryHook ( ( pcRequestedName + 1 ) ) )
\r
855 NetworkBufferDescriptor_t *pxNewBuffer = NULL;
\r
856 NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
\r
857 LLMNRAnswer_t *pxAnswer;
\r
859 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
\r
861 BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +
\r
862 sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
\r
864 /* The field xDataLength was set to the length of the UDP payload.
\r
865 The answer (reply) will be longer than the request, so the packet
\r
866 must be duplicaed into a bigger buffer */
\r
867 pxNetworkBuffer->xDataLength = xDataLength;
\r
868 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
\r
869 if( pxNewBuffer != NULL )
\r
871 BaseType_t xOffset1, xOffset2;
\r
873 xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer );
\r
874 xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer );
\r
876 pxNetworkBuffer = pxNewBuffer;
\r
877 pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + ipUDP_PAYLOAD_OFFSET_IPv4;
\r
879 pucByte = pucUDPPayloadBuffer + xOffset1;
\r
880 pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 );
\r
881 pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
\r
886 /* Just to indicate that the message may not be answered. */
\r
887 pxNetworkBuffer = NULL;
\r
890 if( pxNetworkBuffer != NULL )
\r
892 pxAnswer = (LLMNRAnswer_t *)pucByte;
\r
894 /* Leave 'usIdentifier' and 'usQuestions' untouched. */
\r
895 vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */
\r
896 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
\r
897 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
\r
898 vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */
\r
900 pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
\r
901 pxAnswer->ucNameOffset = ( uint8_t )( pcRequestedName - ( char * ) pucUDPPayloadBuffer );
\r
903 vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */
\r
904 vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
\r
905 vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE );
\r
906 vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 );
\r
907 vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
\r
909 usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucUDPPayloadBuffer ) );
\r
911 prvReplyDNSMessage( pxNetworkBuffer, usLength );
\r
913 if( pxNewBuffer != NULL )
\r
915 vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
\r
920 #endif /* ipconfigUSE_LLMNR == 1 */
\r
923 return ulIPAddress;
\r
925 /*-----------------------------------------------------------*/
\r
927 #if( ipconfigUSE_NBNS == 1 )
\r
929 static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress )
\r
931 uint16_t usFlags, usType, usClass;
\r
932 uint8_t *pucSource, *pucTarget;
\r
934 uint8_t ucNBNSName[ 17 ];
\r
936 usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) );
\r
938 if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )
\r
940 usType = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
\r
941 usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) );
\r
943 /* Not used for now */
\r
945 /* For NBNS a name is 16 bytes long, written with capitals only.
\r
946 Make sure that the copy is terminated with a zero. */
\r
947 pucTarget = ucNBNSName + sizeof(ucNBNSName ) - 2;
\r
948 pucTarget[ 1 ] = '\0';
\r
950 /* Start with decoding the last 2 bytes. */
\r
951 pucSource = pucUDPPayloadBuffer + ( offsetof( NBNSRequest_t, ucName ) + ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) );
\r
955 ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - 0x41 ) << 4 ) | ( pucSource[ 1 ] - 0x41 ) );
\r
957 /* Make sure there are no trailing spaces in the name. */
\r
958 if( ( ucByte == ' ' ) && ( pucTarget[ 1 ] == '\0' ) )
\r
963 *pucTarget = ucByte;
\r
965 if( pucTarget == ucNBNSName )
\r
974 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
976 if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0 )
\r
978 /* If this is a response from another device,
\r
979 add the name to the DNS cache */
\r
980 prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, pdFALSE );
\r
985 /* Avoid compiler warnings. */
\r
986 ( void ) ulIPAddress;
\r
988 #endif /* ipconfigUSE_DNS_CACHE */
\r
990 if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0 ) &&
\r
991 ( usType == dnsNBNS_TYPE_NET_BIOS ) &&
\r
992 ( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) )
\r
995 DNSMessage_t *pxMessage;
\r
996 NBNSAnswer_t *pxAnswer;
\r
998 /* Someone is looking for a device with ucNBNSName,
\r
999 prepare a positive reply. */
\r
1000 NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
\r
1002 if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )
\r
1004 NetworkBufferDescriptor_t *pxNewBuffer;
\r
1005 BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +
\r
1007 sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );
\r
1009 /* The field xDataLength was set to the length of the UDP payload.
\r
1010 The answer (reply) will be longer than the request, so the packet
\r
1011 must be duplicated into a bigger buffer */
\r
1012 pxNetworkBuffer->xDataLength = xDataLength;
\r
1013 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 );
\r
1014 if( pxNewBuffer != NULL )
\r
1016 pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );
\r
1017 pxNetworkBuffer = pxNewBuffer;
\r
1021 /* Just prevent that a reply will be sent */
\r
1022 pxNetworkBuffer = NULL;
\r
1026 /* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */
\r
1027 if( pxNetworkBuffer != NULL )
\r
1029 pxMessage = (DNSMessage_t *)pucUDPPayloadBuffer;
\r
1031 /* As the fields in the structures are not word-aligned, we have to
\r
1032 copy the values byte-by-byte using macro's vSetField16() and vSetField32() */
\r
1033 vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */
\r
1034 vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 );
\r
1035 vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 );
\r
1036 vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 );
\r
1037 vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 );
\r
1039 pxAnswer = (NBNSAnswer_t *)( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) );
\r
1041 vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */
\r
1042 vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */
\r
1043 vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE );
\r
1044 vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */
\r
1045 vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS );
\r
1046 vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) );
\r
1048 usLength = ( uint16_t ) ( offsetof( NBNSRequest_t, usType ) + sizeof( NBNSAnswer_t ) );
\r
1050 prvReplyDNSMessage( pxNetworkBuffer, usLength );
\r
1056 #endif /* ipconfigUSE_NBNS */
\r
1057 /*-----------------------------------------------------------*/
\r
1059 static Socket_t prvCreateDNSSocket( void )
\r
1061 static Socket_t xSocket = NULL;
\r
1062 struct freertos_sockaddr xAddress;
\r
1063 BaseType_t xReturn;
\r
1064 TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
\r
1066 /* This must be the first time this function has been called. Create
\r
1068 xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
\r
1070 /* Auto bind the port. */
\r
1071 xAddress.sin_port = 0u;
\r
1072 xReturn = FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
\r
1074 /* Check the bind was successful, and clean up if not. */
\r
1075 if( xReturn != 0 )
\r
1077 FreeRTOS_closesocket( xSocket );
\r
1082 /* Set the send and receive timeouts. */
\r
1083 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
1084 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
1089 /*-----------------------------------------------------------*/
\r
1091 #if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) )
\r
1093 static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength )
\r
1095 UDPPacket_t *pxUDPPacket;
\r
1096 IPHeader_t *pxIPHeader;
\r
1097 UDPHeader_t *pxUDPHeader;
\r
1099 pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer;
\r
1100 pxIPHeader = &pxUDPPacket->xIPHeader;
\r
1101 pxUDPHeader = &pxUDPPacket->xUDPHeader;
\r
1102 /* HT: started using defines like 'ipSIZE_OF_xxx' */
\r
1103 pxIPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER );
\r
1104 /* HT:endian: should not be translated, copying from packet to packet */
\r
1105 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
1106 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1107 pxIPHeader->ucTimeToLive = ipconfigUDP_TIME_TO_LIVE;
\r
1108 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier );
\r
1109 usPacketIdentifier++;
\r
1110 pxUDPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_UDP_HEADER );
\r
1111 vFlip_16( pxUDPPacket->xUDPHeader.usSourcePort, pxUDPPacket->xUDPHeader.usDestinationPort );
\r
1113 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
\r
1115 /* calculate the IP header checksum */
\r
1116 pxIPHeader->usHeaderChecksum = 0x00;
\r
1117 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
\r
1118 pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
\r
1120 /* calculate the UDP checksum for outgoing package */
\r
1121 usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pdTRUE );
\r
1125 /* Important: tell NIC driver how many bytes must be sent */
\r
1126 pxNetworkBuffer->xDataLength = ( size_t ) ( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER );
\r
1128 /* This function will fill in the eth addresses and send the packet */
\r
1129 vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
\r
1132 #endif /* ipconfigUSE_NBNS == 1 || ipconfigUSE_LLMNR == 1 */
\r
1133 /*-----------------------------------------------------------*/
\r
1135 #if( ipconfigUSE_DNS_CACHE == 1 )
\r
1137 static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp )
\r
1140 BaseType_t xFound = pdFALSE;
\r
1141 static BaseType_t xFreeEntry = 0;
\r
1143 /* For each entry in the DNS cache table. */
\r
1144 for( x = 0; x < ipconfigDNS_CACHE_ENTRIES; x++ )
\r
1146 if( xDNSCache[ x ].pcName[ 0 ] == 0 )
\r
1151 if( strncmp( xDNSCache[ x ].pcName, pcName, sizeof( xDNSCache[ x ].pcName ) ) == 0 )
\r
1153 /* Is this function called for a lookup or to add/update an IP address? */
\r
1154 if( xLookUp != pdFALSE )
\r
1156 *pulIP = xDNSCache[ x ].ulIPAddress;
\r
1160 xDNSCache[ x ].ulIPAddress = *pulIP;
\r
1168 if( xFound == pdFALSE )
\r
1170 if( xLookUp != pdFALSE )
\r
1176 /* Called to add or update an item */
\r
1177 strncpy( xDNSCache[ xFreeEntry ].pcName, pcName, sizeof( xDNSCache[ xFreeEntry ].pcName ) );
\r
1178 xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP;
\r
1181 if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES )
\r
1188 if( ( xLookUp == 0 ) || ( *pulIP != 0 ) )
\r
1190 FreeRTOS_debug_printf( ( "prvProcessDNSCache: %s: '%s' @ %lxip\n", xLookUp ? "look-up" : "add", pcName, FreeRTOS_ntohl( *pulIP ) ) );
\r
1194 #endif /* ipconfigUSE_DNS_CACHE */
\r
1196 #endif /* ipconfigUSE_DNS != 0 */
\r