xref: /FreeRTOS-Plus-TCP-v3.1.0/source/FreeRTOS_UDP_IP.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_UDP_IP.c
30  * @brief This file has the source code for the UDP-IP functionality of the FreeRTOS+TCP
31  *        network stack.
32  */
33 
34 /* Standard includes. */
35 #include <stdint.h>
36 #include <stdio.h>
37 
38 /* FreeRTOS includes. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 #include "queue.h"
42 #include "semphr.h"
43 #include "event_groups.h"
44 #include "list.h"
45 
46 /* FreeRTOS+TCP includes. */
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "FreeRTOS_UDP_IP.h"
51 #include "FreeRTOS_ARP.h"
52 #include "FreeRTOS_DNS.h"
53 #include "FreeRTOS_DHCP.h"
54 #include "FreeRTOS_IP_Utils.h"
55 #include "NetworkInterface.h"
56 #include "NetworkBufferManagement.h"
57 
58 #if ( ipconfigUSE_DNS == 1 )
59     #include "FreeRTOS_DNS.h"
60 #endif
61 
62 /** @brief The expected IP version and header length coded into the IP header itself. */
63 #define ipIP_VERSION_AND_HEADER_LENGTH_BYTE    ( ( uint8_t ) 0x45 )
64 
65 /** @brief Part of the Ethernet and IP headers are always constant when sending an IPv4
66  * UDP packet.  This array defines the constant parts, allowing this part of the
67  * packet to be filled in using a simple memcpy() instead of individual writes. */
68 /*lint -e708 (Info -- union initialization). */
69 UDPPacketHeader_t xDefaultPartUDPPacketHeader =
70 {
71     /* .ucBytes : */
72     {
73         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* Ethernet source MAC address. */
74         0x08, 0x00,                          /* Ethernet frame type. */
75         ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
76         0x00,                                /* ucDifferentiatedServicesCode. */
77         0x00, 0x00,                          /* usLength. */
78         0x00, 0x00,                          /* usIdentification. */
79         0x00, 0x00,                          /* usFragmentOffset. */
80         ipconfigUDP_TIME_TO_LIVE,            /* ucTimeToLive */
81         ipPROTOCOL_UDP,                      /* ucProtocol. */
82         0x00, 0x00,                          /* usHeaderChecksum. */
83         0x00, 0x00, 0x00, 0x00               /* Source IP address. */
84     }
85 };
86 /*-----------------------------------------------------------*/
87 
88 /**
89  * @brief Process the generated UDP packet and do other checks before sending the
90  *        packet such as ARP cache check and address resolution.
91  *
92  * @param[in] pxNetworkBuffer: The network buffer carrying the packet.
93  */
vProcessGeneratedUDPPacket(NetworkBufferDescriptor_t * const pxNetworkBuffer)94 void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
95 {
96     UDPPacket_t * pxUDPPacket;
97     IPHeader_t * pxIPHeader;
98     eARPLookupResult_t eReturned;
99     uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress;
100     size_t uxPayloadSize;
101     /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
102     const void * pvCopySource;
103     void * pvCopyDest;
104 
105     /* Map the UDP packet onto the start of the frame. */
106 
107     /* MISRA Ref 11.3.1 [Misaligned access] */
108 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
109     /* coverity[misra_c_2012_rule_11_3_violation] */
110     pxUDPPacket = ( ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
111 
112     #if ipconfigSUPPORT_OUTGOING_PINGS == 1
113         if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
114         {
115             uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( ICMPPacket_t );
116         }
117         else
118     #endif
119     {
120         uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
121     }
122 
123     /* Determine the ARP cache status for the requested IP address. */
124     eReturned = eARPGetCacheEntry( &( ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
125 
126     if( eReturned != eCantSendPacket )
127     {
128         if( eReturned == eARPCacheHit )
129         {
130             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
131                 uint8_t ucSocketOptions;
132             #endif
133             iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
134 
135             /* Create short cuts to the data within the packet. */
136             pxIPHeader = &( pxUDPPacket->xIPHeader );
137 
138             #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
139 
140                 /* Is it possible that the packet is not actually a UDP packet
141                  * after all, but an ICMP packet. */
142                 if( pxNetworkBuffer->usPort != ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
143             #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
144             {
145                 UDPHeader_t * pxUDPHeader;
146 
147                 pxUDPHeader = &( pxUDPPacket->xUDPHeader );
148 
149                 pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
150                 pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
151                 pxUDPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( UDPHeader_t ) );
152                 pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength );
153                 pxUDPHeader->usChecksum = 0U;
154             }
155 
156             /* memcpy() the constant parts of the header information into
157              * the correct location within the packet.  This fills in:
158              *  xEthernetHeader.xSourceAddress
159              *  xEthernetHeader.usFrameType
160              *  xIPHeader.ucVersionHeaderLength
161              *  xIPHeader.ucDifferentiatedServicesCode
162              *  xIPHeader.usLength
163              *  xIPHeader.usIdentification
164              *  xIPHeader.usFragmentOffset
165              *  xIPHeader.ucTimeToLive
166              *  xIPHeader.ucProtocol
167              * and
168              *  xIPHeader.usHeaderChecksum
169              */
170 
171             /* Save options now, as they will be overwritten by memcpy */
172             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
173                 {
174                     ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ];
175                 }
176             #endif
177 
178             /*
179              * Offset the memcpy by the size of a MAC address to start at the packet's
180              * Ethernet header 'source' MAC address; the preceding 'destination' should not be altered.
181              */
182 
183             /*
184              * Use helper variables for memcpy() to remain
185              * compliant with MISRA Rule 21.15.  These should be
186              * optimized away.
187              */
188             pvCopySource = xDefaultPartUDPPacketHeader.ucBytes;
189             /* The Ethernet source address is at offset 6. */
190             pvCopyDest = &pxNetworkBuffer->pucEthernetBuffer[ sizeof( MACAddress_t ) ];
191             ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartUDPPacketHeader ) );
192 
193             #if ipconfigSUPPORT_OUTGOING_PINGS == 1
194                 if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
195                 {
196                     pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
197                     pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( ICMPHeader_t ) );
198                 }
199                 else
200             #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
201             {
202                 pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) );
203             }
204 
205             pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
206             pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
207 
208             /* The stack doesn't support fragments, so the fragment offset field must always be zero.
209              * The header was never memset to zero, so set both the fragment offset and fragmentation flags in one go.
210              */
211             #if ( ipconfigFORCE_IP_DONT_FRAGMENT != 0 )
212                 pxIPHeader->usFragmentOffset = ipFRAGMENT_FLAGS_DONT_FRAGMENT;
213             #else
214                 pxIPHeader->usFragmentOffset = 0U;
215             #endif
216 
217             #if ( ipconfigUSE_LLMNR == 1 )
218                 {
219                     /* LLMNR messages are typically used on a LAN and they're
220                      * not supposed to cross routers */
221                     if( pxNetworkBuffer->ulIPAddress == ipLLMNR_IP_ADDR )
222                     {
223                         pxIPHeader->ucTimeToLive = 0x01;
224                     }
225                 }
226             #endif
227 
228             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
229                 {
230                     pxIPHeader->usHeaderChecksum = 0U;
231                     pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
232                     pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
233 
234                     if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0U )
235                     {
236                         ( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
237                     }
238                     else
239                     {
240                         pxUDPPacket->xUDPHeader.usChecksum = 0U;
241                     }
242                 }
243             #endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) */
244         }
245         else if( eReturned == eARPCacheMiss )
246         {
247             /* Add an entry to the ARP table with a null hardware address.
248              * This allows the ARP timer to know that an ARP reply is
249              * outstanding, and perform retransmissions if necessary. */
250             vARPRefreshCacheEntry( NULL, ulIPAddress );
251 
252             /* Generate an ARP for the required IP address. */
253             iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
254             pxNetworkBuffer->ulIPAddress = ulIPAddress;
255             vARPGenerateRequestPacket( pxNetworkBuffer );
256         }
257         else
258         {
259             /* The lookup indicated that an ARP request has already been
260              * sent out for the queried IP address. */
261             eReturned = eCantSendPacket;
262         }
263     }
264 
265     if( eReturned != eCantSendPacket )
266     {
267         /* The network driver is responsible for freeing the network buffer
268          * after the packet has been sent. */
269 
270         #if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
271             {
272                 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
273                 {
274                     BaseType_t xIndex;
275 
276                     for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
277                     {
278                         pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
279                     }
280 
281                     pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
282                 }
283             }
284         #endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
285         iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
286         ( void ) xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
287     }
288     else
289     {
290         /* The packet can't be sent (DHCP not completed?).  Just drop the
291          * packet. */
292         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
293     }
294 }
295 /*-----------------------------------------------------------*/
296 
297 /**
298  * @brief Process the received UDP packet.
299  *
300  * @param[in] pxNetworkBuffer: The network buffer carrying the UDP packet.
301  * @param[in] usPort: The port number on which this packet was received.
302  * @param[out] pxIsWaitingForARPResolution: If the packet is awaiting ARP resolution,
303  *             this pointer will be set to pdTRUE. pdFALSE otherwise.
304  *
305  * @return pdPASS in case the UDP packet could be processed. Else pdFAIL is returned.
306  */
xProcessReceivedUDPPacket(NetworkBufferDescriptor_t * pxNetworkBuffer,uint16_t usPort,BaseType_t * pxIsWaitingForARPResolution)307 BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
308                                       uint16_t usPort,
309                                       BaseType_t * pxIsWaitingForARPResolution )
310 {
311     BaseType_t xReturn = pdPASS;
312     FreeRTOS_Socket_t * pxSocket;
313 
314     configASSERT( pxNetworkBuffer != NULL );
315     configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
316 
317     /* Map the ethernet buffer to the UDPPacket_t struct for easy access to the fields. */
318 
319     /* MISRA Ref 11.3.1 [Misaligned access] */
320 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
321     /* coverity[misra_c_2012_rule_11_3_violation] */
322     const UDPPacket_t * pxUDPPacket = ( ( const UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
323 
324     /* Caller must check for minimum packet size. */
325     pxSocket = pxUDPSocketLookup( usPort );
326 
327     *pxIsWaitingForARPResolution = pdFALSE;
328 
329     do
330     {
331         if( pxSocket != NULL )
332         {
333             if( *ipLOCAL_IP_ADDRESS_POINTER != 0U )
334             {
335                 if( xCheckRequiresARPResolution( pxNetworkBuffer ) == pdTRUE )
336                 {
337                     /* Mark this packet as waiting for ARP resolution. */
338                     *pxIsWaitingForARPResolution = pdTRUE;
339 
340                     /* Return a fail to show that the frame will not be processed right now. */
341                     xReturn = pdFAIL;
342                     break;
343                 }
344                 else
345                 {
346                     /* IP address is not on the same subnet, ARP table can be updated.
347                      * When refreshing the ARP cache with received UDP packets we must be
348                      * careful;  hundreds of broadcast messages may pass and if we're not
349                      * handling them, no use to fill the ARP cache with those IP addresses.
350                      */
351                     vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
352                 }
353             }
354             else
355             {
356                 /* During DHCP, IP address is not assigned and therefore ARP verification
357                  * is not possible. */
358             }
359 
360             #if ( ipconfigUSE_CALLBACKS == 1 )
361                 {
362                     /* Did the owner of this socket register a reception handler ? */
363                     if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) )
364                     {
365                         struct freertos_sockaddr xSourceAddress, destinationAddress;
366                         void * pcData = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
367                         FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive;
368                         xSourceAddress.sin_port = pxNetworkBuffer->usPort;
369                         xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress;
370                         destinationAddress.sin_port = usPort;
371                         destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
372 
373                         /* The value of 'xDataLength' was proven to be at least the size of a UDP packet in prvProcessIPPacket(). */
374                         if( xHandler( ( Socket_t ) pxSocket,
375                                       ( void * ) pcData,
376                                       ( size_t ) ( pxNetworkBuffer->xDataLength - ipUDP_PAYLOAD_OFFSET_IPv4 ),
377                                       &( xSourceAddress ),
378                                       &( destinationAddress ) ) != 0 )
379                         {
380                             xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */
381                         }
382                     }
383                 }
384             #endif /* ipconfigUSE_CALLBACKS */
385 
386             #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
387                 {
388                     if( xReturn == pdPASS )
389                     {
390                         if( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets )
391                         {
392                             FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n",
393                                                      listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ),
394                                                      pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) );
395                             xReturn = pdFAIL; /* we did not consume or release the buffer */
396                         }
397                     }
398                 }
399             #endif /* if ( ipconfigUDP_MAX_RX_PACKETS > 0U ) */
400 
401             #if ( ipconfigUSE_CALLBACKS == 1 ) || ( ipconfigUDP_MAX_RX_PACKETS > 0U )
402                 if( xReturn == pdPASS ) /*lint !e774: Boolean within 'if' always evaluates to True, depending on configuration. [MISRA 2012 Rule 14.3, required. */
403             #else
404                 /* xReturn is still pdPASS. */
405             #endif
406             {
407                 vTaskSuspendAll();
408                 {
409                     taskENTER_CRITICAL();
410                     {
411                         /* Add the network packet to the list of packets to be
412                          * processed by the socket. */
413                         vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
414                     }
415                     taskEXIT_CRITICAL();
416                 }
417                 ( void ) xTaskResumeAll();
418 
419                 /* Set the socket's receive event */
420                 if( pxSocket->xEventGroup != NULL )
421                 {
422                     ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_RECEIVE );
423                 }
424 
425                 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
426                     {
427                         if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_READ ) ) != 0U ) )
428                         {
429                             ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_READ );
430                         }
431                     }
432                 #endif
433 
434                 #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
435                     {
436                         if( pxSocket->pxUserSemaphore != NULL )
437                         {
438                             ( void ) xSemaphoreGive( pxSocket->pxUserSemaphore );
439                         }
440                     }
441                 #endif
442 
443                 #if ( ipconfigUSE_DHCP == 1 )
444                     {
445                         if( xIsDHCPSocket( pxSocket ) != 0 )
446                         {
447                             ( void ) xSendDHCPEvent();
448                         }
449                     }
450                 #endif
451             }
452         }
453         else
454         {
455             /* There is no socket listening to the target port, but still it might
456              * be for this node. */
457 
458             #if ( ipconfigUSE_DNS == 1 ) && ( ipconfigDNS_USE_CALLBACKS == 1 )
459 
460                 /* A DNS reply, check for the source port.  Although the DNS client
461                  * does open a UDP socket to send a messages, this socket will be
462                  * closed after a short timeout.  Messages that come late (after the
463                  * socket is closed) will be treated here. */
464                 if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ( uint16_t ) ipDNS_PORT )
465                 {
466                     vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
467                     xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
468                 }
469                 else
470             #endif
471 
472             #if ( ipconfigUSE_LLMNR == 1 )
473                 /* A LLMNR request, check for the destination port. */
474                 if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) ||
475                     ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) )
476                 {
477                     vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
478                     xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
479                 }
480                 else
481             #endif /* ipconfigUSE_LLMNR */
482 
483             #if ( ipconfigUSE_NBNS == 1 )
484                 /* a NetBIOS request, check for the destination port */
485                 if( ( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) ||
486                     ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipNBNS_PORT ) ) )
487                 {
488                     vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
489                     xReturn = ( BaseType_t ) ulNBNSHandlePacket( pxNetworkBuffer );
490                 }
491                 else
492             #endif /* ipconfigUSE_NBNS */
493             {
494                 xReturn = pdFAIL;
495             }
496         }
497     } while( ipFALSE_BOOL );
498 
499     return xReturn;
500 }
501 /*-----------------------------------------------------------*/
502