2 * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.
\r
4 * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license
\r
5 * terms are different to the FreeRTOS license terms.
\r
7 * FreeRTOS+UDP uses a dual license model that allows the software to be used
\r
8 * under a standard GPL open source license, or a commercial license. The
\r
9 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
10 * itself is distributed) requires that all software statically linked with
\r
11 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
12 * Details of both license options follow:
\r
14 * - Open source licensing -
\r
15 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
16 * distributed without charge provided the user adheres to version two of the
\r
17 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
18 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
19 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
21 * - Commercial licensing -
\r
22 * Businesses and individuals that for commercial or other reasons cannot comply
\r
23 * with the terms of the GPL V2 license must obtain a commercial license before
\r
24 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
25 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
26 * and do not require any source files to be changed.
\r
28 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
29 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
30 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
31 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
32 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
33 * implied, expressed, or statutory.
\r
35 * 1 tab == 4 spaces!
\r
37 * http://www.FreeRTOS.org
\r
38 * http://www.FreeRTOS.org/udp
\r
42 /* Standard includes. */
\r
45 /* FreeRTOS includes. */
\r
46 #include "FreeRTOS.h"
\r
52 /* FreeRTOS+UDP includes. */
\r
53 #include "FreeRTOS_UDP_IP.h"
\r
54 #include "FreeRTOS_IP_Private.h"
\r
55 #include "FreeRTOS_Sockets.h"
\r
56 #include "FreeRTOS_DHCP.h"
\r
57 #include "NetworkInterface.h"
\r
58 #include "NetworkBufferManagement.h"
\r
60 /* Sanity check the configuration. */
\r
61 #if configUSE_TIMERS != 1
\r
62 #error configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h to use this file
\r
65 #if configTICK_RATE_HZ > 1000
\r
66 #error configTICK_RATE_HZ must be less than 1000 to use FreeRTOS+UDP
\r
69 #if ( ipconfigEVENT_QUEUE_LENGTH < ( ipconfigNUM_NETWORK_BUFFERS + 5 ) )
\r
70 #error The ipconfigEVENT_QUEUE_LENGTH parameter must be at least ipconfigNUM_NETWORK_BUFFERS + 5
\r
73 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 && ipconfigSUPPORT_OUTGOING_PINGS == 1
\r
74 #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
77 #if ( ipconfigNETWORK_MTU < 46 )
\r
78 #error ipconfigNETWORK_MTU must be at least 46.
\r
80 /*-----------------------------------------------------------*/
\r
82 /* The IP header length in bytes. */
\r
83 #define ipIP_HEADER_LENGTH ( 20 )
\r
85 /* IP protocol definitions. */
\r
86 #define ipPROTOCOL_ICMP ( 1 )
\r
87 #define ipPROTOCOL_UDP ( 17 )
\r
89 /* ICMP protocol definitions. */
\r
90 #define ipICMP_ECHO_REQUEST ( ( uint16_t ) 8 )
\r
91 #define ipICMP_ECHO_REPLY ( ( uint16_t ) 0 )
\r
93 /* The expected IP version and header length coded into the IP header itself. */
\r
94 #define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
\r
96 /* Time delay between repeated attempts to initialise the network hardware. */
\r
97 #define ipINITIALISATION_RETRY_DELAY ( ( ( portTickType ) 3000 ) / portTICK_RATE_MS )
\r
99 /* The local MAC address is accessed from within xDefaultPartUDPPacketHeader,
\r
100 rather than duplicated in its own variable. */
\r
101 #define ipLOCAL_MAC_ADDRESS ( xDefaultPartUDPPacketHeader )
\r
103 /* The local IP address is accessed from within xDefaultPartUDPPacketHeader,
\r
104 rather than duplicated in its own variable. */
\r
105 #define ipLOCAL_IP_ADDRESS_POINTER ( ( uint32_t * ) &( xDefaultPartUDPPacketHeader[ 20 ] ) )
\r
107 /* Defines how often the ARP timer callback function is executed. The time is
\r
108 shorted in the Windows simulator as simulated time is not real time. */
\r
110 #define ipARP_TIMER_PERIOD_MS ( 500 ) /* For windows simulator builds. */
\r
112 #define ipARP_TIMER_PERIOD_MS ( 10000 )
\r
115 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
\r
116 driver will filter incoming packets and only pass the stack those packets it
\r
117 considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
\r
118 be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
\r
119 then the Ethernet driver will pass all received packets to the stack, and the
\r
120 stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
\r
121 needs to call eConsiderFrameForProcessing. */
\r
122 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
\r
123 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
\r
125 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
\r
128 /* When the age of an entry in the ARP table reaches this value (it counts down
\r
129 to zero, so this is an old entry) an ARP request will be sent to see if the
\r
130 entry is still valid and can therefore be refreshed. */
\r
131 #define ipMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3 )
\r
133 /* Number of bits to shift to divide by 8. Used to remove the need for a
\r
135 #define ipSHIFT_TO_DIVIDE_BY_8 ( 3U )
\r
137 /* The bit set in the IP header flags to indicate that the IP packet contains
\r
138 a fragment of the eventual total payload, and that more fragments will follow. */
\r
139 #define ipMORE_FRAGMENTS_FLAG_BIT ( 0x2000U )
\r
141 /* ICMP packets are sent using the same function as UDP packets. The port
\r
142 number is used to distinguish between the two, as 0 is an invalid UDP port. */
\r
143 #define ipPACKET_CONTAINS_ICMP_DATA ( 0 )
\r
145 /* The character used to fill ICMP echo requests, and therefore also the
\r
146 character expected to fill ICMP echo replies. */
\r
147 #define ipECHO_DATA_FILL_BYTE 'x'
\r
149 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )
\r
150 #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
152 #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
153 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
154 #warning Fragment offsets have not been tested on big endian machines.
\r
155 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
156 #endif /* ipconfigBYTE_ORDER */
\r
158 /*-----------------------------------------------------------*/
\r
159 /* Miscellaneous structure and definitions. */
\r
160 /*-----------------------------------------------------------*/
\r
162 typedef struct xARP_CACHE_TABLE_ROW
\r
164 uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */
\r
165 xMACAddress_t xMACAddress; /* The MAC address of an ARP cache entry. */
\r
166 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
171 eARPCacheMiss = 0, /* An ARP table lookup did not find a valid entry. */
\r
172 eARPCacheHit, /* An ARP table lookup found a valid entry. */
\r
173 eCantSendPacket /* There is no IP address, or an ARP is still in progress, so the packet cannot be sent. */
\r
174 } eARPLookupResult_t;
\r
178 eNotFragment = 0, /* The IP packet being sent is not part of a fragment. */
\r
179 eFirstFragment, /* The IP packet being sent is the first in a set of fragmented packets. */
\r
180 eFollowingFragment /* The IP packet being sent is part of a set of fragmented packets. */
\r
181 } eIPFragmentStatus_t;
\r
184 /*-----------------------------------------------------------*/
\r
187 * Called when new data is available from the network interface.
\r
189 static void prvProcessEthernetPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
192 * Called when the application has generated a UDP packet to send.
\r
194 static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
197 * Processes incoming ARP packets.
\r
199 static eFrameProcessingResult_t prvProcessARPPacket( xARPPacket_t * const pxARPFrame );
\r
202 * Process incoming IP packets.
\r
204 static eFrameProcessingResult_t prvProcessIPPacket( const xIPPacket_t * const pxIPPacket, xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
207 * Process incoming ICMP packets.
\r
209 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
210 static eFrameProcessingResult_t prvProcessICMPPacket( xICMPPacket_t * const pxICMPPacket );
\r
211 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
\r
214 * Swap the source and destination addresses in an already constructed Ethernet
\r
215 * frame, and send the frame to the network.
\r
217 static void prvReturnEthernetFrame( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
220 * Return the checksum generated over usDataLengthBytes from pucNextData.
\r
222 static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes );
\r
225 * The callback function that is assigned to all periodic processing timers -
\r
226 * namely the DHCP timer and the ARP timer.
\r
228 void vIPFunctionsTimerCallback( xTimerHandle xTimer );
\r
231 * Reduce the age count in each entry within the ARP cache. An entry is no
\r
232 * longer considered valid and is deleted if its age reaches zero.
\r
234 static void prvAgeARPCache( void );
\r
237 * If ulIPAddress is already in the ARP cache table then reset the age of the
\r
238 * entry back to its maximum value. If ulIPAddress is not already in the ARP
\r
239 * cache table then add it - replacing the oldest current entry if there is not
\r
240 * a free space available.
\r
242 static void prvRefreshARPCacheEntry( const xMACAddress_t * const pxMACAddress, const uint32_t ulIPAddress );
\r
245 * Creates the pseudo header necessary then generate the checksum over the UDP
\r
246 * packet. Returns the calculated checksum.
\r
248 static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket );
\r
251 * Look for ulIPAddress in the ARP cache. If the IP address exists, copy the
\r
252 * associated MAC address into pxMACAddress, refresh the ARP cache entry's
\r
253 * age, and return eARPCacheHit. If the IP address does not exist in the ARP
\r
254 * cache return eARPCacheMiss. If the packet cannot be sent for any reason
\r
255 * (maybe DHCP is still in process, or the addressing needs a gateway but there
\r
256 * isn't a gateway defined) then return eCantSendPacket.
\r
258 static eARPLookupResult_t prvGetARPCacheEntry( uint32_t *pulIPAddress, xMACAddress_t * const pxMACAddress );
\r
261 * The main UDP/IP stack processing task. This task receives commands/events
\r
262 * from the network hardware drivers, tasks that are using sockets, and software
\r
263 * timers (such as the ARP timer).
\r
265 static void prvIPTask( void *pvParameters );
\r
268 * Send out an ARP request for the IP address contained in pxNetworkBuffer, and
\r
269 * add an entry into the ARP table that indicates that an ARP reply is
\r
270 * outstanding so re-transmissions can be generated.
\r
272 static void prvGenerateARPRequestPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );
\r
275 * Called when outgoing packets are fragmented and require a fragment offset in
\r
276 * their IP headers. Set the fragment offset (which includes the IP flags) and
\r
277 * length from the data passed in the pxFragmentParameters structure.
\r
279 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
280 static void prvCalculateFragmentOffsetAndLength( xIPFragmentParameters_t *pxFragmentParameters, uint16_t *pusFragmentOffset, uint16_t *pusFragmentLength );
\r
281 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS */
\r
284 * Complete the pxUDPPacket header with the information passed in
\r
285 * pxNetworkBuffer. ucSocketOptions are passed in case the options include
\r
286 * disabling the checksum.
\r
288 static void prvCompleteUDPHeader( xNetworkBufferDescriptor_t *pxNetworkBuffer, xUDPPacket_t *pxUDPPacket, uint8_t ucSocketOptions );
\r
291 * Send the event eEvent to the IP task event queue, using a block time of
\r
292 * zero. Return pdPASS if the message was sent successfully, otherwise return
\r
295 static portBASE_TYPE prvSendEventToIPTask( eIPEvent_t eEvent );
\r
298 * Generate and send an ARP request for the IP address passed in ulIPAddress.
\r
300 static void prvOutputARPRequest( uint32_t ulIPAddress );
\r
303 * Turns around an incoming ping request to convert it into a ping reply.
\r
305 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
\r
306 static eFrameProcessingResult_t prvProcessICMPEchoRequest( xICMPPacket_t * const pxICMPPacket );
\r
307 #endif /* ipconfigREPLY_TO_INCOMING_PINGS */
\r
310 * Processes incoming ping replies. The application callback function
\r
311 * vApplicationPingReplyHook() is called with the results.
\r
313 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
314 static void prvProcessICMPEchoReply( xICMPPacket_t * const pxICMPPacket );
\r
315 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
318 * Called to create a network connection when the stack is first started, or
\r
319 * when the network connection is lost.
\r
321 static void prvProcessNetworkDownEvent( void );
\r
323 /*-----------------------------------------------------------*/
\r
325 /* The queue used to pass events into the UDP task for processing. */
\r
326 xQueueHandle xNetworkEventQueue = NULL;
\r
328 /* The ARP cache. */
\r
329 static xARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
\r
331 /* The timer that triggers ARP events. */
\r
332 static xTimerHandle xARPTimer = NULL;
\r
334 /* Used to ensure network down events cannot be missed when they cannot be
\r
335 posted to the network event queue because the network event queue is already
\r
337 static portBASE_TYPE xNetworkDownEventPending = pdFALSE;
\r
339 /* For convenience, a MAC address of all zeros and another of all 0xffs are
\r
340 defined const for quick reference. */
\r
341 static const xMACAddress_t xNullMACAddress = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
\r
342 static const xMACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
\r
344 /* Part of the Ethernet and IP headers are always constant when sending an IPv4
\r
345 UDP packet. This array defines the constant parts, allowing this part of the
\r
346 packet to be filled in using a simple memcpy() instead of individual writes. */
\r
347 uint8_t xDefaultPartUDPPacketHeader[] =
\r
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */
\r
350 0x08, 0x00, /* Ethernet frame type. */
\r
351 ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
\r
352 0x00, /* ucDifferentiatedServicesCode. */
\r
353 0x00, 0x00, /* usLength. */
\r
354 0x00, 0x00, /* usIdentification. */
\r
355 0x00, 0x00, /* usFragmentOffset. */
\r
356 updconfigIP_TIME_TO_LIVE, /* ucTimeToLive */
\r
357 ipPROTOCOL_UDP, /* ucProtocol. */
\r
358 0x00, 0x00, /* usHeaderChecksum. */
\r
359 0x00, 0x00, 0x00, 0x00 /* Source IP address. */
\r
362 /* Part of the Ethernet and ARP headers are always constant when sending an IPv4
\r
363 ARP packet. This array defines the constant parts, allowing this part of the
\r
364 packet to be filled in using a simple memcpy() instead of individual writes. */
\r
365 static const uint8_t xDefaultPartARPPacketHeader[] =
\r
367 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
\r
368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
\r
369 0x08, 0x06, /* Ethernet frame type (ipARP_TYPE). */
\r
370 0x00, 0x01, /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
\r
371 0x08, 0x00, /* usProtocolType. */
\r
372 ipMAC_ADDRESS_LENGTH_BYTES, /* ucHardwareAddressLength. */
\r
373 ipIP_ADDRESS_LENGTH_BYTES, /* ucProtocolAddressLength. */
\r
374 0x00, 0x01, /* usOperation (ipARP_REQUEST). */
\r
375 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
\r
376 0x00, 0x00, 0x00, 0x00, /* ulSenderProtocolAddress. */
\r
377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* xTargetHardwareAddress. */
\r
380 /* Structure that stores the netmask, gateway address and DNS server addresses. */
\r
381 static xNetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0 };
\r
383 /*-----------------------------------------------------------*/
\r
385 static void prvIPTask( void *pvParameters )
\r
387 xIPStackEvent_t xReceivedEvent;
\r
389 /* Just to prevent compiler warnings about unused parameters. */
\r
390 ( void ) pvParameters;
\r
392 /* Create the ARP timer, but don't start it until the network has
\r
394 xARPTimer = xTimerCreate( ( const signed char * const ) "ARPTimer", ( ipARP_TIMER_PERIOD_MS / portTICK_RATE_MS ), pdTRUE, ( void * ) eARPTimerEvent, vIPFunctionsTimerCallback );
\r
395 configASSERT( xARPTimer );
\r
397 /* Generate a dummy message to say that the network connection has gone
\r
398 down. This will cause this task to initialise the network interface. After
\r
399 this it is the responsibility of the network interface hardware driver to
\r
400 send this message if a previously connected network is disconnected. */
\r
401 FreeRTOS_NetworkDown();
\r
403 /* Loop, processing IP events. */
\r
406 /* Wait until there is something to do. */
\r
407 if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, portMAX_DELAY ) == pdPASS )
\r
409 iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );
\r
411 switch( xReceivedEvent.eEventType )
\r
413 case eNetworkDownEvent :
\r
414 /* Attempt to establish a connection. */
\r
415 prvProcessNetworkDownEvent();
\r
418 case eEthernetRxEvent :
\r
419 /* The network hardware driver has received a new packet.
\r
420 A pointer to the received buffer is located in the pvData
\r
421 member of the received event structure. */
\r
422 prvProcessEthernetPacket( ( xNetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
\r
425 case eARPTimerEvent :
\r
426 /* The ARP timer has expired, process the ARP cache. */
\r
430 case eStackTxEvent :
\r
431 /* The network stack has generated a packet to send. A
\r
432 pointer to the generated buffer is located in the pvData
\r
433 member of the received event structure. */
\r
434 prvProcessGeneratedPacket( ( xNetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
\r
438 /* The DHCP state machine needs processing. */
\r
439 #if ipconfigUSE_DHCP == 1
\r
441 vDHCPProcess( pdFALSE, ( xMACAddress_t * ) ipLOCAL_MAC_ADDRESS, ipLOCAL_IP_ADDRESS_POINTER, &xNetworkAddressing );
\r
447 /* Should not get here. */
\r
451 if( xNetworkDownEventPending != pdFALSE )
\r
453 /* A network down event could not be posted to the network
\r
454 event queue because the queue was full. Try posting again. */
\r
455 FreeRTOS_NetworkDown();
\r
460 /*-----------------------------------------------------------*/
\r
462 void FreeRTOS_NetworkDown( void )
\r
464 static const xIPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
\r
465 const portTickType xDontBlock = 0;
\r
467 /* Simply send the network task the appropriate event. */
\r
468 if( xQueueSendToBack( xNetworkEventQueue, &xNetworkDownEvent, xDontBlock ) != pdPASS )
\r
470 xNetworkDownEventPending = pdTRUE;
\r
474 xNetworkDownEventPending = pdFALSE;
\r
477 iptraceNETWORK_DOWN();
\r
479 /*-----------------------------------------------------------*/
\r
481 portBASE_TYPE FreeRTOS_NetworkDownFromISR( void )
\r
483 static const xIPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
\r
484 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
486 /* Simply send the network task the appropriate event. */
\r
487 if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
\r
489 xNetworkDownEventPending = pdTRUE;
\r
493 xNetworkDownEventPending = pdFALSE;
\r
495 iptraceNETWORK_DOWN();
\r
497 return xHigherPriorityTaskWoken;
\r
499 /*-----------------------------------------------------------*/
\r
501 void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, portTickType xBlockTimeTicks )
\r
503 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
506 /* Cap the block time. The reason for this is explained where
\r
507 ipconfigMAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official
\r
508 FreeRTOSIPConfig.h header file is being used). */
\r
509 if( xBlockTimeTicks > ipconfigMAX_SEND_BLOCK_TIME_TICKS )
\r
511 xBlockTimeTicks = ipconfigMAX_SEND_BLOCK_TIME_TICKS;
\r
514 /* Obtain a network buffer with the required amount of storage. */
\r
515 pxNetworkBuffer = pxNetworkBufferGet( sizeof( xUDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );
\r
517 if( pxNetworkBuffer != NULL )
\r
519 /* Leave space for the UPD header. */
\r
520 pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] );
\r
527 return ( void * ) pvReturn;
\r
529 /*-----------------------------------------------------------*/
\r
531 void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )
\r
533 uint8_t *pucBuffer;
\r
535 /* Obtain the network buffer from the zero copy pointer. */
\r
536 pucBuffer = ( uint8_t * ) pvBuffer;
\r
537 pucBuffer -= ( ipBUFFER_PADDING + sizeof( xUDPPacket_t ) );
\r
539 vNetworkBufferRelease( * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer ) );
\r
541 /*-----------------------------------------------------------*/
\r
543 uint8_t * FreeRTOS_GetMACAddress( void )
\r
545 return ipLOCAL_MAC_ADDRESS;
\r
547 /*-----------------------------------------------------------*/
\r
549 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
551 static portBASE_TYPE xReturn = pdFALSE;
\r
553 /* Only create the IP event queue if it has not already been created, in
\r
554 case this function is called more than once. */
\r
555 if( xNetworkEventQueue == NULL )
\r
557 xNetworkEventQueue = xQueueCreate( ipconfigEVENT_QUEUE_LENGTH, sizeof( xIPStackEvent_t ) );
\r
558 configASSERT( xNetworkEventQueue );
\r
559 vQueueAddToRegistry( xNetworkEventQueue, ( signed char * ) "NetEvnt" );
\r
562 if( xNetworkBuffersInitialise() == pdPASS )
\r
564 if( xNetworkEventQueue != NULL )
\r
566 /* xReturn is static to ensure the network interface is not
\r
567 initialised twice. */
\r
568 if( xReturn == pdFALSE )
\r
570 /* Store the local IP and MAC address. */
\r
571 xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );
\r
572 xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );
\r
573 xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );
\r
574 xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );
\r
576 #if ipconfigUSE_DHCP == 1
\r
578 /* The IP address is not set until DHCP completes. */
\r
579 *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;
\r
583 *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
\r
585 #endif /* ipconfigUSE_DHCP == 1 */
\r
587 /* The MAC address is stored in the start of the default packet
\r
588 header fragment, which is used when sending UDP packets. */
\r
589 memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
591 /* Prepare the sockets interface. */
\r
592 FreeRTOS_SocketsInit();
\r
594 /* Create the task that processes Ethernet and stack events. */
\r
595 xReturn = xTaskCreate( prvIPTask, ( const signed char * const ) "UDP/IP", ipconfigUDP_TASK_STACK_SIZE_WORDS, NULL, ipconfigUDP_TASK_PRIORITY, NULL );
\r
602 /*-----------------------------------------------------------*/
\r
604 void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )
\r
606 if( pulIPAddress != NULL )
\r
608 *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
611 if( pulNetMask != NULL )
\r
613 *pulNetMask = xNetworkAddressing.ulNetMask;
\r
616 if( pulGatewayAddress != NULL )
\r
618 *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;
\r
621 if( pulDNSServerAddress != NULL )
\r
623 *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;
\r
626 /*-----------------------------------------------------------*/
\r
628 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
630 portBASE_TYPE FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, portTickType xBlockTimeTicks )
\r
632 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
633 xICMPHeader_t *pxICMPHeader;
\r
634 portBASE_TYPE xReturn = pdFAIL;
\r
635 static uint16_t usSequenceNumber = 0;
\r
637 xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
\r
639 if( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( xIPHeader_t ) ) - sizeof( xICMPHeader_t ) ) )
\r
641 pxNetworkBuffer = pxNetworkBufferGet( xNumberOfBytesToSend + sizeof( xICMPPacket_t ), xBlockTimeTicks );
\r
643 if( pxNetworkBuffer != NULL )
\r
645 pxICMPHeader = ( xICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] );
\r
646 usSequenceNumber++;
\r
648 /* Fill in the basic header information. */
\r
649 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;
\r
650 pxICMPHeader->ucTypeOfService = 0;
\r
651 pxICMPHeader->usIdentifier = usSequenceNumber;
\r
652 pxICMPHeader->usSequenceNumber = usSequenceNumber;
\r
653 pxICMPHeader->usChecksum = 0;
\r
655 /* Find the start of the data. */
\r
656 pucChar = ( uint8_t * ) pxICMPHeader;
\r
657 pucChar += sizeof( xICMPHeader_t );
\r
659 /* Just memset the data to a fixed value. */
\r
660 memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );
\r
662 /* The message is complete, calculate the checksum. */
\r
663 pxICMPHeader->usChecksum = prvGenerateChecksum( ( uint8_t * ) pxICMPHeader, ( uint16_t ) ( xNumberOfBytesToSend + sizeof( xICMPHeader_t ) ) );
\r
665 /* Complete the network buffer information. */
\r
666 pxNetworkBuffer->ulIPAddress = ulIPAddress;
\r
667 pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
\r
668 pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( xICMPHeader_t );
\r
670 /* Send to the stack. */
\r
671 xStackTxEvent.pvData = pxNetworkBuffer;
\r
672 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xBlockTimeTicks ) != pdPASS )
\r
674 vNetworkBufferRelease( pxNetworkBuffer );
\r
675 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
\r
679 xReturn = usSequenceNumber;
\r
685 /* The requested number of bytes will not fit in the available space
\r
686 in the network buffer. Outgoing fragmentation is only supported for
\r
693 #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */
\r
695 /*-----------------------------------------------------------*/
\r
697 static portBASE_TYPE prvSendEventToIPTask( eIPEvent_t eEvent )
\r
699 xIPStackEvent_t xEventMessage;
\r
700 const portTickType xDontBlock = 0;
\r
701 portBASE_TYPE xReturn;
\r
703 xEventMessage.eEventType = eEvent;
\r
704 xReturn = xQueueSendToBack( xNetworkEventQueue, &xEventMessage, xDontBlock );
\r
706 if( xReturn != pdPASS )
\r
708 iptraceSTACK_TX_EVENT_LOST( ipARP_TIMER_EVENT );
\r
713 /*-----------------------------------------------------------*/
\r
715 void vIPFunctionsTimerCallback( xTimerHandle xTimer )
\r
717 eIPEvent_t eMessage;
\r
719 /* This time can be used to send more than one type of message to the IP
\r
720 task. The message ID is stored in the ID of the timer. The strange
\r
721 casting is to avoid compiler warnings. */
\r
722 eMessage = ( eIPEvent_t ) ( ( int ) pvTimerGetTimerID( xTimer ) );
\r
724 prvSendEventToIPTask( eMessage );
\r
726 /*-----------------------------------------------------------*/
\r
728 static void prvOutputARPRequest( uint32_t ulIPAddress )
\r
730 xNetworkBufferDescriptor_t *pxNetworkBuffer;
\r
732 /* This is called from the context of the IP event task, so a block time
\r
733 must not be used. */
\r
734 pxNetworkBuffer = pxNetworkBufferGet( sizeof( xARPPacket_t ), 0 );
\r
735 if( pxNetworkBuffer != NULL )
\r
737 pxNetworkBuffer->ulIPAddress = ulIPAddress;
\r
738 prvGenerateARPRequestPacket( pxNetworkBuffer );
\r
739 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
742 /*-----------------------------------------------------------*/
\r
744 static void prvAgeARPCache( void )
\r
748 /* Loop through each entry in the ARP cache. */
\r
749 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
751 /* If the entry is valid (its age is greater than zero). */
\r
752 if( xARPCache[ x ].ucAge > 0U )
\r
754 /* Decrement the age value of the entry in this ARP cache table row.
\r
755 When the age reaches zero it is no longer considered valid. */
\r
756 ( xARPCache[ x ].ucAge )--;
\r
758 /* If the entry has a MAC address of 0, then it is waiting an ARP
\r
759 reply, and the ARP request should be retransmitted. */
\r
760 if( memcmp( ( void * ) &xNullMACAddress, ( void * ) &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
762 prvOutputARPRequest( xARPCache[ x ].ulIPAddress );
\r
764 else if( xARPCache[ x ].ucAge <= ipMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
\r
766 /* This entry will get removed soon. See if the MAC address is
\r
767 still valid to prevent this happening. */
\r
768 iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
\r
769 prvOutputARPRequest( xARPCache[ x ].ulIPAddress );
\r
773 /* The age has just ticked down, with nothing to do. */
\r
776 if( xARPCache[ x ].ucAge == 0 )
\r
778 /* The entry is no longer valid. Wipe it out. */
\r
779 iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
\r
780 xARPCache[ x ].ulIPAddress = 0UL;
\r
785 /*-----------------------------------------------------------*/
\r
787 static eARPLookupResult_t prvGetARPCacheEntry( uint32_t *pulIPAddress, xMACAddress_t * const pxMACAddress )
\r
790 eARPLookupResult_t eReturn;
\r
791 uint32_t ulAddressToLookup;
\r
793 if( *pulIPAddress == ipBROADCAST_IP_ADDRESS )
\r
795 /* This is a broadcast so uses the broadcast MAC address. */
\r
796 memcpy( ( void * ) pxMACAddress, &xBroadcastMACAddress, sizeof( xMACAddress_t ) );
\r
797 eReturn = eARPCacheHit;
\r
799 else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )
\r
801 /* The IP address has not yet been assigned, so there is nothing that
\r
803 eReturn = eCantSendPacket;
\r
807 if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
\r
809 /* The IP address is off the local network, so look up the hardware
\r
810 address of the router, if any. */
\r
811 ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
\r
815 /* The IP address is on the local network, so lookup the requested
\r
816 IP address directly. */
\r
817 ulAddressToLookup = *pulIPAddress;
\r
820 if( ulAddressToLookup == 0UL )
\r
822 /* The address is not on the local network, and there is not a
\r
824 eReturn = eCantSendPacket;
\r
828 eReturn = eARPCacheMiss;
\r
830 /* Loop through each entry in the ARP cache. */
\r
831 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
833 /* Does this row in the ARP cache table hold an entry for the IP
\r
834 address being queried? */
\r
835 if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
\r
837 /* The IP address matched. Is there a valid MAC address? */
\r
838 if( memcmp( ( void * ) &xNullMACAddress, ( void * ) &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
840 /* This entry is waiting an ARP reply, so is not valid. */
\r
841 eReturn = eCantSendPacket;
\r
845 /* A valid entry was found. */
\r
846 memcpy( pxMACAddress, &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) );
\r
847 eReturn = eARPCacheHit;
\r
851 if( eReturn != eARPCacheMiss )
\r
857 if( eReturn == eARPCacheMiss )
\r
859 /* It might be that the ARP has to go to the gateway. */
\r
860 *pulIPAddress = ulAddressToLookup;
\r
867 /*-----------------------------------------------------------*/
\r
869 static void prvRefreshARPCacheEntry( const xMACAddress_t * const pxMACAddress, const uint32_t ulIPAddress )
\r
871 portBASE_TYPE x, xEntryFound = pdFALSE, xOldestEntry = 0;
\r
872 uint8_t ucMinAgeFound = 0U;
\r
874 /* Only process the IP address if it is on the local network. */
\r
875 if( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
\r
877 /* Start with the maximum possible number. */
\r
880 /* For each entry in the ARP cache table. */
\r
881 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
883 /* Does this line in the cache table hold an entry for the IP
\r
884 address being queried? */
\r
885 if( xARPCache[ x ].ulIPAddress == ulIPAddress )
\r
887 /* If the MAC address is all zeros then the refresh is due to
\r
888 an ARP reply, so in effect this is a new entry in the ARP
\r
890 if( memcmp( &( xARPCache[ x ].xMACAddress ), &xNullMACAddress, sizeof( xMACAddress_t ) ) == 0 )
\r
892 iptraceARP_TABLE_ENTRY_CREATED( xARPCache[ x ].ulIPAddress, *pxMACAddress );
\r
895 /* Refresh the cache entry so the entry's age is back to its
\r
897 xARPCache[ x ].ucAge = ipconfigMAX_ARP_AGE;
\r
898 memcpy( &( xARPCache[ x ].xMACAddress ), pxMACAddress, sizeof( xMACAddress_t ) );
\r
899 xEntryFound = pdTRUE;
\r
904 /* As the table is traversed, remember the table row that
\r
905 contains the oldest entry (the lowest age count, as ages are
\r
906 decremented to zero) so the row can be re-used if this function
\r
907 needs to add an entry that does not already exist. */
\r
908 if( xARPCache[ x ].ucAge < ucMinAgeFound )
\r
910 ucMinAgeFound = xARPCache[ x ].ucAge;
\r
916 if( xEntryFound == pdFALSE )
\r
918 /* The wanted entry does not already exist. Add the entry into the
\r
919 cache, replacing the oldest entry (which might be an empty entry). */
\r
920 xARPCache[ xOldestEntry ].ulIPAddress = ulIPAddress;
\r
921 memcpy( &( xARPCache[ xOldestEntry ].xMACAddress ), pxMACAddress, sizeof( xMACAddress_t ) );
\r
923 /* If the MAC address is all zeros, then this entry is not yet
\r
924 complete but still waiting the reply from an ARP request. When this
\r
925 is the case the age is set to a much lower value as an ARP
\r
926 retransmission will be generated each time the ARP timer is called
\r
927 while the reply is still outstanding. */
\r
928 if( pxMACAddress == &xNullMACAddress )
\r
930 xARPCache[ xOldestEntry ].ucAge = ipconfigMAX_ARP_RETRANSMISSIONS;
\r
934 iptraceARP_TABLE_ENTRY_CREATED( xARPCache[ xOldestEntry ].ulIPAddress, xARPCache[ xOldestEntry ].xMACAddress );
\r
935 xARPCache[ xOldestEntry ].ucAge = ipconfigMAX_ARP_AGE;
\r
940 /*-----------------------------------------------------------*/
\r
942 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
944 static void prvCalculateFragmentOffsetAndLength( xIPFragmentParameters_t *pxFragmentParameters, uint16_t *pusFragmentOffset, uint16_t *pusFragmentLength )
\r
946 *pusFragmentOffset = pxFragmentParameters->usFragmentedPacketOffset;
\r
948 if( *pusFragmentOffset != 0 )
\r
950 /* Take into account that the payload has had a UDP header added in the
\r
951 first fragment of the set. */
\r
952 *pusFragmentOffset += sizeof( xUDPHeader_t );
\r
955 /* The offset is defined in multiples of 8 bytes. */
\r
956 *pusFragmentOffset >>= ipSHIFT_TO_DIVIDE_BY_8;
\r
957 *pusFragmentLength = pxFragmentParameters->usFragmentLength;
\r
959 if( ( pxFragmentParameters->ucSocketOptions & FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET ) != 0 )
\r
961 /* Set the more fragments flag. */
\r
962 *pusFragmentOffset |= ipMORE_FRAGMENTS_FLAG_BIT;
\r
967 /*-----------------------------------------------------------*/
\r
969 static void prvCompleteUDPHeader( xNetworkBufferDescriptor_t *pxNetworkBuffer, xUDPPacket_t *pxUDPPacket, uint8_t ucSocketOptions )
\r
971 xUDPHeader_t *pxUDPHeader;
\r
973 pxUDPHeader = &( pxUDPPacket->xUDPHeader );
\r
975 pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
\r
976 pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
\r
977 pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xUDPHeader_t ) );
\r
978 pxUDPHeader->usLength = FreeRTOS_htons( pxUDPPacket->xUDPHeader.usLength );
\r
979 pxUDPHeader->usChecksum = 0;
\r
981 if( ( ucSocketOptions & FREERTOS_SO_UDPCKSUM_OUT ) != 0U )
\r
983 pxUDPHeader->usChecksum = prvGenerateUDPChecksum( pxUDPPacket );
\r
984 if( pxUDPHeader->usChecksum == 0x00 )
\r
986 /* A calculated checksum of 0 must be inverted as 0 means the
\r
987 checksum is disabled. */
\r
988 pxUDPHeader->usChecksum = 0xffffU;
\r
992 /*-----------------------------------------------------------*/
\r
994 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1
\r
996 static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
998 xUDPPacket_t *pxUDPPacket;
\r
999 xUDPHeader_t *pxUDPHeader;
\r
1000 xIPHeader_t *pxIPHeader;
\r
1001 eARPLookupResult_t eReturned;
\r
1002 eIPFragmentStatus_t eFragmentStatus;
\r
1003 uint16_t usFragmentOffset = 0, usFragmentLength;
\r
1004 xIPFragmentParameters_t *pxFragmentParameters;
\r
1005 static uint16_t usPacketIdentifier = 0U;
\r
1007 /* Map the UDP packet onto the start of the frame. */
\r
1008 pxUDPPacket = ( xUDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1010 /* Determine the ARP cache status for the requested IP address. */
\r
1011 eReturned = prvGetARPCacheEntry( &( pxNetworkBuffer->ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
\r
1013 if( eReturned != eCantSendPacket )
\r
1015 if( eReturned == eARPCacheHit )
\r
1017 iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
\r
1019 /* Create short cuts to the data within the packet. */
\r
1020 pxUDPHeader = &( pxUDPPacket->xUDPHeader );
\r
1021 pxIPHeader = &( pxUDPPacket->xIPHeader );
\r
1022 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );
\r
1024 /* IP header source and destination addresses must be set
\r
1025 before the UDP checksum is calculated. */
\r
1026 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1027 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1029 /* If the packet is not fragmented, or if the packet is the
\r
1030 first in a fragmented packet, then a UDP header is required. */
\r
1031 if( ( pxFragmentParameters->ucSocketOptions & FREERTOS_FRAGMENTED_PACKET ) == 0 )
\r
1033 eFragmentStatus = eNotFragment;
\r
1035 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1037 /* Is it possible that the packet is not actually a UDP
\r
1038 packet after all, but an ICMP packet. */
\r
1039 if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )
\r
1041 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );
\r
1044 #else /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1046 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );
\r
1048 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1051 usFragmentLength = 0U;
\r
1053 /* The identifier is incremented as this is a new and
\r
1054 unfragmented IP packet. */
\r
1055 usPacketIdentifier++;
\r
1057 else if( pxFragmentParameters->usFragmentedPacketOffset == 0 )
\r
1059 eFragmentStatus = eFirstFragment;
\r
1060 prvCalculateFragmentOffsetAndLength( pxFragmentParameters, &usFragmentOffset, &usFragmentLength );
\r
1061 /* Note FREERTOS_SO_UDPCKSUM_OUT is used because checksums
\r
1062 cannot currently be used on fragmented packets. */
\r
1063 pxFragmentParameters->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;
\r
1064 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );
\r
1066 /* The identifier is incremented because, although this is a
\r
1067 fragmented packet, it is the first in the fragmentation
\r
1069 usPacketIdentifier++;
\r
1073 eFragmentStatus = eFollowingFragment;
\r
1074 prvCalculateFragmentOffsetAndLength( pxFragmentParameters, &usFragmentOffset, &usFragmentLength );
\r
1077 /* memcpy() the constant parts of the header information into the
\r
1078 correct location within the packet. This fills in:
\r
1079 xEthernetHeader.xSourceAddress
\r
1080 xEthernetHeader.usFrameType
\r
1081 xIPHeader.ucVersionHeaderLength
\r
1082 xIPHeader.ucDifferentiatedServicesCode
\r
1083 xIPHeader.usLength
\r
1084 xIPHeader.usIdentification
\r
1085 xIPHeader.usFragmentOffset
\r
1086 xIPHeader.ucTimeToLive
\r
1087 xIPHeader.ucProtocol
\r
1089 xIPHeader.usHeaderChecksum
\r
1091 memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xDefaultPartUDPPacketHeader ) );
\r
1093 /* The fragment status is used to complete the length and
\r
1094 fragment offset fields. */
\r
1095 if( eFragmentStatus == eNotFragment )
\r
1097 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1099 else if( eFragmentStatus == eFirstFragment )
\r
1101 pxIPHeader->usFragmentOffset = FreeRTOS_htons( usFragmentOffset );
\r
1102 pxIPHeader->usLength = ( uint16_t ) ( usFragmentLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1106 pxIPHeader->usFragmentOffset = FreeRTOS_htons( usFragmentOffset );
\r
1107 pxIPHeader->usLength = ( uint16_t ) ( usFragmentLength + sizeof( xIPHeader_t ) );
\r
1110 /* The total transmit size adds on the Ethernet header. */
\r
1111 pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( xEthernetHeader_t );
\r
1112 pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
\r
1113 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1114 pxIPHeader->usIdentification = usPacketIdentifier;
\r
1115 pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH );
\r
1117 else if ( eReturned == eARPCacheMiss )
\r
1119 /* Send an ARP for the required IP address. */
\r
1120 iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
\r
1121 prvGenerateARPRequestPacket( pxNetworkBuffer );
\r
1123 /* Add an entry to the ARP table with a null hardware address.
\r
1124 This allows the ARP timer to know that an ARP reply is
\r
1125 outstanding, and perform retransmissions if necessary. */
\r
1126 prvRefreshARPCacheEntry( &xNullMACAddress, pxNetworkBuffer->ulIPAddress );
\r
1130 /* The lookup indicated that an ARP request has already been
\r
1131 sent out for the queried IP address. */
\r
1132 eReturned = eCantSendPacket;
\r
1136 if( eReturned != eCantSendPacket )
\r
1138 /* The network driver is responsible for freeing the network buffer
\r
1139 after the packet has been sent. */
\r
1140 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
1144 /* The packet can't be sent (DHCP not completed?). Just drop the
\r
1146 vNetworkBufferRelease( pxNetworkBuffer );
\r
1150 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 */
\r
1152 static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1154 xUDPPacket_t *pxUDPPacket;
\r
1155 xIPHeader_t *pxIPHeader;
\r
1156 eARPLookupResult_t eReturned;
\r
1158 /* Map the UDP packet onto the start of the frame. */
\r
1159 pxUDPPacket = ( xUDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1161 /* Determine the ARP cache status for the requested IP address. */
\r
1162 eReturned = prvGetARPCacheEntry( &( pxNetworkBuffer->ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
\r
1163 if( eReturned != eCantSendPacket )
\r
1165 if( eReturned == eARPCacheHit )
\r
1167 iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
\r
1169 /* Create short cuts to the data within the packet. */
\r
1170 pxIPHeader = &( pxUDPPacket->xIPHeader );
\r
1172 /* IP header source and destination addresses must be set before
\r
1173 the UDP checksum is calculated. The socket options, which
\r
1174 specify whether a checksum should be calculated or not, are
\r
1175 passed in the as yet unused part of the packet data. */
\r
1176 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1177 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1179 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1181 /* Is it possible that the packet is not actually a UDP packet
\r
1182 after all, but an ICMP packet. */
\r
1183 if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )
\r
1185 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] );
\r
1188 #else /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1190 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] );
\r
1192 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1194 /* memcpy() the constant parts of the header information into
\r
1195 the correct location within the packet. This fills in:
\r
1196 xEthernetHeader.xSourceAddress
\r
1197 xEthernetHeader.usFrameType
\r
1198 xIPHeader.ucVersionHeaderLength
\r
1199 xIPHeader.ucDifferentiatedServicesCode
\r
1200 xIPHeader.usLength
\r
1201 xIPHeader.usIdentification
\r
1202 xIPHeader.usFragmentOffset
\r
1203 xIPHeader.ucTimeToLive
\r
1204 xIPHeader.ucProtocol
\r
1206 xIPHeader.usHeaderChecksum
\r
1208 memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xDefaultPartUDPPacketHeader ) );
\r
1210 #if ipconfigSUPPORT_OUTGOING_PINGS == 1
\r
1212 if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA )
\r
1214 pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
\r
1215 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) );
\r
1219 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1222 #else /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1224 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );
\r
1226 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1228 /* The total transmit size adds on the Ethernet header. */
\r
1229 pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( xEthernetHeader_t );
\r
1230 pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
\r
1231 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
\r
1232 pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH );
\r
1234 else if ( eReturned == eARPCacheMiss )
\r
1236 /* Generate an ARP for the required IP address. */
\r
1237 iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
\r
1238 prvGenerateARPRequestPacket( pxNetworkBuffer );
\r
1240 /* Add an entry to the ARP table with a null hardware address.
\r
1241 This allows the ARP timer to know that an ARP reply is
\r
1242 outstanding, and perform retransmissions if necessary. */
\r
1243 prvRefreshARPCacheEntry( &xNullMACAddress, pxNetworkBuffer->ulIPAddress );
\r
1247 /* The lookup indicated that an ARP request has already been
\r
1248 sent out for the queried IP address. */
\r
1249 eReturned = eCantSendPacket;
\r
1253 if( eReturned != eCantSendPacket )
\r
1255 /* The network driver is responsible for freeing the network buffer
\r
1256 after the packet has been sent. */
\r
1257 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
1261 /* The packet can't be sent (DHCP not completed?). Just drop the
\r
1263 vNetworkBufferRelease( pxNetworkBuffer );
\r
1268 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 */
\r
1269 /*-----------------------------------------------------------*/
\r
1271 static void prvGenerateARPRequestPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1273 xARPPacket_t *pxARPPacket;
\r
1275 pxARPPacket = ( xARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1277 /* memcpy the const part of the header information into the correct
\r
1278 location in the packet. This copies:
\r
1279 xEthernetHeader.ulDestinationAddress
\r
1280 xEthernetHeader.usFrameType;
\r
1281 xARPHeader.usHardwareType;
\r
1282 xARPHeader.usProtocolType;
\r
1283 xARPHeader.ucHardwareAddressLength;
\r
1284 xARPHeader.ucProtocolAddressLength;
\r
1285 xARPHeader.usOperation;
\r
1286 xARPHeader.xTargetHardwareAddress;
\r
1288 memcpy( ( void * ) &( pxARPPacket->xEthernetHeader ), ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );
\r
1289 memcpy( ( void * ) &( pxARPPacket->xEthernetHeader.xSourceAddress ) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
1290 memcpy( ( void * ) &( pxARPPacket->xARPHeader.xSenderHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
1291 pxARPPacket->xARPHeader.ulSenderProtocolAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1292 pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
\r
1294 pxNetworkBuffer->xDataLength = sizeof( xARPPacket_t );
\r
1296 iptraceCREATING_ARP_REQUEST( ulIPAddress );
\r
1298 /*-----------------------------------------------------------*/
\r
1300 eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
\r
1302 eFrameProcessingResult_t eReturn;
\r
1303 const xEthernetHeader_t *pxEthernetHeader;
\r
1305 pxEthernetHeader = ( const xEthernetHeader_t * ) pucEthernetBuffer;
\r
1307 if( memcmp( ( void * ) &xBroadcastMACAddress, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
1309 /* The packet was a broadcast - process it. */
\r
1310 eReturn = eProcessBuffer;
\r
1312 else if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( xMACAddress_t ) ) == 0 )
\r
1314 /* The packet was to this node directly - process it. */
\r
1315 eReturn = eProcessBuffer;
\r
1319 /* The packet was not a broadcast, or for this node, just release
\r
1320 the buffer without taking any other action. */
\r
1321 eReturn = eReleaseBuffer;
\r
1324 #if ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1
\r
1326 uint16_t usFrameType;
\r
1328 if( eReturn == eProcessBuffer )
\r
1330 usFrameType = pxEthernetHeader->usFrameType;
\r
1331 usFrameType = FreeRTOS_ntohs( usFrameType );
\r
1333 if( usFrameType <= 0x600U )
\r
1335 /* Not an Ethernet II frame. */
\r
1336 eReturn = eReleaseBuffer;
\r
1340 #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */
\r
1344 /*-----------------------------------------------------------*/
\r
1346 static void prvProcessNetworkDownEvent( void )
\r
1348 /* Stop the ARP timer while there is no network. */
\r
1349 xTimerStop( xARPTimer, portMAX_DELAY );
\r
1351 #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
\r
1353 static portBASE_TYPE xCallEventHook = pdFALSE;
\r
1355 /* The first network down event is generated by the IP stack
\r
1356 itself to initialise the network hardware, so do not call the
\r
1357 network down event the first time through. */
\r
1358 if( xCallEventHook == pdFALSE )
\r
1360 vApplicationIPNetworkEventHook( eNetworkDown );
\r
1362 xCallEventHook = pdTRUE;
\r
1366 /* The network has been disconnected (or is being
\r
1367 initialised for the first time). Perform whatever hardware
\r
1368 processing is necessary to bring it up again, or wait for it
\r
1369 to be available again. This is hardware dependent. */
\r
1370 if( xNetworkInterfaceInitialise() != pdPASS )
\r
1372 /* Ideally the network interface initialisation function
\r
1373 will only return when the network is available. In case
\r
1374 this is not the case, wait a while before retrying the
\r
1375 initialisation. */
\r
1376 vTaskDelay( ipINITIALISATION_RETRY_DELAY );
\r
1377 FreeRTOS_NetworkDown();
\r
1381 /* Start the ARP timer. */
\r
1382 xTimerStart( xARPTimer, portMAX_DELAY );
\r
1384 #if ipconfigUSE_DHCP == 1
\r
1386 /* The network is not up until DHCP has completed. */
\r
1387 vDHCPProcess( pdTRUE, ( xMACAddress_t * ) ipLOCAL_MAC_ADDRESS, ipLOCAL_IP_ADDRESS_POINTER, &xNetworkAddressing );
\r
1388 prvSendEventToIPTask( eDHCPEvent );
\r
1392 #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
\r
1394 vApplicationIPNetworkEventHook( eNetworkUp );
\r
1396 #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
\r
1398 /* Static configuration is being used, so the network is now up. */
\r
1399 #if ipconfigFREERTOS_PLUS_NABTO == 1
\r
1401 vStartNabtoTask();
\r
1403 #endif /* ipconfigFREERTOS_PLUS_NABTO */
\r
1408 /*-----------------------------------------------------------*/
\r
1410 static void prvProcessEthernetPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1412 xEthernetHeader_t *pxEthernetHeader;
\r
1413 volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */
\r
1415 configASSERT( pxNetworkBuffer );
\r
1417 /* Interpret the Ethernet frame. */
\r
1418 eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
\r
1419 pxEthernetHeader = ( xEthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
1421 if( eReturned == eProcessBuffer )
\r
1423 /* Interpret the received Ethernet packet. */
\r
1424 switch ( pxEthernetHeader->usFrameType )
\r
1427 /* The Ethernet frame contains an ARP packet. */
\r
1428 eReturned = prvProcessARPPacket( ( xARPPacket_t * ) pxEthernetHeader );
\r
1432 /* The Ethernet frame contains an IP packet. */
\r
1433 eReturned = prvProcessIPPacket( ( xIPPacket_t * ) pxEthernetHeader, pxNetworkBuffer );
\r
1437 /* No other packet types are handled. Nothing to do. */
\r
1438 eReturned = eReleaseBuffer;
\r
1443 /* Perform any actions that resulted from processing the Ethernet
\r
1445 switch( eReturned )
\r
1447 case eReturnEthernetFrame :
\r
1448 /* The Ethernet frame will have been updated (maybe it was
\r
1449 an ARP request or a PING request?) and should be sent back to
\r
1451 prvReturnEthernetFrame( pxNetworkBuffer );
\r
1452 /* The buffer must be released once
\r
1453 the frame has been transmitted. */
\r
1456 case eFrameConsumed :
\r
1457 /* The frame is in use somewhere, don't release the buffer
\r
1462 /* The frame is not being used anywhere, and the
\r
1463 xNetworkBufferDescriptor_t structure containing the frame should just be
\r
1464 released back to the list of free buffers. */
\r
1465 vNetworkBufferRelease( pxNetworkBuffer );
\r
1469 /*-----------------------------------------------------------*/
\r
1471 static eFrameProcessingResult_t prvProcessIPPacket( const xIPPacket_t * const pxIPPacket, xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1473 eFrameProcessingResult_t eReturn = eReleaseBuffer;
\r
1474 const xIPHeader_t * pxIPHeader;
\r
1475 xUDPPacket_t *pxUDPPacket;
\r
1476 portBASE_TYPE xChecksumIsCorrect;
\r
1478 pxIPHeader = &( pxIPPacket->xIPHeader );
\r
1480 /* Is the packet for this node? */
\r
1481 if( ( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER ) || ( pxIPHeader->ulDestinationIPAddress == ipBROADCAST_IP_ADDRESS ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0 ) )
\r
1483 /* Ensure the frame is IPv4 with no options bytes, and that the incoming
\r
1484 packet is not fragmented (only outgoing packets can be fragmented) as
\r
1485 these are the only handled IP frames currently. */
\r
1486 if( ( pxIPHeader->ucVersionHeaderLength == ipIP_VERSION_AND_HEADER_LENGTH_BYTE ) && ( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) == 0U ) )
\r
1488 /* Is the IP header checksum correct? */
\r
1489 if( prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH ) == 0 )
\r
1491 /* Add the IP and MAC addresses to the ARP table if they are not
\r
1492 already there - otherwise refresh the age of the existing
\r
1494 prvRefreshARPCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
\r
1495 switch( pxIPHeader->ucProtocol )
\r
1497 case ipPROTOCOL_ICMP :
\r
1499 /* The IP packet contained an ICMP frame. Don't bother
\r
1500 checking the ICMP checksum, as if it is wrong then the
\r
1501 wrong data will also be returned, and the source of the
\r
1502 ping will know something went wrong because it will not
\r
1503 be able to validate what it receives. */
\r
1504 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1506 if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
\r
1508 eReturn = prvProcessICMPPacket( ( xICMPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ) );
\r
1511 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
\r
1514 case ipPROTOCOL_UDP :
\r
1516 /* The IP packet contained a UDP frame. */
\r
1517 pxUDPPacket = ( xUDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1519 /* Note the header values required prior to the
\r
1520 checksum generation as the checksum pseudo header
\r
1521 may clobber some of these values. */
\r
1522 pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( xUDPHeader_t );
\r
1523 pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;
\r
1524 pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
\r
1526 /* Is the checksum required? */
\r
1527 if( pxUDPPacket->xUDPHeader.usChecksum == 0 )
\r
1529 xChecksumIsCorrect = pdTRUE;
\r
1531 else if( prvGenerateUDPChecksum( pxUDPPacket ) == 0 )
\r
1533 xChecksumIsCorrect = pdTRUE;
\r
1537 xChecksumIsCorrect = pdFALSE;
\r
1540 /* Is the checksum correct? */
\r
1541 if( xChecksumIsCorrect == pdTRUE )
\r
1543 /* Pass the packet payload to the UDP sockets
\r
1544 implementation. */
\r
1545 if( xProcessReceivedUDPPacket( pxNetworkBuffer, pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )
\r
1547 eReturn = eFrameConsumed;
\r
1554 /* Not a supported frame type. */
\r
1563 /*-----------------------------------------------------------*/
\r
1565 static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket )
\r
1567 xPseudoHeader_t *pxPseudoHeader;
\r
1568 uint16_t usLength, usReturn;
\r
1570 /* Map the pseudo header into the correct place within the real IP
\r
1572 pxPseudoHeader = ( xPseudoHeader_t * ) &( pxUDPPacket->xIPHeader.ucTimeToLive );
\r
1574 /* Ordering here is important so as not to overwrite data that is required
\r
1575 but has not yet been used as the pseudo header overlaps the information
\r
1576 that is being copied into it. */
\r
1577 pxPseudoHeader->ulSourceAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
\r
1578 pxPseudoHeader->ulDestinationAddress = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
\r
1579 pxPseudoHeader->ucZeros = 0x00;
\r
1580 pxPseudoHeader->ucProtocol = ipPROTOCOL_UDP;
\r
1581 pxPseudoHeader->usUDPLength = pxUDPPacket->xUDPHeader.usLength;
\r
1583 usLength = FreeRTOS_ntohs( pxPseudoHeader->usUDPLength );
\r
1584 usReturn = prvGenerateChecksum( ( uint8_t * ) pxPseudoHeader, usLength + sizeof( xPseudoHeader_t ) );
\r
1588 /*-----------------------------------------------------------*/
\r
1590 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1592 static void prvProcessICMPEchoReply( xICMPPacket_t * const pxICMPPacket )
\r
1594 ePingReplyStatus_t eStatus = eSuccess;
\r
1595 uint16_t usDataLength, usCount;
\r
1598 /* Find the total length of the IP packet. */
\r
1599 usDataLength = pxICMPPacket->xIPHeader.usLength;
\r
1600 usDataLength = FreeRTOS_ntohs( usDataLength );
\r
1602 /* Remove the length of the IP headers to obtain the length of the ICMP
\r
1603 message itself. */
\r
1604 usDataLength -= sizeof( xIPHeader_t );
\r
1606 if( prvGenerateChecksum( ( uint8_t * ) &( pxICMPPacket->xICMPHeader ), usDataLength ) != 0 )
\r
1608 eStatus = eInvalidChecksum;
\r
1612 /* Remove the length of the ICMP header, to obtain the length of
\r
1613 data contained in the ping. */
\r
1614 usDataLength -= sizeof( xICMPHeader_t );
\r
1616 /* Find the first byte of the data within the ICMP packet. */
\r
1617 pucByte = ( uint8_t * ) pxICMPPacket;
\r
1618 pucByte += sizeof( xICMPPacket_t );
\r
1620 /* Check each byte. */
\r
1621 for( usCount = 0; usCount < usDataLength; usCount++ )
\r
1623 if( *pucByte != ipECHO_DATA_FILL_BYTE )
\r
1625 eStatus = eInvalidData;
\r
1633 vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );
\r
1637 /*-----------------------------------------------------------*/
\r
1639 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
\r
1641 static eFrameProcessingResult_t prvProcessICMPEchoRequest( xICMPPacket_t * const pxICMPPacket )
\r
1643 xICMPHeader_t *pxICMPHeader;
\r
1644 xIPHeader_t *pxIPHeader;
\r
1646 iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );
\r
1648 pxICMPHeader = &( pxICMPPacket->xICMPHeader );
\r
1649 pxIPHeader = &( pxICMPPacket->xIPHeader );
\r
1651 /* The checksum can be checked here - but a ping reply should be
\r
1652 returned even if the checksum is incorrect so the other end can
\r
1653 tell that the ping was received - even if the ping reply contains
\r
1655 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REPLY;
\r
1656 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
\r
1657 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1659 /* Update the checksum because the ucTypeOfMessage member in the
\r
1660 header has been changed to ipICMP_ECHO_REPLY. */
\r
1661 if( pxICMPHeader->usChecksum >= FreeRTOS_htons( ( ( uint16_t ) 0xffffU ) - ( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) ) ) )
\r
1663 pxICMPHeader->usChecksum += FreeRTOS_htons( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) ) + ( uint16_t ) 1U;
\r
1667 pxICMPHeader->usChecksum += FreeRTOS_htons( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) );
\r
1670 return eReturnEthernetFrame;
\r
1673 #endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */
\r
1675 /*-----------------------------------------------------------*/
\r
1677 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1679 static eFrameProcessingResult_t prvProcessICMPPacket( xICMPPacket_t * const pxICMPPacket )
\r
1681 eFrameProcessingResult_t eReturn = eReleaseBuffer;
\r
1683 iptraceICMP_PACKET_RECEIVED();
\r
1685 switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )
\r
1687 case ipICMP_ECHO_REQUEST :
\r
1688 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
\r
1690 eReturn = prvProcessICMPEchoRequest( pxICMPPacket );
\r
1692 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */
\r
1695 case ipICMP_ECHO_REPLY :
\r
1696 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
\r
1698 prvProcessICMPEchoReply( pxICMPPacket );
\r
1700 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
\r
1710 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
\r
1711 /*-----------------------------------------------------------*/
\r
1713 static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes )
\r
1715 uint32_t ulChecksum = 0;
\r
1716 uint16_t us, usDataLength16BitWords, *pusNextData;
\r
1718 /* There are half as many 16 bit words than bytes. */
\r
1719 usDataLength16BitWords = ( usDataLengthBytes >> 1U );
\r
1721 pusNextData = ( uint16_t * ) pucNextData;
\r
1723 for( us = 0U; us < usDataLength16BitWords; us++ )
\r
1725 ulChecksum += ( uint32_t ) pusNextData[ us ];
\r
1728 if( ( usDataLengthBytes & 0x01U ) != 0x00 )
\r
1730 /* There is one byte left over. */
\r
1731 #if ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN
\r
1733 ulChecksum += ( uint32_t ) pucNextData[ usDataLengthBytes - 1 ];
\r
1737 us = ( uint16_t ) pucNextData[ usDataLengthBytes - 1 ];
\r
1738 ulChecksum += ( uint32_t ) ( us << 8 );
\r
1743 while( ( ulChecksum >> 16UL ) != 0x00UL )
\r
1745 ulChecksum = ( ulChecksum & 0xffffUL ) + ( ulChecksum >> 16UL );
\r
1748 return ~( ( uint16_t ) ulChecksum );
\r
1750 /*-----------------------------------------------------------*/
\r
1752 static void prvReturnEthernetFrame( xNetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
1754 xEthernetHeader_t *pxEthernetHeader;
\r
1756 pxEthernetHeader = ( xEthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1758 /* Swap source and destination MAC addresses. */
\r
1759 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );
\r
1760 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
1763 xNetworkInterfaceOutput( pxNetworkBuffer );
\r
1765 /*-----------------------------------------------------------*/
\r
1767 static eFrameProcessingResult_t prvProcessARPPacket( xARPPacket_t * const pxARPFrame )
\r
1769 eFrameProcessingResult_t eReturn = eReleaseBuffer;
\r
1770 xARPHeader_t *pxARPHeader;
\r
1772 pxARPHeader = &( pxARPFrame->xARPHeader );
\r
1774 traceARP_PACKET_RECEIVED();
\r
1776 /* Sanity check the protocol type. Don't do anything if the local IP
\r
1777 address is zero because that means a DHCP request has not completed. */
\r
1778 if( ( pxARPHeader->usProtocolType == ipARP_PROTOCOL_TYPE ) && ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )
\r
1780 switch( pxARPHeader->usOperation )
\r
1782 case ipARP_REQUEST :
\r
1783 /* The packet contained an ARP request. Was it for the IP
\r
1784 address of the node running this code? */
\r
1785 if( pxARPHeader->ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
\r
1787 iptraceSENDING_ARP_REPLY( pxARPHeader->ulSenderProtocolAddress );
\r
1789 /* The request is for the address of this node. Add the
\r
1790 entry into the ARP cache, or refresh the entry if it
\r
1791 already exists. */
\r
1792 prvRefreshARPCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), pxARPHeader->ulSenderProtocolAddress );
\r
1794 /* Generate a reply payload in the same buffer. */
\r
1795 pxARPHeader->usOperation = ipARP_REPLY;
\r
1796 memcpy( ( void * ) &( pxARPHeader->xTargetHardwareAddress ), ( void * ) &( pxARPHeader->xSenderHardwareAddress ), sizeof( xMACAddress_t ) );
\r
1797 pxARPHeader->ulTargetProtocolAddress = pxARPHeader->ulSenderProtocolAddress;
\r
1798 memcpy( ( void * ) &( pxARPHeader->xSenderHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( xMACAddress_t ) );
\r
1799 pxARPHeader->ulSenderProtocolAddress = *ipLOCAL_IP_ADDRESS_POINTER;
\r
1801 eReturn = eReturnEthernetFrame;
\r
1805 case ipARP_REPLY :
\r
1806 iptracePROCESSING_RECEIVED_ARP_REPLY( pxARPHeader->ulTargetProtocolAddress );
\r
1807 prvRefreshARPCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), pxARPHeader->ulSenderProtocolAddress );
\r
1818 /*-----------------------------------------------------------*/
\r
1820 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )
\r
1821 uint16_t FreeRTOS_htons( uint16_t usIn )
\r
1823 return ( ( usIn & ( uint16_t ) 0x00ff ) << ( uint16_t ) 8U ) |
\r
1824 ( ( usIn & ( uint16_t ) 0xff00 ) >> ( uint16_t ) 8U );
\r
1826 #endif /* ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN */
\r
1827 /*-----------------------------------------------------------*/
\r
1829 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )
\r
1830 uint32_t FreeRTOS_htonl( uint32_t ulIn )
\r
1832 return ( ( ulIn & 0x000000ffUL ) << 24UL ) |
\r
1833 ( ( ulIn & 0x0000ff00UL ) << 8UL ) |
\r
1834 ( ( ulIn & 0x00ff0000UL ) >> 8UL ) |
\r
1835 ( ( ulIn & 0xff000000UL ) >> 24UL );
\r
1837 #endif /* ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN */
\r
1839 /*-----------------------------------------------------------*/
\r