2 * FreeRTOS+UDP V1.0.3 (C) 2014 Real Time Engineers ltd.
\r
3 * All rights reserved
\r
5 * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license
\r
6 * terms are different to the FreeRTOS license terms.
\r
8 * FreeRTOS+UDP uses a dual license model that allows the software to be used
\r
9 * under a standard GPL open source license, or a commercial license. The
\r
10 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
11 * itself is distributed) requires that all software statically linked with
\r
12 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
13 * Details of both license options follow:
\r
15 * - Open source licensing -
\r
16 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
17 * distributed without charge provided the user adheres to version two of the
\r
18 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
19 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
20 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
22 * - Commercial licensing -
\r
23 * Businesses and individuals that for commercial or other reasons cannot comply
\r
24 * with the terms of the GPL V2 license must obtain a commercial license before
\r
25 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
26 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
27 * and do not require any source files to be changed.
\r
29 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
30 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
31 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
32 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
33 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
34 * implied, expressed, or statutory.
\r
36 * 1 tab == 4 spaces!
\r
38 * http://www.FreeRTOS.org
\r
39 * http://www.FreeRTOS.org/udp
\r
43 /* Standard includes. */
\r
46 /* FreeRTOS includes. */
\r
47 #include "FreeRTOS.h"
\r
53 /* FreeRTOS+UDP includes. */
\r
54 #include "FreeRTOS_UDP_IP.h"
\r
55 #include "FreeRTOS_IP_Private.h"
\r
56 #include "FreeRTOS_Sockets.h"
\r
57 #include "FreeRTOS_DHCP.h"
\r
58 #include "NetworkInterface.h"
\r
59 #include "NetworkBufferManagement.h"
\r
61 /* Sanity check the configuration. */
\r
62 #if configUSE_TIMERS != 1
\r
63 #error configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h to use this file
\r
66 #if configTICK_RATE_HZ > 1000
\r
67 #error configTICK_RATE_HZ must be less than 1000 to use FreeRTOS+UDP
\r
70 #if ( ipconfigEVENT_QUEUE_LENGTH < ( ipconfigNUM_NETWORK_BUFFERS + 5 ) )
\r
71 #error The ipconfigEVENT_QUEUE_LENGTH parameter must be at least ipconfigNUM_NETWORK_BUFFERS + 5
\r
74 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 && ipconfigSUPPORT_OUTGOING_PINGS == 1
\r
75 #error ipconfigSUPPORT_OUTGOING_PINGS can only be set to 1 if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is set to 0 as IP fragmentation is not supported for ICMP (ping) packets
\r
78 #if ( ipconfigNETWORK_MTU < 46 )
\r
79 #error ipconfigNETWORK_MTU must be at least 46.
\r
81 /*-----------------------------------------------------------*/
\r
83 /* The IP header length in bytes. */
\r
84 #define ipIP_HEADER_LENGTH ( 20 )
\r
86 /* IP protocol definitions. */
\r
87 #define ipPROTOCOL_ICMP ( 1 )
\r
88 #define ipPROTOCOL_UDP ( 17 )
\r
90 /* ICMP protocol definitions. */
\r
91 #define ipICMP_ECHO_REQUEST ( ( uint16_t ) 8 )
\r
92 #define ipICMP_ECHO_REPLY ( ( uint16_t ) 0 )
\r
94 /* The expected IP version and header length coded into the IP header itself. */
\r
95 #define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
\r
97 /* Time delay between repeated attempts to initialise the network hardware. */
\r
98 #define ipINITIALISATION_RETRY_DELAY ( ( ( portTickType ) 3000 ) / portTICK_RATE_MS )
\r
100 /* The local MAC address is accessed from within xDefaultPartUDPPacketHeader,
\r
101 rather than duplicated in its own variable. */
\r
102 #define ipLOCAL_MAC_ADDRESS ( xDefaultPartUDPPacketHeader )
\r
104 /* The local IP address is accessed from within xDefaultPartUDPPacketHeader,
\r
105 rather than duplicated in its own variable. */
\r
106 #define ipLOCAL_IP_ADDRESS_POINTER ( ( uint32_t * ) &( xDefaultPartUDPPacketHeader[ 20 ] ) )
\r
108 /* Defines how often the ARP timer callback function is executed. The time is
\r
109 shorted in the Windows simulator as simulated time is not real time. */
\r
111 #define ipARP_TIMER_PERIOD_MS ( 500 ) /* For windows simulator builds. */
\r
113 #define ipARP_TIMER_PERIOD_MS ( 10000 )
\r
116 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
\r
117 driver will filter incoming packets and only pass the stack those packets it
\r
118 considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
\r
119 be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
\r
120 then the Ethernet driver will pass all received packets to the stack, and the
\r
121 stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
\r
122 needs to call eConsiderFrameForProcessing. */
\r
123 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
\r
124 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
\r
126 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
\r
129 /* When the age of an entry in the ARP table reaches this value (it counts down
\r
130 to zero, so this is an old entry) an ARP request will be sent to see if the
\r
131 entry is still valid and can therefore be refreshed. */
\r
132 #define ipMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3 )
\r
134 /* Number of bits to shift to divide by 8. Used to remove the need for a
\r
136 #define ipSHIFT_TO_DIVIDE_BY_8 ( 3U )
\r
138 /* The bit set in the IP header flags to indicate that the IP packet contains
\r
139 a fragment of the eventual total payload, and that more fragments will follow. */
\r
140 #define ipMORE_FRAGMENTS_FLAG_BIT ( 0x2000U )
\r
142 /* ICMP packets are sent using the same function as UDP packets. The port
\r
143 number is used to distinguish between the two, as 0 is an invalid UDP port. */
\r
144 #define ipPACKET_CONTAINS_ICMP_DATA ( 0 )
\r
146 /* The character used to fill ICMP echo requests, and therefore also the
\r
147 character expected to fill ICMP echo replies. */
\r
148 #define ipECHO_DATA_FILL_BYTE 'x'
\r
150 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )
\r
151 #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0xff0f ) /* The bits in the two byte IP header field that make up the fragment offset value. */
\r
153 #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */
\r
154 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
155 #warning Fragment offsets have not been tested on big endian machines.
\r
156 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
157 #endif /* ipconfigBYTE_ORDER */
\r
159 /*-----------------------------------------------------------*/
\r
160 /* Miscellaneous structure and definitions. */
\r
161 /*-----------------------------------------------------------*/
\r
163 typedef struct xARP_CACHE_TABLE_ROW
\r
165 uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */
\r
166 xMACAddress_t xMACAddress; /* The MAC address of an ARP cache entry. */
\r
167 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
172 eARPCacheMiss = 0, /* An ARP table lookup did not find a valid entry. */
\r
173 eARPCacheHit, /* An ARP table lookup found a valid entry. */
\r
174 eCantSendPacket /* There is no IP address, or an ARP is still in progress, so the packet cannot be sent. */
\r
175 } eARPLookupResult_t;
\r
179 eNotFragment = 0, /* The IP packet being sent is not part of a fragment. */
\r
180 eFirstFragment, /* The IP packet being sent is the first in a set of fragmented packets. */
\r
181 eFollowingFragment /* The IP packet being sent is part of a set of fragmented packets. */
\r
182 } eIPFragmentStatus_t;
\r
185 /*-----------------------------------------------------------*/
\r
188 * Called when new data is available from the network interface.
\r
190 static void prvProcessEthernetPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
193 * Called when the application has generated a UDP packet to send.
\r
195 static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
198 * Processes incoming ARP packets.
\r
200 static eFrameProcessingResult_t prvProcessARPPacket( xARPPacket_t * const pxARPFrame );
\r
203 * Process incoming IP packets.
\r
205 static eFrameProcessingResult_t prvProcessIPPacket( const xIPPacket_t * const pxIPPacket, xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
208 * Process incoming ICMP packets.
\r
210 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
211 static eFrameProcessingResult_t prvProcessICMPPacket( xICMPPacket_t * const pxICMPPacket );
\r
212 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
\r
215 * Swap the source and destination addresses in an already constructed Ethernet
\r
216 * frame, and send the frame to the network.
\r
218 static void prvReturnEthernetFrame( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
221 * Return the checksum generated over usDataLengthBytes from pucNextData.
\r
223 static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes, portBASE_TYPE xChecksumIsOffloaded );
\r
226 * The callback function that is assigned to all periodic processing timers -
\r
227 * namely the DHCP timer and the ARP timer.
\r
229 void vIPFunctionsTimerCallback( xTimerHandle xTimer );
\r
232 * Reduce the age count in each entry within the ARP cache. An entry is no
\r
233 * longer considered valid and is deleted if its age reaches zero.
\r
235 static void prvAgeARPCache( void );
\r
238 * If ulIPAddress is already in the ARP cache table then reset the age of the
\r
239 * entry back to its maximum value. If ulIPAddress is not already in the ARP
\r
240 * cache table then add it - replacing the oldest current entry if there is not
\r
241 * a free space available.
\r
243 static void prvRefreshARPCacheEntry( const xMACAddress_t * const pxMACAddress, const uint32_t ulIPAddress );
\r
246 * Creates the pseudo header necessary then generate the checksum over the UDP
\r
247 * packet. Returns the calculated checksum.
\r
249 static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket, portBASE_TYPE xChecksumIsOffloaded );
\r
252 * Look for ulIPAddress in the ARP cache. If the IP address exists, copy the
\r
253 * associated MAC address into pxMACAddress, refresh the ARP cache entry's
\r
254 * age, and return eARPCacheHit. If the IP address does not exist in the ARP
\r
255 * cache return eARPCacheMiss. If the packet cannot be sent for any reason
\r
256 * (maybe DHCP is still in process, or the addressing needs a gateway but there
\r
257 * isn't a gateway defined) then return eCantSendPacket.
\r
259 static eARPLookupResult_t prvGetARPCacheEntry( uint32_t *pulIPAddress, xMACAddress_t * const pxMACAddress );
\r
262 * The main UDP/IP stack processing task. This task receives commands/events
\r
263 * from the network hardware drivers, tasks that are using sockets, and software
\r
264 * timers (such as the ARP timer).
\r
266 static void prvIPTask( void *pvParameters );
\r
269 * Send out an ARP request for the IP address contained in pxNetworkBuffer, and
\r
270 * add an entry into the ARP table that indicates that an ARP reply is
\r
271 * outstanding so re-transmissions can be generated.
\r
273 static void prvGenerateARPRequestPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
276 * Called when outgoing packets are fragmented and require a fragment offset in
\r
277 * their IP headers. Set the fragment offset (which includes the IP flags) and
\r
278 * length from the data passed in the pxFragmentParameters structure.
\r
280 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
281 static void prvCalculateFragmentOffsetAndLength( xIPFragmentParameters_t *pxFragmentParameters, uint16_t *pusFragmentOffset, uint16_t *pusFragmentLength );
\r
282 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
285 * Complete the pxUDPPacket header with the information passed in
\r
286 * pxNetworkBuffer. ucSocketOptions are passed in case the options include
\r
287 * disabling the checksum.
\r
289 static void prvCompleteUDPHeader( xNetworkBufferDescriptor_t *pxNetworkBuffer, xUDPPacket_t *pxUDPPacket, uint8_t ucSocketOptions );
\r
292 * Send the event eEvent to the IP task event queue, using a block time of
\r
293 * zero. Return pdPASS if the message was sent successfully, otherwise return
\r
296 static portBASE_TYPE prvSendEventToIPTask( eIPEvent_t eEvent );
\r
299 * Generate and send an ARP request for the IP address passed in ulIPAddress.
\r
301 static void prvOutputARPRequest( uint32_t ulIPAddress );
\r
304 * Turns around an incoming ping request to convert it into a ping reply.
\r
306 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
\r
307 static eFrameProcessingResult_t prvProcessICMPEchoRequest( xICMPPacket_t * const pxICMPPacket );
\r
308 #endif /* ipconfigREPLY_TO_INCOMING_PINGS */
\r
311 * Processes incoming ping replies. The application callback function
\r
312 * vApplicationPingReplyHook() is called with the results.
\r
314 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
315 static void prvProcessICMPEchoReply( xICMPPacket_t * const pxICMPPacket );
\r
316 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
319 * Called to create a network connection when the stack is first started, or
\r
320 * when the network connection is lost.
\r
322 static void prvProcessNetworkDownEvent( void );
\r
324 /*-----------------------------------------------------------*/
\r
326 /* The queue used to pass events into the UDP task for processing. */
\r
327 xQueueHandle xNetworkEventQueue = NULL;
\r
329 /* The ARP cache. */
\r
330 static xARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
\r
332 /* The timer that triggers ARP events. */
\r
333 static xTimerHandle xARPTimer = NULL;
\r
335 /* Used to ensure network down events cannot be missed when they cannot be
\r
336 posted to the network event queue because the network event queue is already
\r
338 static portBASE_TYPE xNetworkDownEventPending = pdFALSE;
\r
340 /* For convenience, a MAC address of all zeros and another of all 0xffs are
\r
341 defined const for quick reference. */
\r
342 static const xMACAddress_t xNullMACAddress = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
\r
343 static const xMACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
\r
345 /* Part of the Ethernet and IP headers are always constant when sending an IPv4
\r
346 UDP packet. This array defines the constant parts, allowing this part of the
\r
347 packet to be filled in using a simple memcpy() instead of individual writes. */
\r
348 uint8_t xDefaultPartUDPPacketHeader[] =
\r
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */
\r
351 0x08, 0x00, /* Ethernet frame type. */
\r
352 ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
\r
353 0x00, /* ucDifferentiatedServicesCode. */
\r
354 0x00, 0x00, /* usLength. */
\r
355 0x00, 0x00, /* usIdentification. */
\r
356 0x00, 0x00, /* usFragmentOffset. */
\r
357 updconfigIP_TIME_TO_LIVE, /* ucTimeToLive */
\r
358 ipPROTOCOL_UDP, /* ucProtocol. */
\r
359 0x00, 0x00, /* usHeaderChecksum. */
\r
360 0x00, 0x00, 0x00, 0x00 /* Source IP address. */
\r
363 /* Part of the Ethernet and ARP headers are always constant when sending an IPv4
\r
364 ARP packet. This array defines the constant parts, allowing this part of the
\r
365 packet to be filled in using a simple memcpy() instead of individual writes. */
\r
366 static const uint8_t xDefaultPartARPPacketHeader[] =
\r
368 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
\r
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
\r
370 0x08, 0x06, /* Ethernet frame type (ipARP_TYPE). */
\r
371 0x00, 0x01, /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
\r
372 0x08, 0x00, /* usProtocolType. */
\r
373 ipMAC_ADDRESS_LENGTH_BYTES, /* ucHardwareAddressLength. */
\r
374 ipIP_ADDRESS_LENGTH_BYTES, /* ucProtocolAddressLength. */
\r
375 0x00, 0x01, /* usOperation (ipARP_REQUEST). */
\r
376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
\r
377 0x00, 0x00, 0x00, 0x00, /* ulSenderProtocolAddress. */
\r
378 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* xTargetHardwareAddress. */
\r
381 /* Structure that stores the netmask, gateway address and DNS server addresses. */
\r
382 static xNetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0 };
\r
384 /*-----------------------------------------------------------*/
\r
386 static void prvIPTask( void *pvParameters )
\r
388 xIPStackEvent_t xReceivedEvent;
\r
390 /* Just to prevent compiler warnings about unused parameters. */
\r
391 ( void ) pvParameters;
\r
393 /* Create the ARP timer, but don't start it until the network has
\r
395 xARPTimer = xTimerCreate( "ARPTimer", ( ipARP_TIMER_PERIOD_MS / portTICK_RATE_MS ), pdTRUE, ( void * ) eARPTimerEvent, vIPFunctionsTimerCallback );
\r
396 configASSERT( xARPTimer );
\r
398 /* Generate a dummy message to say that the network connection has gone
\r
399 down. This will cause this task to initialise the network interface. After
\r
400 this it is the responsibility of the network interface hardware driver to
\r
401 send this message if a previously connected network is disconnected. */
\r
402 FreeRTOS_NetworkDown();
\r
404 /* Loop, processing IP events. */
\r
407 /* Wait until there is something to do. */
\r
408 if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, portMAX_DELAY ) == pdPASS )
\r
410 iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );
\r
412 switch( xReceivedEvent.eEventType )
\r
414 case eNetworkDownEvent :
\r
415 /* Attempt to establish a connection. */
\r
416 prvProcessNetworkDownEvent();
\r
419 case eEthernetRxEvent :
\r
420 /* The network hardware driver has received a new packet.
\r
421 A pointer to the received buffer is located in the pvData
\r
422 member of the received event structure. */
\r
423 prvProcessEthernetPacket( ( xNetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
\r
426 case eARPTimerEvent :
\r
427 /* The ARP timer has expired, process the ARP cache. */
\r
431 case eStackTxEvent :
\r
432 /* The network stack has generated a packet to send. A
\r
433 pointer to the generated buffer is located in the pvData
\r
434 member of the received event structure. */
\r
435 prvProcessGeneratedPacket( ( xNetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
\r
439 /* The DHCP state machine needs processing. */
\r
440 #if ipconfigUSE_DHCP == 1
\r
442 vDHCPProcess( pdFALSE, ( xMACAddress_t * ) ipLOCAL_MAC_ADDRESS, ipLOCAL_IP_ADDRESS_POINTER, &xNetworkAddressing );
\r
448 /* Should not get here. */
\r
452 if( xNetworkDownEventPending != pdFALSE )
\r
454 /* A network down event could not be posted to the network
\r
455 event queue because the queue was full. Try posting again. */
\r
456 FreeRTOS_NetworkDown();
\r
461 /*-----------------------------------------------------------*/
\r
463 void FreeRTOS_NetworkDown( void )
\r
465 static const xIPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
\r
466 const portTickType xDontBlock = 0;
\r
468 /* Simply send the network task the appropriate event. */
\r
469 if( xQueueSendToBack( xNetworkEventQueue, &xNetworkDownEvent, xDontBlock ) != pdPASS )
\r
471 xNetworkDownEventPending = pdTRUE;
\r
475 xNetworkDownEventPending = pdFALSE;
\r
478 iptraceNETWORK_DOWN();
\r
480 /*-----------------------------------------------------------*/
\r
482 portBASE_TYPE FreeRTOS_NetworkDownFromISR( void )
\r
484 static const xIPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
\r
485 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
487 /* Simply send the network task the appropriate event. */
\r
488 if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
\r
490 xNetworkDownEventPending = pdTRUE;
\r
494 xNetworkDownEventPending = pdFALSE;
\r
496 iptraceNETWORK_DOWN();
\r
498 return xHigherPriorityTaskWoken;
\r
500 /*-----------------------------------------------------------*/
\r
502 void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, portTickType xBlockTimeTicks )
\r
504 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
507 /* Cap the block time. The reason for this is explained where
\r
508 ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official
\r
509 FreeRTOSIPConfig.h header file is being used). */
\r
510 if( xBlockTimeTicks > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
512 xBlockTimeTicks = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
515 /* Obtain a network buffer with the required amount of storage. */
\r
516 pxNetworkBuffer = pxNetworkBufferGet( sizeof( xUDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );
\r
518 if( pxNetworkBuffer != NULL )
\r
520 /* Leave space for the UPD header. */
\r
521 pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] );
\r
528 return ( void * ) pvReturn;
\r
530 /*-----------------------------------------------------------*/
\r
532 void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )
\r
534 uint8_t *pucBuffer;
\r
536 /* Obtain the network buffer from the zero copy pointer. */
\r
537 pucBuffer = ( uint8_t * ) pvBuffer;
\r
538 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
540 vNetworkBufferRelease( * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer ) );
\r
542 /*-----------------------------------------------------------*/
\r
544 uint8_t * FreeRTOS_GetMACAddress( void )
\r
546 return ipLOCAL_MAC_ADDRESS;
\r
548 /*-----------------------------------------------------------*/
\r
550 portBASE_TYPE FreeRTOS_IPInit( const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
\r
552 static portBASE_TYPE xReturn = pdFALSE;
\r
554 /* Only create the IP event queue if it has not already been created, in
\r
555 case this function is called more than once. */
\r
556 if( xNetworkEventQueue == NULL )
\r
558 xNetworkEventQueue = xQueueCreate( ipconfigEVENT_QUEUE_LENGTH, sizeof( xIPStackEvent_t ) );
\r
559 configASSERT( xNetworkEventQueue );
\r
560 vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );
\r
563 if( xNetworkBuffersInitialise() == pdPASS )
\r
565 if( xNetworkEventQueue != NULL )
\r
567 /* xReturn is static to ensure the network interface is not
\r
568 initialised twice. */
\r
569 if( xReturn == pdFALSE )
\r
571 /* Store the local IP and MAC address. */
\r
572 xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );
\r
573 xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );
\r
574 xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );
\r
575 xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );
\r
577 #if ipconfigUSE_DHCP == 1
\r
579 /* The IP address is not set until DHCP completes. */
\r
580 *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;
\r
584 *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
\r
586 /* Ensure the gateway is on the same subnet as the IP
\r
588 configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );
\r
590 #endif /* ipconfigUSE_DHCP == 1 */
\r
592 /* The MAC address is stored in the start of the default packet
\r
593 header fragment, which is used when sending UDP packets. */
\r
594 memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
596 /* Prepare the sockets interface. */
\r
597 FreeRTOS_SocketsInit();
\r
599 /* Create the task that processes Ethernet and stack events. */
\r
600 xReturn = xTaskCreate( prvIPTask, "UDP/IP", ipconfigUDP_TASK_STACK_SIZE_WORDS, NULL, ipconfigUDP_TASK_PRIORITY, NULL );
\r
607 /*-----------------------------------------------------------*/
\r
609 void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )
\r
611 if( pulIPAddress != NULL )
\r
613 *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
616 if( pulNetMask != NULL )
\r
618 *pulNetMask = xNetworkAddressing.ulNetMask;
\r
621 if( pulGatewayAddress != NULL )
\r
623 *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;
\r
626 if( pulDNSServerAddress != NULL )
\r
628 *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;
\r
631 /*-----------------------------------------------------------*/
\r
633 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
635 portBASE_TYPE FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, portTickType xBlockTimeTicks )
\r
637 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
638 xICMPHeader_t *pxICMPHeader;
\r
639 portBASE_TYPE xReturn = pdFAIL;
\r
640 static uint16_t usSequenceNumber = 0;
\r
642 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
644 if( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( xIPHeader_t ) ) - sizeof( xICMPHeader_t ) ) )
\r
646 pxNetworkBuffer = pxNetworkBufferGet( xNumberOfBytesToSend + sizeof( xICMPPacket_t ), xBlockTimeTicks );
\r
648 if( pxNetworkBuffer != NULL )
\r
650 pxICMPHeader = ( xICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] );
\r
651 usSequenceNumber++;
\r
653 /* Fill in the basic header information. */
\r
654 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;
\r
655 pxICMPHeader->ucTypeOfService = 0;
\r
656 pxICMPHeader->usIdentifier = usSequenceNumber;
\r
657 pxICMPHeader->usSequenceNumber = usSequenceNumber;
\r
658 pxICMPHeader->usChecksum = 0;
\r
660 /* Find the start of the data. */
\r
661 pucChar = ( uint8_t * ) pxICMPHeader;
\r
662 pucChar += sizeof( xICMPHeader_t );
\r
664 /* Just memset the data to a fixed value. */
\r
665 memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );
\r
667 /* The message is complete, calculate the checksum. */
\r
668 pxICMPHeader->usChecksum = prvGenerateChecksum( ( uint8_t * ) pxICMPHeader, ( uint16_t ) ( xNumberOfBytesToSend + sizeof( xICMPHeader_t ) ), pdFALSE );
\r
670 /* Complete the network buffer information. */
\r
671 pxNetworkBuffer->ulIPAddress = ulIPAddress;
\r
672 pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
\r
673 pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( xICMPHeader_t );
\r
675 /* Send to the stack. */
\r
676 xStackTxEvent.pvData = pxNetworkBuffer;
\r
677 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xBlockTimeTicks ) != pdPASS )
\r
679 vNetworkBufferRelease( pxNetworkBuffer );
\r
680 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
684 xReturn = usSequenceNumber;
\r
690 /* The requested number of bytes will not fit in the available space
\r
691 in the network buffer. Outgoing fragmentation is only supported for
\r
698 #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */
\r
700 /*-----------------------------------------------------------*/
\r
702 static portBASE_TYPE prvSendEventToIPTask( eIPEvent_t eEvent )
\r
704 xIPStackEvent_t xEventMessage;
\r
705 const portTickType xDontBlock = 0;
\r
706 portBASE_TYPE xReturn;
\r
708 xEventMessage.eEventType = eEvent;
\r
709 xReturn = xQueueSendToBack( xNetworkEventQueue, &xEventMessage, xDontBlock );
\r
711 if( xReturn != pdPASS )
\r
713 iptraceSTACK_TX_EVENT_LOST( ipARP_TIMER_EVENT );
\r
718 /*-----------------------------------------------------------*/
\r
720 void vIPFunctionsTimerCallback( xTimerHandle xTimer )
\r
722 eIPEvent_t eMessage;
\r
724 /* This time can be used to send more than one type of message to the IP
\r
725 task. The message ID is stored in the ID of the timer. The strange
\r
726 casting is to avoid compiler warnings. */
\r
727 eMessage = ( eIPEvent_t ) ( ( portBASE_TYPE ) pvTimerGetTimerID( xTimer ) );
\r
729 prvSendEventToIPTask( eMessage );
\r
731 /*-----------------------------------------------------------*/
\r
733 static void prvOutputARPRequest( uint32_t ulIPAddress )
\r
735 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
737 /* This is called from the context of the IP event task, so a block time
\r
738 must not be used. */
\r
739 pxNetworkBuffer = pxNetworkBufferGet( sizeof( xARPPacket_t ), 0 );
\r
740 if( pxNetworkBuffer != NULL )
\r
742 pxNetworkBuffer->ulIPAddress = ulIPAddress;
\r
743 prvGenerateARPRequestPacket( pxNetworkBuffer );
\r
744 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
747 /*-----------------------------------------------------------*/
\r
749 static void prvAgeARPCache( void )
\r
753 /* Loop through each entry in the ARP cache. */
\r
754 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
756 /* If the entry is valid (its age is greater than zero). */
\r
757 if( xARPCache[ x ].ucAge > 0U )
\r
759 /* Decrement the age value of the entry in this ARP cache table row.
\r
760 When the age reaches zero it is no longer considered valid. */
\r
761 ( xARPCache[ x ].ucAge )--;
\r
763 /* If the entry has a MAC address of 0, then it is waiting an ARP
\r
764 reply, and the ARP request should be retransmitted. */
\r
765 if( memcmp( ( void * ) &xNullMACAddress, ( void * ) &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
767 prvOutputARPRequest( xARPCache[ x ].ulIPAddress );
\r
769 else if( xARPCache[ x ].ucAge <= ipMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
\r
771 /* This entry will get removed soon. See if the MAC address is
\r
772 still valid to prevent this happening. */
\r
773 iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
\r
774 prvOutputARPRequest( xARPCache[ x ].ulIPAddress );
\r
778 /* The age has just ticked down, with nothing to do. */
\r
781 if( xARPCache[ x ].ucAge == 0 )
\r
783 /* The entry is no longer valid. Wipe it out. */
\r
784 iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
\r
785 xARPCache[ x ].ulIPAddress = 0UL;
\r
790 /*-----------------------------------------------------------*/
\r
792 static eARPLookupResult_t prvGetARPCacheEntry( uint32_t *pulIPAddress, xMACAddress_t * const pxMACAddress )
\r
795 eARPLookupResult_t eReturn;
\r
796 uint32_t ulAddressToLookup;
\r
798 if( *pulIPAddress == ipBROADCAST_IP_ADDRESS )
\r
800 /* This is a broadcast so uses the broadcast MAC address. */
\r
801 memcpy( ( void * ) pxMACAddress, &xBroadcastMACAddress, sizeof( xMACAddress_t ) );
\r
802 eReturn = eARPCacheHit;
\r
804 else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )
\r
806 /* The IP address has not yet been assigned, so there is nothing that
\r
808 eReturn = eCantSendPacket;
\r
812 if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
\r
814 /* The IP address is off the local network, so look up the hardware
\r
815 address of the router, if any. */
\r
816 ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
\r
820 /* The IP address is on the local network, so lookup the requested
\r
821 IP address directly. */
\r
822 ulAddressToLookup = *pulIPAddress;
\r
825 if( ulAddressToLookup == 0UL )
\r
827 /* The address is not on the local network, and there is not a
\r
829 eReturn = eCantSendPacket;
\r
833 eReturn = eARPCacheMiss;
\r
835 /* Loop through each entry in the ARP cache. */
\r
836 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
838 /* Does this row in the ARP cache table hold an entry for the IP
\r
839 address being queried? */
\r
840 if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
\r
842 /* The IP address matched. Is there a valid MAC address? */
\r
843 if( memcmp( ( void * ) &xNullMACAddress, ( void * ) &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
845 /* This entry is waiting an ARP reply, so is not valid. */
\r
846 eReturn = eCantSendPacket;
\r
850 /* A valid entry was found. */
\r
851 memcpy( pxMACAddress, &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) );
\r
852 eReturn = eARPCacheHit;
\r
856 if( eReturn != eARPCacheMiss )
\r
862 if( eReturn == eARPCacheMiss )
\r
864 /* It might be that the ARP has to go to the gateway. */
\r
865 *pulIPAddress = ulAddressToLookup;
\r
872 /*-----------------------------------------------------------*/
\r
874 static void prvRefreshARPCacheEntry( const xMACAddress_t * const pxMACAddress, const uint32_t ulIPAddress )
\r
876 portBASE_TYPE x, xEntryFound = pdFALSE, xOldestEntry = 0;
\r
877 uint8_t ucMinAgeFound = 0U;
\r
879 /* Only process the IP address if it is on the local network. */
\r
880 if( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
\r
882 /* Start with the maximum possible number. */
\r
885 /* For each entry in the ARP cache table. */
\r
886 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
888 /* Does this line in the cache table hold an entry for the IP
\r
889 address being queried? */
\r
890 if( xARPCache[ x ].ulIPAddress == ulIPAddress )
\r
892 /* If the MAC address is all zeros then the refresh is due to
\r
893 an ARP reply, so in effect this is a new entry in the ARP
\r
895 if( memcmp( &( xARPCache[ x ].xMACAddress ), &xNullMACAddress, sizeof( xMACAddress_t ) ) == 0 )
\r
897 iptraceARP_TABLE_ENTRY_CREATED( xARPCache[ x ].ulIPAddress, *pxMACAddress );
\r
900 /* Refresh the cache entry so the entry's age is back to its
\r
902 xARPCache[ x ].ucAge = ipconfigMAX_ARP_AGE;
\r
903 memcpy( &( xARPCache[ x ].xMACAddress ), pxMACAddress, sizeof( xMACAddress_t ) );
\r
904 xEntryFound = pdTRUE;
\r
909 /* As the table is traversed, remember the table row that
\r
910 contains the oldest entry (the lowest age count, as ages are
\r
911 decremented to zero) so the row can be re-used if this function
\r
912 needs to add an entry that does not already exist. */
\r
913 if( xARPCache[ x ].ucAge < ucMinAgeFound )
\r
915 ucMinAgeFound = xARPCache[ x ].ucAge;
\r
921 if( xEntryFound == pdFALSE )
\r
923 /* The wanted entry does not already exist. Add the entry into the
\r
924 cache, replacing the oldest entry (which might be an empty entry). */
\r
925 xARPCache[ xOldestEntry ].ulIPAddress = ulIPAddress;
\r
926 memcpy( &( xARPCache[ xOldestEntry ].xMACAddress ), pxMACAddress, sizeof( xMACAddress_t ) );
\r
928 /* If the MAC address is all zeros, then this entry is not yet
\r
929 complete but still waiting the reply from an ARP request. When this
\r
930 is the case the age is set to a much lower value as an ARP
\r
931 retransmission will be generated each time the ARP timer is called
\r
932 while the reply is still outstanding. */
\r
933 if( pxMACAddress == &xNullMACAddress )
\r
935 xARPCache[ xOldestEntry ].ucAge = ipconfigMAX_ARP_RETRANSMISSIONS;
\r
939 iptraceARP_TABLE_ENTRY_CREATED( xARPCache[ xOldestEntry ].ulIPAddress, xARPCache[ xOldestEntry ].xMACAddress );
\r
940 xARPCache[ xOldestEntry ].ucAge = ipconfigMAX_ARP_AGE;
\r
945 /*-----------------------------------------------------------*/
\r
947 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
949 static void prvCalculateFragmentOffsetAndLength( xIPFragmentParameters_t *pxFragmentParameters, uint16_t *pusFragmentOffset, uint16_t *pusFragmentLength )
\r
951 *pusFragmentOffset = pxFragmentParameters->usFragmentedPacketOffset;
\r
953 if( *pusFragmentOffset != 0 )
\r
955 /* Take into account that the payload has had a UDP header added in the
\r
956 first fragment of the set. */
\r
957 *pusFragmentOffset += sizeof( xUDPHeader_t );
\r
960 /* The offset is defined in multiples of 8 bytes. */
\r
961 *pusFragmentOffset >>= ipSHIFT_TO_DIVIDE_BY_8;
\r
962 *pusFragmentLength = pxFragmentParameters->usFragmentLength;
\r
964 if( ( pxFragmentParameters->ucSocketOptions & FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET ) != 0 )
\r
966 /* Set the more fragments flag. */
\r
967 *pusFragmentOffset |= ipMORE_FRAGMENTS_FLAG_BIT;
\r
972 /*-----------------------------------------------------------*/
\r
974 static void prvCompleteUDPHeader( xNetworkBufferDescriptor_t *pxNetworkBuffer, xUDPPacket_t *pxUDPPacket, uint8_t ucSocketOptions )
\r
976 xUDPHeader_t *pxUDPHeader;
\r
978 pxUDPHeader = &( pxUDPPacket->xUDPHeader );
\r
980 pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
\r
981 pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
\r
982 pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xUDPHeader_t ) );
\r
983 pxUDPHeader->usLength = FreeRTOS_htons( pxUDPPacket->xUDPHeader.usLength );
\r
984 pxUDPHeader->usChecksum = 0;
\r
986 if( ( ucSocketOptions & FREERTOS_SO_UDPCKSUM_OUT ) != 0U )
\r
988 pxUDPHeader->usChecksum = prvGenerateUDPChecksum( pxUDPPacket, ipconfigETHERNET_DRIVER_ADDS_UDP_CHECKSUM );
\r
989 if( pxUDPHeader->usChecksum == 0x00 )
\r
991 /* A calculated checksum of 0 must be inverted as 0 means the
\r
992 checksum is disabled. */
\r
993 pxUDPHeader->usChecksum = 0xffffU;
\r
997 /*-----------------------------------------------------------*/
\r
999 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
1001 static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1003 xUDPPacket_t *pxUDPPacket;
\r
1004 xUDPHeader_t *pxUDPHeader;
\r
1005 xIPHeader_t *pxIPHeader;
\r
1006 eARPLookupResult_t eReturned;
\r
1007 eIPFragmentStatus_t eFragmentStatus;
\r
1008 uint16_t usFragmentOffset = 0, usFragmentLength;
\r
1009 xIPFragmentParameters_t *pxFragmentParameters;
\r
1010 static uint16_t usPacketIdentifier = 0U;
\r
1012 /* Map the UDP packet onto the start of the frame. */
\r
1013 pxUDPPacket = ( xUDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1015 /* Determine the ARP cache status for the requested IP address. */
\r
1016 eReturned = prvGetARPCacheEntry( &( pxNetworkBuffer->ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
\r
1018 if( eReturned != eCantSendPacket )
\r
1020 if( eReturned == eARPCacheHit )
\r
1022 iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
\r
1024 /* Create short cuts to the data within the packet. */
\r
1025 pxUDPHeader = &( pxUDPPacket->xUDPHeader );
\r
1026 pxIPHeader = &( pxUDPPacket->xIPHeader );
\r
1027 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
1029 /* IP header source and destination addresses must be set
\r
1030 before the UDP checksum is calculated. */
\r
1031 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1032 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1034 /* If the packet is not fragmented, or if the packet is the
\r
1035 first in a fragmented packet, then a UDP header is required. */
\r
1036 if( ( pxFragmentParameters->ucSocketOptions & FREERTOS_FRAGMENTED_PACKET ) == 0 )
\r
1038 eFragmentStatus = eNotFragment;
\r
1040 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1042 /* Is it possible that the packet is not actually a UDP
\r
1043 packet after all, but an ICMP packet. */
\r
1044 if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )
\r
1046 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );
\r
1049 #else /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1051 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );
\r
1053 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1056 usFragmentLength = 0U;
\r
1058 /* The identifier is incremented as this is a new and
\r
1059 unfragmented IP packet. */
\r
1060 usPacketIdentifier++;
\r
1062 else if( pxFragmentParameters->usFragmentedPacketOffset == 0 )
\r
1064 eFragmentStatus = eFirstFragment;
\r
1065 prvCalculateFragmentOffsetAndLength( pxFragmentParameters, &usFragmentOffset, &usFragmentLength );
\r
1066 /* Note FREERTOS_SO_UDPCKSUM_OUT is used because checksums
\r
1067 cannot currently be used on fragmented packets. */
\r
1068 pxFragmentParameters->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
1069 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );
\r
1071 /* The identifier is incremented because, although this is a
\r
1072 fragmented packet, it is the first in the fragmentation
\r
1074 usPacketIdentifier++;
\r
1078 eFragmentStatus = eFollowingFragment;
\r
1079 prvCalculateFragmentOffsetAndLength( pxFragmentParameters, &usFragmentOffset, &usFragmentLength );
\r
1082 /* memcpy() the constant parts of the header information into the
\r
1083 correct location within the packet. This fills in:
\r
1084 xEthernetHeader.xSourceAddress
\r
1085 xEthernetHeader.usFrameType
\r
1086 xIPHeader.ucVersionHeaderLength
\r
1087 xIPHeader.ucDifferentiatedServicesCode
\r
1088 xIPHeader.usLength
\r
1089 xIPHeader.usIdentification
\r
1090 xIPHeader.usFragmentOffset
\r
1091 xIPHeader.ucTimeToLive
\r
1092 xIPHeader.ucProtocol
\r
1094 xIPHeader.usHeaderChecksum
\r
1096 memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xDefaultPartUDPPacketHeader ) );
\r
1098 /* The fragment status is used to complete the length and
\r
1099 fragment offset fields. */
\r
1100 if( eFragmentStatus == eNotFragment )
\r
1102 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1104 else if( eFragmentStatus == eFirstFragment )
\r
1106 pxIPHeader->usFragmentOffset = FreeRTOS_htons( usFragmentOffset );
\r
1107 pxIPHeader->usLength = ( uint16_t ) ( usFragmentLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1111 pxIPHeader->usFragmentOffset = FreeRTOS_htons( usFragmentOffset );
\r
1112 pxIPHeader->usLength = ( uint16_t ) ( usFragmentLength + sizeof( xIPHeader_t ) );
\r
1115 /* The total transmit size adds on the Ethernet header. */
\r
1116 pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( xEthernetHeader_t );
\r
1117 pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
\r
1118 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1119 pxIPHeader->usIdentification = usPacketIdentifier;
\r
1120 pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH, ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM );
\r
1122 else if ( eReturned == eARPCacheMiss )
\r
1124 /* Send an ARP for the required IP address. */
\r
1125 iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
\r
1126 prvGenerateARPRequestPacket( pxNetworkBuffer );
\r
1128 /* Add an entry to the ARP table with a null hardware address.
\r
1129 This allows the ARP timer to know that an ARP reply is
\r
1130 outstanding, and perform retransmissions if necessary. */
\r
1131 prvRefreshARPCacheEntry( &xNullMACAddress, pxNetworkBuffer->ulIPAddress );
\r
1135 /* The lookup indicated that an ARP request has already been
\r
1136 sent out for the queried IP address. */
\r
1137 eReturned = eCantSendPacket;
\r
1141 if( eReturned != eCantSendPacket )
\r
1143 /* The network driver is responsible for freeing the network buffer
\r
1144 after the packet has been sent. */
\r
1145 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
1149 /* The packet can't be sent (DHCP not completed?). Just drop the
\r
1151 vNetworkBufferRelease( pxNetworkBuffer );
\r
1155 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 */
\r
1157 static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1159 xUDPPacket_t *pxUDPPacket;
\r
1160 xIPHeader_t *pxIPHeader;
\r
1161 eARPLookupResult_t eReturned;
\r
1163 /* Map the UDP packet onto the start of the frame. */
\r
1164 pxUDPPacket = ( xUDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1166 /* Determine the ARP cache status for the requested IP address. */
\r
1167 eReturned = prvGetARPCacheEntry( &( pxNetworkBuffer->ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
\r
1168 if( eReturned != eCantSendPacket )
\r
1170 if( eReturned == eARPCacheHit )
\r
1172 iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
\r
1174 /* Create short cuts to the data within the packet. */
\r
1175 pxIPHeader = &( pxUDPPacket->xIPHeader );
\r
1177 /* IP header source and destination addresses must be set before
\r
1178 the UDP checksum is calculated. The socket options, which
\r
1179 specify whether a checksum should be calculated or not, are
\r
1180 passed in the as yet unused part of the packet data. */
\r
1181 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1182 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1184 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1186 /* Is it possible that the packet is not actually a UDP packet
\r
1187 after all, but an ICMP packet. */
\r
1188 if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )
\r
1190 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] );
\r
1193 #else /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1195 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] );
\r
1197 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1199 /* memcpy() the constant parts of the header information into
\r
1200 the correct location within the packet. This fills in:
\r
1201 xEthernetHeader.xSourceAddress
\r
1202 xEthernetHeader.usFrameType
\r
1203 xIPHeader.ucVersionHeaderLength
\r
1204 xIPHeader.ucDifferentiatedServicesCode
\r
1205 xIPHeader.usLength
\r
1206 xIPHeader.usIdentification
\r
1207 xIPHeader.usFragmentOffset
\r
1208 xIPHeader.ucTimeToLive
\r
1209 xIPHeader.ucProtocol
\r
1211 xIPHeader.usHeaderChecksum
\r
1213 memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xDefaultPartUDPPacketHeader ) );
\r
1215 #if ipconfigSUPPORT_OUTGOING_PINGS == 1
\r
1217 if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA )
\r
1219 pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
\r
1220 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) );
\r
1224 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1227 #else /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1229 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1231 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1233 /* The total transmit size adds on the Ethernet header. */
\r
1234 pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( xEthernetHeader_t );
\r
1235 pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
\r
1236 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1237 pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH, ipconfigETHERNET_DRIVER_ADDS_IP_CHECKSUM );
\r
1239 else if ( eReturned == eARPCacheMiss )
\r
1241 /* Generate an ARP for the required IP address. */
\r
1242 iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
\r
1243 prvGenerateARPRequestPacket( pxNetworkBuffer );
\r
1245 /* Add an entry to the ARP table with a null hardware address.
\r
1246 This allows the ARP timer to know that an ARP reply is
\r
1247 outstanding, and perform retransmissions if necessary. */
\r
1248 prvRefreshARPCacheEntry( &xNullMACAddress, pxNetworkBuffer->ulIPAddress );
\r
1252 /* The lookup indicated that an ARP request has already been
\r
1253 sent out for the queried IP address. */
\r
1254 eReturned = eCantSendPacket;
\r
1258 if( eReturned != eCantSendPacket )
\r
1260 /* The network driver is responsible for freeing the network buffer
\r
1261 after the packet has been sent. */
\r
1262 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
1266 /* The packet can't be sent (DHCP not completed?). Just drop the
\r
1268 vNetworkBufferRelease( pxNetworkBuffer );
\r
1273 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 */
\r
1274 /*-----------------------------------------------------------*/
\r
1276 static void prvGenerateARPRequestPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1278 xARPPacket_t *pxARPPacket;
\r
1280 pxARPPacket = ( xARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1282 /* memcpy the const part of the header information into the correct
\r
1283 location in the packet. This copies:
\r
1284 xEthernetHeader.ulDestinationAddress
\r
1285 xEthernetHeader.usFrameType;
\r
1286 xARPHeader.usHardwareType;
\r
1287 xARPHeader.usProtocolType;
\r
1288 xARPHeader.ucHardwareAddressLength;
\r
1289 xARPHeader.ucProtocolAddressLength;
\r
1290 xARPHeader.usOperation;
\r
1291 xARPHeader.xTargetHardwareAddress;
\r
1293 memcpy( ( void * ) &( pxARPPacket->xEthernetHeader ), ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );
\r
1294 memcpy( ( void * ) &( pxARPPacket->xEthernetHeader.xSourceAddress ) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
1295 memcpy( ( void * ) &( pxARPPacket->xARPHeader.xSenderHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
1296 pxARPPacket->xARPHeader.ulSenderProtocolAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1297 pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
\r
1299 pxNetworkBuffer->xDataLength = sizeof( xARPPacket_t );
\r
1301 iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );
\r
1303 /*-----------------------------------------------------------*/
\r
1305 eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
\r
1307 eFrameProcessingResult_t eReturn;
\r
1308 const xEthernetHeader_t *pxEthernetHeader;
\r
1310 pxEthernetHeader = ( const xEthernetHeader_t * ) pucEthernetBuffer;
\r
1312 if( memcmp( ( void * ) &xBroadcastMACAddress, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
1314 /* The packet was a broadcast - process it. */
\r
1315 eReturn = eProcessBuffer;
\r
1317 else if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
1319 /* The packet was to this node directly - process it. */
\r
1320 eReturn = eProcessBuffer;
\r
1324 /* The packet was not a broadcast, or for this node, just release
\r
1325 the buffer without taking any other action. */
\r
1326 eReturn = eReleaseBuffer;
\r
1329 #if ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1
\r
1331 uint16_t usFrameType;
\r
1333 if( eReturn == eProcessBuffer )
\r
1335 usFrameType = pxEthernetHeader->usFrameType;
\r
1336 usFrameType = FreeRTOS_ntohs( usFrameType );
\r
1338 if( usFrameType <= 0x600U )
\r
1340 /* Not an Ethernet II frame. */
\r
1341 eReturn = eReleaseBuffer;
\r
1345 #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */
\r
1349 /*-----------------------------------------------------------*/
\r
1351 static void prvProcessNetworkDownEvent( void )
\r
1353 /* Stop the ARP timer while there is no network. */
\r
1354 xTimerStop( xARPTimer, portMAX_DELAY );
\r
1356 #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
\r
1358 static portBASE_TYPE xCallEventHook = pdFALSE;
\r
1360 /* The first network down event is generated by the IP stack
\r
1361 itself to initialise the network hardware, so do not call the
\r
1362 network down event the first time through. */
\r
1363 if( xCallEventHook == pdTRUE )
\r
1365 vApplicationIPNetworkEventHook( eNetworkDown );
\r
1367 xCallEventHook = pdTRUE;
\r
1371 /* The network has been disconnected (or is being
\r
1372 initialised for the first time). Perform whatever hardware
\r
1373 processing is necessary to bring it up again, or wait for it
\r
1374 to be available again. This is hardware dependent. */
\r
1375 if( xNetworkInterfaceInitialise() != pdPASS )
\r
1377 /* Ideally the network interface initialisation function
\r
1378 will only return when the network is available. In case
\r
1379 this is not the case, wait a while before retrying the
\r
1380 initialisation. */
\r
1381 vTaskDelay( ipINITIALISATION_RETRY_DELAY );
\r
1382 FreeRTOS_NetworkDown();
\r
1386 /* Start the ARP timer. */
\r
1387 xTimerStart( xARPTimer, portMAX_DELAY );
\r
1389 #if ipconfigUSE_DHCP == 1
\r
1391 /* The network is not up until DHCP has completed. */
\r
1392 vDHCPProcess( pdTRUE, ( xMACAddress_t * ) ipLOCAL_MAC_ADDRESS, ipLOCAL_IP_ADDRESS_POINTER, &xNetworkAddressing );
\r
1393 prvSendEventToIPTask( eDHCPEvent );
\r
1397 #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
\r
1399 vApplicationIPNetworkEventHook( eNetworkUp );
\r
1401 #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
\r
1403 /* Static configuration is being used, so the network is now up. */
\r
1404 #if ipconfigFREERTOS_PLUS_NABTO == 1
\r
1406 /* Return value is used in configASSERT() inside the
\r
1408 ( void ) xStartNabtoTask();
\r
1410 #endif /* ipconfigFREERTOS_PLUS_NABTO */
\r
1415 /*-----------------------------------------------------------*/
\r
1417 static void prvProcessEthernetPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1419 xEthernetHeader_t *pxEthernetHeader;
\r
1420 volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */
\r
1422 configASSERT( pxNetworkBuffer );
\r
1424 /* Interpret the Ethernet frame. */
\r
1425 eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
\r
1426 pxEthernetHeader = ( xEthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1428 if( eReturned == eProcessBuffer )
\r
1430 /* Interpret the received Ethernet packet. */
\r
1431 switch ( pxEthernetHeader->usFrameType )
\r
1434 /* The Ethernet frame contains an ARP packet. */
\r
1435 eReturned = prvProcessARPPacket( ( xARPPacket_t * ) pxEthernetHeader );
\r
1439 /* The Ethernet frame contains an IP packet. */
\r
1440 eReturned = prvProcessIPPacket( ( xIPPacket_t * ) pxEthernetHeader, pxNetworkBuffer );
\r
1444 /* No other packet types are handled. Nothing to do. */
\r
1445 eReturned = eReleaseBuffer;
\r
1450 /* Perform any actions that resulted from processing the Ethernet
\r
1452 switch( eReturned )
\r
1454 case eReturnEthernetFrame :
\r
1455 /* The Ethernet frame will have been updated (maybe it was
\r
1456 an ARP request or a PING request?) and should be sent back to
\r
1458 prvReturnEthernetFrame( pxNetworkBuffer );
\r
1459 /* The buffer must be released once
\r
1460 the frame has been transmitted. */
\r
1463 case eFrameConsumed :
\r
1464 /* The frame is in use somewhere, don't release the buffer
\r
1469 /* The frame is not being used anywhere, and the
\r
1470 xNetworkBufferDescriptor_t structure containing the frame should just be
\r
1471 released back to the list of free buffers. */
\r
1472 vNetworkBufferRelease( pxNetworkBuffer );
\r
1476 /*-----------------------------------------------------------*/
\r
1478 static eFrameProcessingResult_t prvProcessIPPacket( const xIPPacket_t * const pxIPPacket, xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1480 eFrameProcessingResult_t eReturn = eReleaseBuffer;
\r
1481 const xIPHeader_t * pxIPHeader;
\r
1482 xUDPPacket_t *pxUDPPacket;
\r
1483 portBASE_TYPE xChecksumIsCorrect;
\r
1485 pxIPHeader = &( pxIPPacket->xIPHeader );
\r
1487 /* Is the packet for this node? */
\r
1488 if( ( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER ) || ( pxIPHeader->ulDestinationIPAddress == ipBROADCAST_IP_ADDRESS ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0 ) )
\r
1490 /* Ensure the frame is IPv4 with no options bytes, and that the incoming
\r
1491 packet is not fragmented (only outgoing packets can be fragmented) as
\r
1492 these are the only handled IP frames currently. */
\r
1493 if( ( pxIPHeader->ucVersionHeaderLength == ipIP_VERSION_AND_HEADER_LENGTH_BYTE ) && ( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) == 0U ) )
\r
1495 /* Is the IP header checksum correct? */
\r
1496 if( prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH, ipconfigETHERNET_DRIVER_CHECKS_IP_CHECKSUM ) == 0 )
\r
1498 /* Add the IP and MAC addresses to the ARP table if they are not
\r
1499 already there - otherwise refresh the age of the existing
\r
1501 prvRefreshARPCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
\r
1502 switch( pxIPHeader->ucProtocol )
\r
1504 case ipPROTOCOL_ICMP :
\r
1506 /* The IP packet contained an ICMP frame. Don't bother
\r
1507 checking the ICMP checksum, as if it is wrong then the
\r
1508 wrong data will also be returned, and the source of the
\r
1509 ping will know something went wrong because it will not
\r
1510 be able to validate what it receives. */
\r
1511 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1513 if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
\r
1515 eReturn = prvProcessICMPPacket( ( xICMPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ) );
\r
1518 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
\r
1521 case ipPROTOCOL_UDP :
\r
1523 /* The IP packet contained a UDP frame. */
\r
1524 pxUDPPacket = ( xUDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1526 /* Note the header values required prior to the
\r
1527 checksum generation as the checksum pseudo header
\r
1528 may clobber some of these values. */
\r
1529 pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( xUDPHeader_t );
\r
1530 pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;
\r
1531 pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
\r
1533 /* Is the checksum required? */
\r
1534 if( pxUDPPacket->xUDPHeader.usChecksum == 0 )
\r
1536 xChecksumIsCorrect = pdTRUE;
\r
1538 else if( prvGenerateUDPChecksum( pxUDPPacket, ipconfigETHERNET_DRIVER_CHECKS_UDP_CHECKSUM ) == 0 )
\r
1540 xChecksumIsCorrect = pdTRUE;
\r
1544 xChecksumIsCorrect = pdFALSE;
\r
1547 /* Is the checksum correct? */
\r
1548 if( xChecksumIsCorrect == pdTRUE )
\r
1550 /* Pass the packet payload to the UDP sockets
\r
1551 implementation. */
\r
1552 if( xProcessReceivedUDPPacket( pxNetworkBuffer, pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )
\r
1554 eReturn = eFrameConsumed;
\r
1561 /* Not a supported frame type. */
\r
1570 /*-----------------------------------------------------------*/
\r
1572 static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket, portBASE_TYPE xChecksumIsOffloaded )
\r
1574 xPseudoHeader_t *pxPseudoHeader;
\r
1575 uint16_t usLength, usReturn;
\r
1577 if( xChecksumIsOffloaded == pdFALSE )
\r
1579 /* Map the pseudo header into the correct place within the real IP
\r
1581 pxPseudoHeader = ( xPseudoHeader_t * ) &( pxUDPPacket->xIPHeader.ucTimeToLive );
\r
1583 /* Ordering here is important so as not to overwrite data that is required
\r
1584 but has not yet been used as the pseudo header overlaps the information
\r
1585 that is being copied into it. */
\r
1586 pxPseudoHeader->ulSourceAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
\r
1587 pxPseudoHeader->ulDestinationAddress = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
\r
1588 pxPseudoHeader->ucZeros = 0x00;
\r
1589 pxPseudoHeader->ucProtocol = ipPROTOCOL_UDP;
\r
1590 pxPseudoHeader->usUDPLength = pxUDPPacket->xUDPHeader.usLength;
\r
1592 usLength = FreeRTOS_ntohs( pxPseudoHeader->usUDPLength );
\r
1593 usReturn = prvGenerateChecksum( ( uint8_t * ) pxPseudoHeader, usLength + sizeof( xPseudoHeader_t ), pdFALSE );
\r
1597 /* The hardware will check the checksum. Returning 0 allows this
\r
1598 function to be used to both check an incoming checksum and set an
\r
1599 outgoing checksum in this case. */
\r
1605 /*-----------------------------------------------------------*/
\r
1607 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1609 static void prvProcessICMPEchoReply( xICMPPacket_t * const pxICMPPacket )
\r
1611 ePingReplyStatus_t eStatus = eSuccess;
\r
1612 uint16_t usDataLength, usCount;
\r
1615 /* Find the total length of the IP packet. */
\r
1616 usDataLength = pxICMPPacket->xIPHeader.usLength;
\r
1617 usDataLength = FreeRTOS_ntohs( usDataLength );
\r
1619 /* Remove the length of the IP headers to obtain the length of the ICMP
\r
1620 message itself. */
\r
1621 usDataLength -= sizeof( xIPHeader_t );
\r
1623 if( prvGenerateChecksum( ( uint8_t * ) &( pxICMPPacket->xICMPHeader ), usDataLength, pdFALSE ) != 0 )
\r
1625 eStatus = eInvalidChecksum;
\r
1629 /* Remove the length of the ICMP header, to obtain the length of
\r
1630 data contained in the ping. */
\r
1631 usDataLength -= sizeof( xICMPHeader_t );
\r
1633 /* Find the first byte of the data within the ICMP packet. */
\r
1634 pucByte = ( uint8_t * ) pxICMPPacket;
\r
1635 pucByte += sizeof( xICMPPacket_t );
\r
1637 /* Check each byte. */
\r
1638 for( usCount = 0; usCount < usDataLength; usCount++ )
\r
1640 if( *pucByte != ipECHO_DATA_FILL_BYTE )
\r
1642 eStatus = eInvalidData;
\r
1650 vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );
\r
1654 /*-----------------------------------------------------------*/
\r
1656 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
\r
1658 static eFrameProcessingResult_t prvProcessICMPEchoRequest( xICMPPacket_t * const pxICMPPacket )
\r
1660 xICMPHeader_t *pxICMPHeader;
\r
1661 xIPHeader_t *pxIPHeader;
\r
1663 pxICMPHeader = &( pxICMPPacket->xICMPHeader );
\r
1664 pxIPHeader = &( pxICMPPacket->xIPHeader );
\r
1666 iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );
\r
1668 /* The checksum can be checked here - but a ping reply should be
\r
1669 returned even if the checksum is incorrect so the other end can
\r
1670 tell that the ping was received - even if the ping reply contains
\r
1672 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REPLY;
\r
1673 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
1674 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1676 /* Update the checksum because the ucTypeOfMessage member in the
\r
1677 header has been changed to ipICMP_ECHO_REPLY. */
\r
1678 if( pxICMPHeader->usChecksum >= FreeRTOS_htons( ( ( uint16_t ) 0xffffU ) - ( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) ) ) )
\r
1680 pxICMPHeader->usChecksum += FreeRTOS_htons( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) ) + ( uint16_t ) 1U;
\r
1684 pxICMPHeader->usChecksum += FreeRTOS_htons( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) );
\r
1687 return eReturnEthernetFrame;
\r
1690 #endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */
\r
1692 /*-----------------------------------------------------------*/
\r
1694 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1696 static eFrameProcessingResult_t prvProcessICMPPacket( xICMPPacket_t * const pxICMPPacket )
\r
1698 eFrameProcessingResult_t eReturn = eReleaseBuffer;
\r
1700 iptraceICMP_PACKET_RECEIVED();
\r
1702 switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )
\r
1704 case ipICMP_ECHO_REQUEST :
\r
1705 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
\r
1707 eReturn = prvProcessICMPEchoRequest( pxICMPPacket );
\r
1709 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */
\r
1712 case ipICMP_ECHO_REPLY :
\r
1713 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1715 prvProcessICMPEchoReply( pxICMPPacket );
\r
1717 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1727 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
\r
1728 /*-----------------------------------------------------------*/
\r
1730 static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes, portBASE_TYPE xChecksumIsOffloaded )
\r
1732 uint32_t ulChecksum = 0;
\r
1733 uint16_t us, usDataLength16BitWords, *pusNextData, usReturn;
\r
1735 if( xChecksumIsOffloaded == pdFALSE )
\r
1737 /* There are half as many 16 bit words than bytes. */
\r
1738 usDataLength16BitWords = ( usDataLengthBytes >> 1U );
\r
1740 pusNextData = ( uint16_t * ) pucNextData;
\r
1742 for( us = 0U; us < usDataLength16BitWords; us++ )
\r
1744 ulChecksum += ( uint32_t ) pusNextData[ us ];
\r
1747 if( ( usDataLengthBytes & 0x01U ) != 0x00 )
\r
1749 /* There is one byte left over. */
\r
1750 #if ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN
\r
1752 ulChecksum += ( uint32_t ) pucNextData[ usDataLengthBytes - 1 ];
\r
1756 us = ( uint16_t ) pucNextData[ usDataLengthBytes - 1 ];
\r
1757 ulChecksum += ( uint32_t ) ( us << 8 );
\r
1762 while( ( ulChecksum >> 16UL ) != 0x00UL )
\r
1764 ulChecksum = ( ulChecksum & 0xffffUL ) + ( ulChecksum >> 16UL );
\r
1767 usReturn = ~( ( uint16_t ) ulChecksum );
\r
1771 /* The checksum is calculated by the hardware. Return 0 here to ensure
\r
1772 this works for both incoming and outgoing checksums. */
\r
1778 /*-----------------------------------------------------------*/
\r
1780 static void prvReturnEthernetFrame( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1782 xEthernetHeader_t *pxEthernetHeader;
\r
1784 pxEthernetHeader = ( xEthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1786 /* Swap source and destination MAC addresses. */
\r
1787 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );
\r
1788 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
1791 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
1793 /*-----------------------------------------------------------*/
\r
1795 static eFrameProcessingResult_t prvProcessARPPacket( xARPPacket_t * const pxARPFrame )
\r
1797 eFrameProcessingResult_t eReturn = eReleaseBuffer;
\r
1798 xARPHeader_t *pxARPHeader;
\r
1800 pxARPHeader = &( pxARPFrame->xARPHeader );
\r
1802 traceARP_PACKET_RECEIVED();
\r
1804 /* Sanity check the protocol type. Don't do anything if the local IP
\r
1805 address is zero because that means a DHCP request has not completed. */
\r
1806 if( ( pxARPHeader->usProtocolType == ipARP_PROTOCOL_TYPE ) && ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )
\r
1808 switch( pxARPHeader->usOperation )
\r
1810 case ipARP_REQUEST :
\r
1811 /* The packet contained an ARP request. Was it for the IP
\r
1812 address of the node running this code? */
\r
1813 if( pxARPHeader->ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
\r
1815 iptraceSENDING_ARP_REPLY( pxARPHeader->ulSenderProtocolAddress );
\r
1817 /* The request is for the address of this node. Add the
\r
1818 entry into the ARP cache, or refresh the entry if it
\r
1819 already exists. */
\r
1820 prvRefreshARPCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), pxARPHeader->ulSenderProtocolAddress );
\r
1822 /* Generate a reply payload in the same buffer. */
\r
1823 pxARPHeader->usOperation = ipARP_REPLY;
\r
1824 memcpy( ( void * ) &( pxARPHeader->xTargetHardwareAddress ), ( void * ) &( pxARPHeader->xSenderHardwareAddress ), sizeof( xMACAddress_t ) );
\r
1825 pxARPHeader->ulTargetProtocolAddress = pxARPHeader->ulSenderProtocolAddress;
\r
1826 memcpy( ( void * ) &( pxARPHeader->xSenderHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( xMACAddress_t ) );
\r
1827 pxARPHeader->ulSenderProtocolAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1829 eReturn = eReturnEthernetFrame;
\r
1833 case ipARP_REPLY :
\r
1834 iptracePROCESSING_RECEIVED_ARP_REPLY( pxARPHeader->ulTargetProtocolAddress );
\r
1835 prvRefreshARPCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), pxARPHeader->ulSenderProtocolAddress );
\r
1846 /*-----------------------------------------------------------*/
\r
1848 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )
\r
1849 uint16_t FreeRTOS_htons( uint16_t usIn )
\r
1851 return ( ( usIn & ( uint16_t ) 0x00ff ) << ( uint16_t ) 8U ) |
\r
1852 ( ( usIn & ( uint16_t ) 0xff00 ) >> ( uint16_t ) 8U );
\r
1854 #endif /* ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN */
\r
1855 /*-----------------------------------------------------------*/
\r
1857 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )
\r
1858 uint32_t FreeRTOS_htonl( uint32_t ulIn )
\r
1860 return ( ( ulIn & 0x000000ffUL ) << 24UL ) |
\r
1861 ( ( ulIn & 0x0000ff00UL ) << 8UL ) |
\r
1862 ( ( ulIn & 0x00ff0000UL ) >> 8UL ) |
\r
1863 ( ( ulIn & 0xff000000UL ) >> 24UL );
\r
1865 #endif /* ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN */
\r
1867 /*-----------------------------------------------------------*/
\r