]> begriffs open source - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-UDP/FreeRTOS_UDP_IP.c
Add a configASSERT() that checks the gateway address is on the same subnet as the...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-UDP / FreeRTOS_UDP_IP.c
1 /*\r
2  * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.\r
3  *\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
6  *\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
13  *\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
20  *\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
27  *\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
34  *\r
35  * 1 tab == 4 spaces!\r
36  *\r
37  * http://www.FreeRTOS.org\r
38  * http://www.FreeRTOS.org/udp\r
39  *\r
40  */\r
41 \r
42 /* Standard includes. */\r
43 #include <stdint.h>\r
44 \r
45 /* FreeRTOS includes. */\r
46 #include "FreeRTOS.h"\r
47 #include "task.h"\r
48 #include "queue.h"\r
49 #include "semphr.h"\r
50 #include "timers.h"\r
51 \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
59 \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
63 #endif\r
64 \r
65 #if configTICK_RATE_HZ > 1000\r
66         #error configTICK_RATE_HZ must be less than 1000 to use FreeRTOS+UDP\r
67 #endif\r
68 \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
71 #endif\r
72 \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
75 #endif\r
76 \r
77 #if ( ipconfigNETWORK_MTU < 46 )\r
78         #error ipconfigNETWORK_MTU must be at least 46.\r
79 #endif\r
80 /*-----------------------------------------------------------*/\r
81 \r
82 /* The IP header length in bytes. */\r
83 #define ipIP_HEADER_LENGTH              ( 20 )\r
84 \r
85 /* IP protocol definitions. */\r
86 #define ipPROTOCOL_ICMP                 ( 1 )\r
87 #define ipPROTOCOL_UDP                  ( 17 )\r
88 \r
89 /* ICMP protocol definitions. */\r
90 #define ipICMP_ECHO_REQUEST             ( ( uint16_t ) 8 )\r
91 #define ipICMP_ECHO_REPLY               ( ( uint16_t ) 0 )\r
92 \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
95 \r
96 /* Time delay between repeated attempts to initialise the network hardware. */\r
97 #define ipINITIALISATION_RETRY_DELAY    ( ( ( portTickType ) 3000 ) / portTICK_RATE_MS )\r
98 \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
102 \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
106 \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
109 #ifdef _WINDOWS_\r
110         #define ipARP_TIMER_PERIOD_MS   ( 500 ) /* For windows simulator builds. */\r
111 #else\r
112         #define ipARP_TIMER_PERIOD_MS   ( 10000 )\r
113 #endif\r
114 \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
124 #else\r
125         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer\r
126 #endif\r
127 \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
132 \r
133 /* Number of bits to shift to divide by 8.  Used to remove the need for a\r
134 divide. */\r
135 #define ipSHIFT_TO_DIVIDE_BY_8                                          ( 3U )\r
136 \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
140 \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
144 \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
148 \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
151 #else\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
157 \r
158 /*-----------------------------------------------------------*/\r
159 /* Miscellaneous structure and definitions. */\r
160 /*-----------------------------------------------------------*/\r
161 \r
162 typedef struct xARP_CACHE_TABLE_ROW\r
163 {\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
167 } xARPCacheRow_t;\r
168 \r
169 typedef enum\r
170 {\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
175 \r
176 typedef enum\r
177 {\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
182 \r
183 \r
184 /*-----------------------------------------------------------*/\r
185 \r
186 /*\r
187  * Called when new data is available from the network interface.\r
188  */\r
189 static void prvProcessEthernetPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );\r
190 \r
191 /*\r
192  * Called when the application has generated a UDP packet to send.\r
193  */\r
194 static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );\r
195 \r
196 /*\r
197  * Processes incoming ARP packets.\r
198  */\r
199 static eFrameProcessingResult_t prvProcessARPPacket( xARPPacket_t * const pxARPFrame );\r
200 \r
201 /*\r
202  * Process incoming IP packets.\r
203  */\r
204 static eFrameProcessingResult_t prvProcessIPPacket( const xIPPacket_t * const pxIPPacket, xNetworkBufferDescriptor_t * const pxNetworkBuffer );\r
205 \r
206 /*\r
207  * Process incoming ICMP packets.\r
208  */\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
212 \r
213 /*\r
214  * Swap the source and destination addresses in an already constructed Ethernet\r
215  * frame, and send the frame to the network.\r
216  */\r
217 static void prvReturnEthernetFrame( xNetworkBufferDescriptor_t * const pxNetworkBuffer );\r
218 \r
219 /*\r
220  * Return the checksum generated over usDataLengthBytes from pucNextData.\r
221  */\r
222 static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes );\r
223 \r
224 /*\r
225  * The callback function that is assigned to all periodic processing timers -\r
226  * namely the DHCP timer and the ARP timer.\r
227  */\r
228 void vIPFunctionsTimerCallback( xTimerHandle xTimer );\r
229 \r
230 /*\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
233  */\r
234 static void prvAgeARPCache( void );\r
235 \r
236 /*\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
241  */\r
242 static void prvRefreshARPCacheEntry( const xMACAddress_t * const pxMACAddress, const uint32_t ulIPAddress );\r
243 \r
244 /*\r
245  * Creates the pseudo header necessary then generate the checksum over the UDP\r
246  * packet.  Returns the calculated checksum.\r
247  */\r
248 static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket );\r
249 \r
250 /*\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
257  */\r
258 static eARPLookupResult_t prvGetARPCacheEntry( uint32_t *pulIPAddress, xMACAddress_t * const pxMACAddress );\r
259 \r
260 /*\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
264  */\r
265 static void prvIPTask( void *pvParameters );\r
266 \r
267 /*\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
271  */\r
272 static void prvGenerateARPRequestPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer );\r
273 \r
274 /*\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
278  */\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
282 \r
283 /*\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
287  */\r
288 static void prvCompleteUDPHeader( xNetworkBufferDescriptor_t *pxNetworkBuffer, xUDPPacket_t *pxUDPPacket, uint8_t ucSocketOptions );\r
289 \r
290 /*\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
293  * pdFALSE.\r
294 */\r
295 static portBASE_TYPE prvSendEventToIPTask( eIPEvent_t eEvent );\r
296 \r
297 /*\r
298  * Generate and send an ARP request for the IP address passed in ulIPAddress.\r
299  */\r
300 static void prvOutputARPRequest( uint32_t ulIPAddress );\r
301 \r
302 /*\r
303  * Turns around an incoming ping request to convert it into a ping reply.\r
304  */\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
308 \r
309 /*\r
310  * Processes incoming ping replies.  The application callback function\r
311  * vApplicationPingReplyHook() is called with the results.\r
312  */\r
313 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
314         static void prvProcessICMPEchoReply( xICMPPacket_t * const pxICMPPacket );\r
315 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
316 \r
317 /*\r
318  * Called to create a network connection when the stack is first started, or\r
319  * when the network connection is lost.\r
320  */\r
321 static void prvProcessNetworkDownEvent( void );\r
322 \r
323 /*-----------------------------------------------------------*/\r
324 \r
325 /* The queue used to pass events into the UDP task for processing. */\r
326 xQueueHandle xNetworkEventQueue = NULL;\r
327 \r
328 /* The ARP cache. */\r
329 static xARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];\r
330 \r
331 /* The timer that triggers ARP events. */\r
332 static xTimerHandle xARPTimer = NULL;\r
333 \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
336 full. */\r
337 static portBASE_TYPE xNetworkDownEventPending = pdFALSE;\r
338 \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
343 \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
348 {\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
360 };\r
361 \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
366 {\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
378 };\r
379 \r
380 /* Structure that stores the netmask, gateway address and DNS server addresses. */\r
381 static xNetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0 };\r
382 \r
383 /*-----------------------------------------------------------*/\r
384 \r
385 static void prvIPTask( void *pvParameters )\r
386 {\r
387 xIPStackEvent_t xReceivedEvent;\r
388 \r
389         /* Just to prevent compiler warnings about unused parameters. */\r
390         ( void ) pvParameters;\r
391 \r
392         /* Create the ARP timer, but don't start it until the network has\r
393         connected. */\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
396 \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
402 \r
403         /* Loop, processing IP events. */\r
404         for( ;; )\r
405         {\r
406                 /* Wait until there is something to do. */\r
407                 if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, portMAX_DELAY ) == pdPASS )\r
408                 {\r
409                         iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );\r
410 \r
411                         switch( xReceivedEvent.eEventType )\r
412                         {\r
413                                 case eNetworkDownEvent :\r
414                                         /* Attempt to establish a connection. */\r
415                                         prvProcessNetworkDownEvent();\r
416                                         break;\r
417 \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
423                                         break;\r
424 \r
425                                 case eARPTimerEvent :\r
426                                         /* The ARP timer has expired, process the ARP cache. */\r
427                                         prvAgeARPCache();\r
428                                         break;\r
429 \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
435                                         break;\r
436 \r
437                                 case eDHCPEvent:\r
438                                         /* The DHCP state machine needs processing. */\r
439                                         #if ipconfigUSE_DHCP == 1\r
440                                         {\r
441                                                 vDHCPProcess( pdFALSE, ( xMACAddress_t * ) ipLOCAL_MAC_ADDRESS, ipLOCAL_IP_ADDRESS_POINTER, &xNetworkAddressing );\r
442                                         }\r
443                                         #endif\r
444                                         break;\r
445 \r
446                                 default :\r
447                                         /* Should not get here. */\r
448                                         break;\r
449                         }\r
450 \r
451                         if( xNetworkDownEventPending != pdFALSE )\r
452                         {\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
456                         }\r
457                 }\r
458         }\r
459 }\r
460 /*-----------------------------------------------------------*/\r
461 \r
462 void FreeRTOS_NetworkDown( void )\r
463 {\r
464 static const xIPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };\r
465 const portTickType xDontBlock = 0;\r
466 \r
467         /* Simply send the network task the appropriate event. */\r
468         if( xQueueSendToBack( xNetworkEventQueue, &xNetworkDownEvent, xDontBlock ) != pdPASS )\r
469         {\r
470                 xNetworkDownEventPending = pdTRUE;\r
471         }\r
472         else\r
473         {\r
474                 xNetworkDownEventPending = pdFALSE;\r
475         }\r
476 \r
477         iptraceNETWORK_DOWN();\r
478 }\r
479 /*-----------------------------------------------------------*/\r
480 \r
481 portBASE_TYPE FreeRTOS_NetworkDownFromISR( void )\r
482 {\r
483 static const xIPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };\r
484 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
485 \r
486         /* Simply send the network task the appropriate event. */\r
487         if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )\r
488         {\r
489                 xNetworkDownEventPending = pdTRUE;\r
490         }\r
491         else\r
492         {\r
493                 xNetworkDownEventPending = pdFALSE;\r
494         }\r
495         iptraceNETWORK_DOWN();\r
496 \r
497         return xHigherPriorityTaskWoken;\r
498 }\r
499 /*-----------------------------------------------------------*/\r
500 \r
501 void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, portTickType xBlockTimeTicks )\r
502 {\r
503 xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
504 void *pvReturn;\r
505 \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
510         {\r
511                 xBlockTimeTicks = ipconfigMAX_SEND_BLOCK_TIME_TICKS;\r
512         }\r
513 \r
514         /* Obtain a network buffer with the required amount of storage. */\r
515         pxNetworkBuffer = pxNetworkBufferGet( sizeof( xUDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );\r
516 \r
517         if( pxNetworkBuffer != NULL )\r
518         {\r
519                 /* Leave space for the UPD header. */\r
520                 pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET ] );\r
521         }\r
522         else\r
523         {\r
524                 pvReturn = NULL;\r
525         }\r
526 \r
527         return ( void * ) pvReturn;\r
528 }\r
529 /*-----------------------------------------------------------*/\r
530 \r
531 void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )\r
532 {\r
533 uint8_t *pucBuffer;\r
534 \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
538 \r
539         vNetworkBufferRelease( * ( ( xNetworkBufferDescriptor_t ** ) pucBuffer ) );\r
540 }\r
541 /*-----------------------------------------------------------*/\r
542 \r
543 uint8_t * FreeRTOS_GetMACAddress( void )\r
544 {\r
545         return ipLOCAL_MAC_ADDRESS;\r
546 }\r
547 /*-----------------------------------------------------------*/\r
548 \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
550 {\r
551 static portBASE_TYPE xReturn = pdFALSE;\r
552 \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
556         {\r
557                 xNetworkEventQueue = xQueueCreate( ipconfigEVENT_QUEUE_LENGTH, sizeof( xIPStackEvent_t ) );\r
558                 configASSERT( xNetworkEventQueue );\r
559                 vQueueAddToRegistry( xNetworkEventQueue, ( signed char * ) "NetEvnt" );\r
560         }\r
561 \r
562         if( xNetworkBuffersInitialise() == pdPASS )\r
563         {\r
564                 if( xNetworkEventQueue != NULL )\r
565                 {\r
566                         /* xReturn is static to ensure the network interface is not\r
567                         initialised     twice. */\r
568                         if( xReturn == pdFALSE )\r
569                         {\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
575 \r
576                                 #if ipconfigUSE_DHCP == 1\r
577                                 {\r
578                                         /* The IP address is not set until DHCP completes. */\r
579                                         *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;\r
580                                 }\r
581                                 #else\r
582                                 {\r
583                                         *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;\r
584                                         \r
585                                         /* Ensure the gateway is on the same subnet as the IP \r
586                                         address. */\r
587                                         configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );\r
588                                 }\r
589                                 #endif /* ipconfigUSE_DHCP == 1 */\r
590 \r
591                                 /* The MAC address is stored in the start of the default packet\r
592                                 header fragment, which is used when sending UDP packets. */\r
593                                 memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
594 \r
595                                 /* Prepare the sockets interface. */\r
596                                 FreeRTOS_SocketsInit();\r
597 \r
598                                 /* Create the task that processes Ethernet and stack events. */\r
599                                 xReturn = xTaskCreate( prvIPTask, ( const signed char * const ) "UDP/IP", ipconfigUDP_TASK_STACK_SIZE_WORDS, NULL, ipconfigUDP_TASK_PRIORITY, NULL );\r
600                         }\r
601                 }\r
602         }\r
603 \r
604         return xReturn;\r
605 }\r
606 /*-----------------------------------------------------------*/\r
607 \r
608 void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )\r
609 {\r
610         if( pulIPAddress != NULL )\r
611         {\r
612                 *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
613         }\r
614 \r
615         if( pulNetMask != NULL )\r
616         {\r
617                 *pulNetMask = xNetworkAddressing.ulNetMask;\r
618         }\r
619 \r
620         if( pulGatewayAddress != NULL )\r
621         {\r
622                 *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;\r
623         }\r
624 \r
625         if( pulDNSServerAddress != NULL )\r
626         {\r
627                 *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;\r
628         }\r
629 }\r
630 /*-----------------------------------------------------------*/\r
631 \r
632 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
633 \r
634         portBASE_TYPE FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, portTickType xBlockTimeTicks )\r
635         {\r
636         xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
637         xICMPHeader_t *pxICMPHeader;\r
638         portBASE_TYPE xReturn = pdFAIL;\r
639         static uint16_t usSequenceNumber = 0;\r
640         uint8_t *pucChar;\r
641         xIPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };\r
642 \r
643                 if( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( xIPHeader_t ) ) - sizeof( xICMPHeader_t ) ) )\r
644                 {\r
645                         pxNetworkBuffer = pxNetworkBufferGet( xNumberOfBytesToSend + sizeof( xICMPPacket_t ), xBlockTimeTicks );\r
646 \r
647                         if( pxNetworkBuffer != NULL )\r
648                         {\r
649                                 pxICMPHeader = ( xICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] );\r
650                                 usSequenceNumber++;\r
651 \r
652                                 /* Fill in the basic header information. */\r
653                                 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;\r
654                                 pxICMPHeader->ucTypeOfService = 0;\r
655                                 pxICMPHeader->usIdentifier = usSequenceNumber;\r
656                                 pxICMPHeader->usSequenceNumber = usSequenceNumber;\r
657                                 pxICMPHeader->usChecksum = 0;\r
658 \r
659                                 /* Find the start of the data. */\r
660                                 pucChar = ( uint8_t * ) pxICMPHeader;\r
661                                 pucChar += sizeof( xICMPHeader_t );\r
662 \r
663                                 /* Just memset the data to a fixed value. */\r
664                                 memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );\r
665 \r
666                                 /* The message is complete, calculate the checksum. */\r
667                                 pxICMPHeader->usChecksum = prvGenerateChecksum( ( uint8_t * ) pxICMPHeader, ( uint16_t ) ( xNumberOfBytesToSend + sizeof( xICMPHeader_t ) ) );\r
668 \r
669                                 /* Complete the network buffer information. */\r
670                                 pxNetworkBuffer->ulIPAddress = ulIPAddress;\r
671                                 pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;\r
672                                 pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( xICMPHeader_t );\r
673 \r
674                                 /* Send to the stack. */\r
675                                 xStackTxEvent.pvData = pxNetworkBuffer;\r
676                                 if( xQueueSendToBack( xNetworkEventQueue, &xStackTxEvent, xBlockTimeTicks ) != pdPASS )\r
677                                 {\r
678                                         vNetworkBufferRelease( pxNetworkBuffer );\r
679                                         iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );\r
680                                 }\r
681                                 else\r
682                                 {\r
683                                         xReturn = usSequenceNumber;\r
684                                 }\r
685                         }\r
686                 }\r
687                 else\r
688                 {\r
689                         /* The requested number of bytes will not fit in the available space\r
690                         in the network buffer.  Outgoing fragmentation is only supported for\r
691                         UDP packets. */\r
692                 }\r
693 \r
694                 return xReturn;\r
695         }\r
696 \r
697 #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */\r
698 \r
699 /*-----------------------------------------------------------*/\r
700 \r
701 static portBASE_TYPE prvSendEventToIPTask( eIPEvent_t eEvent )\r
702 {\r
703 xIPStackEvent_t xEventMessage;\r
704 const portTickType xDontBlock = 0;\r
705 portBASE_TYPE xReturn;\r
706 \r
707         xEventMessage.eEventType = eEvent;\r
708         xReturn = xQueueSendToBack( xNetworkEventQueue, &xEventMessage, xDontBlock );\r
709 \r
710         if( xReturn != pdPASS )\r
711         {\r
712                 iptraceSTACK_TX_EVENT_LOST( ipARP_TIMER_EVENT );\r
713         }\r
714 \r
715         return xReturn;\r
716 }\r
717 /*-----------------------------------------------------------*/\r
718 \r
719 void vIPFunctionsTimerCallback( xTimerHandle xTimer )\r
720 {\r
721 eIPEvent_t eMessage;\r
722 \r
723         /* This time can be used to send more than one type of message to the IP\r
724         task.  The message ID is stored in the ID of the timer.  The strange\r
725         casting is to avoid compiler warnings. */\r
726         eMessage = ( eIPEvent_t ) ( ( int ) pvTimerGetTimerID( xTimer ) );\r
727 \r
728         prvSendEventToIPTask( eMessage );\r
729 }\r
730 /*-----------------------------------------------------------*/\r
731 \r
732 static void prvOutputARPRequest( uint32_t ulIPAddress )\r
733 {\r
734 xNetworkBufferDescriptor_t *pxNetworkBuffer;\r
735 \r
736         /* This is called from the context of the IP event task, so a block time\r
737         must not be used. */\r
738         pxNetworkBuffer = pxNetworkBufferGet( sizeof( xARPPacket_t ), 0 );\r
739         if( pxNetworkBuffer != NULL )\r
740         {\r
741                 pxNetworkBuffer->ulIPAddress = ulIPAddress;\r
742                 prvGenerateARPRequestPacket( pxNetworkBuffer );\r
743                 xNetworkInterfaceOutput( pxNetworkBuffer );\r
744         }\r
745 }\r
746 /*-----------------------------------------------------------*/\r
747 \r
748 static void prvAgeARPCache( void )\r
749 {\r
750 portBASE_TYPE x;\r
751 \r
752         /* Loop through each entry in the ARP cache. */\r
753         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
754         {\r
755                 /* If the entry is valid (its age is greater than zero). */\r
756                 if( xARPCache[ x ].ucAge > 0U )\r
757                 {\r
758                         /* Decrement the age value of the entry in this ARP cache table row.\r
759                         When the age reaches zero it is no longer considered valid. */\r
760                         ( xARPCache[ x ].ucAge )--;\r
761 \r
762                         /* If the entry has a MAC address of 0, then it is waiting an ARP\r
763                         reply, and the ARP request should be retransmitted. */\r
764                         if( memcmp( ( void * ) &xNullMACAddress, ( void * ) &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) ) == 0 )\r
765                         {\r
766                                 prvOutputARPRequest( xARPCache[ x ].ulIPAddress );\r
767                         }\r
768                         else if( xARPCache[ x ].ucAge <= ipMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )\r
769                         {\r
770                                 /* This entry will get removed soon.  See if the MAC address is\r
771                                 still valid to prevent this happening. */\r
772                                 iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );\r
773                                 prvOutputARPRequest( xARPCache[ x ].ulIPAddress );\r
774                         }\r
775                         else\r
776                         {\r
777                                 /* The age has just ticked down, with nothing to do. */\r
778                         }\r
779 \r
780                         if( xARPCache[ x ].ucAge == 0 )\r
781                         {\r
782                                 /* The entry is no longer valid.  Wipe it out. */\r
783                                 iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );\r
784                                 xARPCache[ x ].ulIPAddress = 0UL;\r
785                         }\r
786                 }\r
787         }\r
788 }\r
789 /*-----------------------------------------------------------*/\r
790 \r
791 static eARPLookupResult_t prvGetARPCacheEntry( uint32_t *pulIPAddress, xMACAddress_t * const pxMACAddress )\r
792 {\r
793 portBASE_TYPE x;\r
794 eARPLookupResult_t eReturn;\r
795 uint32_t ulAddressToLookup;\r
796 \r
797         if( *pulIPAddress == ipBROADCAST_IP_ADDRESS )\r
798         {\r
799                 /* This is a broadcast so uses the broadcast MAC address. */\r
800                 memcpy( ( void * ) pxMACAddress, &xBroadcastMACAddress, sizeof( xMACAddress_t ) );\r
801                 eReturn = eARPCacheHit;\r
802         }\r
803         else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )\r
804         {\r
805                 /* The IP address has not yet been assigned, so there is nothing that\r
806                 can be done. */\r
807                 eReturn = eCantSendPacket;\r
808         }\r
809         else\r
810         {\r
811                 if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )\r
812                 {\r
813                         /* The IP address is off the local network, so look up the hardware\r
814                         address of the router, if any. */\r
815                         ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;\r
816                 }\r
817                 else\r
818                 {\r
819                         /* The IP address is on the local network, so lookup the requested\r
820                         IP address directly. */\r
821                         ulAddressToLookup = *pulIPAddress;\r
822                 }\r
823 \r
824                 if( ulAddressToLookup == 0UL )\r
825                 {\r
826                         /* The address is not on the local network, and there is not a\r
827                         router. */\r
828                         eReturn = eCantSendPacket;\r
829                 }\r
830                 else\r
831                 {\r
832                         eReturn = eARPCacheMiss;\r
833 \r
834                         /* Loop through each entry in the ARP cache. */\r
835                         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
836                         {\r
837                                 /* Does this row in the ARP cache table hold an entry for the IP\r
838                                 address being queried? */\r
839                                 if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )\r
840                                 {\r
841                                         /* The IP address matched.  Is there a valid MAC address? */\r
842                                         if( memcmp( ( void * ) &xNullMACAddress, ( void * ) &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) ) == 0 )\r
843                                         {\r
844                                                 /* This entry is waiting an ARP reply, so is not valid. */\r
845                                                 eReturn = eCantSendPacket;\r
846                                         }\r
847                                         else\r
848                                         {\r
849                                                 /* A valid entry was found. */\r
850                                                 memcpy( pxMACAddress, &( xARPCache[ x ].xMACAddress ), sizeof( xMACAddress_t ) );\r
851                                                 eReturn = eARPCacheHit;\r
852                                         }\r
853                                 }\r
854 \r
855                                 if( eReturn != eARPCacheMiss )\r
856                                 {\r
857                                         break;\r
858                                 }\r
859                         }\r
860 \r
861                         if( eReturn == eARPCacheMiss )\r
862                         {\r
863                                 /* It might be that the ARP has to go to the gateway. */\r
864                                 *pulIPAddress = ulAddressToLookup;\r
865                         }\r
866                 }\r
867         }\r
868 \r
869         return eReturn;\r
870 }\r
871 /*-----------------------------------------------------------*/\r
872 \r
873 static void prvRefreshARPCacheEntry( const xMACAddress_t * const pxMACAddress, const uint32_t ulIPAddress )\r
874 {\r
875 portBASE_TYPE x, xEntryFound = pdFALSE, xOldestEntry = 0;\r
876 uint8_t ucMinAgeFound = 0U;\r
877 \r
878         /* Only process the IP address if it is on the local network. */\r
879         if( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )\r
880         {\r
881                 /* Start with the maximum possible number. */\r
882                 ucMinAgeFound--;\r
883 \r
884                 /* For each entry in the ARP cache table. */\r
885                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
886                 {\r
887                         /* Does this line in the cache table hold an entry for the IP\r
888                         address being queried? */\r
889                         if( xARPCache[ x ].ulIPAddress == ulIPAddress )\r
890                         {\r
891                                 /* If the MAC address is all zeros then the refresh is due to\r
892                                 an ARP reply, so in effect this is a new entry in the ARP\r
893                                 cache. */\r
894                                 if( memcmp( &( xARPCache[ x ].xMACAddress ), &xNullMACAddress, sizeof( xMACAddress_t ) ) == 0 )\r
895                                 {\r
896                                         iptraceARP_TABLE_ENTRY_CREATED( xARPCache[ x ].ulIPAddress, *pxMACAddress );\r
897                                 }\r
898 \r
899                                 /* Refresh the cache entry so the entry's age is back to its\r
900                                 maximum value. */\r
901                                 xARPCache[ x ].ucAge = ipconfigMAX_ARP_AGE;\r
902                                 memcpy( &( xARPCache[ x ].xMACAddress ), pxMACAddress, sizeof( xMACAddress_t ) );\r
903                                 xEntryFound = pdTRUE;\r
904                                 break;\r
905                         }\r
906                         else\r
907                         {\r
908                                 /* As the table is traversed, remember the table row that\r
909                                 contains the oldest entry (the lowest age count, as ages are\r
910                                 decremented to zero) so the row can be re-used if this function\r
911                                 needs to add an entry that does not already exist. */\r
912                                 if( xARPCache[ x ].ucAge < ucMinAgeFound )\r
913                                 {\r
914                                         ucMinAgeFound = xARPCache[ x ].ucAge;\r
915                                         xOldestEntry = x;\r
916                                 }\r
917                         }\r
918                 }\r
919 \r
920                 if( xEntryFound == pdFALSE )\r
921                 {\r
922                         /* The wanted entry does not already exist.  Add the entry into the\r
923                         cache, replacing the oldest entry (which might be an empty entry). */\r
924                         xARPCache[ xOldestEntry ].ulIPAddress = ulIPAddress;\r
925                         memcpy( &( xARPCache[ xOldestEntry ].xMACAddress ), pxMACAddress, sizeof( xMACAddress_t ) );\r
926 \r
927                         /* If the MAC address is all zeros, then this entry is not yet\r
928                         complete but still waiting the reply from an ARP request.  When this\r
929                         is the case     the age is set to a much lower value as an ARP\r
930                         retransmission will be generated each time the ARP timer is called\r
931                         while the reply is still outstanding. */\r
932                         if( pxMACAddress == &xNullMACAddress )\r
933                         {\r
934                                 xARPCache[ xOldestEntry ].ucAge = ipconfigMAX_ARP_RETRANSMISSIONS;\r
935                         }\r
936                         else\r
937                         {\r
938                                 iptraceARP_TABLE_ENTRY_CREATED( xARPCache[ xOldestEntry ].ulIPAddress, xARPCache[ xOldestEntry ].xMACAddress );\r
939                                 xARPCache[ xOldestEntry ].ucAge = ipconfigMAX_ARP_AGE;\r
940                         }\r
941                 }\r
942         }\r
943 }\r
944 /*-----------------------------------------------------------*/\r
945 \r
946 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1\r
947 \r
948         static void prvCalculateFragmentOffsetAndLength( xIPFragmentParameters_t *pxFragmentParameters, uint16_t *pusFragmentOffset, uint16_t *pusFragmentLength )\r
949         {\r
950                 *pusFragmentOffset = pxFragmentParameters->usFragmentedPacketOffset;\r
951 \r
952                 if( *pusFragmentOffset != 0 )\r
953                 {\r
954                         /* Take into account that the payload has had a UDP header added in the\r
955                         first fragment of the set. */\r
956                         *pusFragmentOffset += sizeof( xUDPHeader_t );\r
957                 }\r
958 \r
959                 /* The offset is defined in multiples of 8 bytes. */\r
960                 *pusFragmentOffset >>= ipSHIFT_TO_DIVIDE_BY_8;\r
961                 *pusFragmentLength = pxFragmentParameters->usFragmentLength;\r
962 \r
963                 if( ( pxFragmentParameters->ucSocketOptions & FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET ) != 0 )\r
964                 {\r
965                         /* Set the more fragments flag. */\r
966                         *pusFragmentOffset |= ipMORE_FRAGMENTS_FLAG_BIT;\r
967                 }\r
968         }\r
969 \r
970 #endif\r
971 /*-----------------------------------------------------------*/\r
972 \r
973 static void prvCompleteUDPHeader( xNetworkBufferDescriptor_t *pxNetworkBuffer, xUDPPacket_t *pxUDPPacket, uint8_t ucSocketOptions )\r
974 {\r
975 xUDPHeader_t *pxUDPHeader;\r
976 \r
977         pxUDPHeader = &( pxUDPPacket->xUDPHeader );\r
978 \r
979         pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;\r
980         pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;\r
981         pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xUDPHeader_t ) );\r
982         pxUDPHeader->usLength = FreeRTOS_htons( pxUDPPacket->xUDPHeader.usLength );\r
983         pxUDPHeader->usChecksum = 0;\r
984 \r
985         if( ( ucSocketOptions & FREERTOS_SO_UDPCKSUM_OUT ) != 0U )\r
986         {\r
987                 pxUDPHeader->usChecksum = prvGenerateUDPChecksum( pxUDPPacket );\r
988                 if( pxUDPHeader->usChecksum == 0x00 )\r
989                 {\r
990                         /* A calculated checksum of 0 must be inverted as 0 means the\r
991                         checksum is disabled. */\r
992                         pxUDPHeader->usChecksum = 0xffffU;\r
993                 }\r
994         }\r
995 }\r
996 /*-----------------------------------------------------------*/\r
997 \r
998 #if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1\r
999 \r
1000         static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1001         {\r
1002         xUDPPacket_t *pxUDPPacket;\r
1003         xUDPHeader_t *pxUDPHeader;\r
1004         xIPHeader_t *pxIPHeader;\r
1005         eARPLookupResult_t eReturned;\r
1006         eIPFragmentStatus_t eFragmentStatus;\r
1007         uint16_t usFragmentOffset = 0, usFragmentLength;\r
1008         xIPFragmentParameters_t *pxFragmentParameters;\r
1009         static uint16_t usPacketIdentifier = 0U;\r
1010 \r
1011                 /* Map the UDP packet onto the start of the frame. */\r
1012                 pxUDPPacket = ( xUDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
1013 \r
1014                 /* Determine the ARP cache status for the requested IP address. */\r
1015                 eReturned = prvGetARPCacheEntry( &( pxNetworkBuffer->ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );\r
1016 \r
1017                 if( eReturned != eCantSendPacket )\r
1018                 {\r
1019                         if( eReturned == eARPCacheHit )\r
1020                         {\r
1021                                 iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );\r
1022 \r
1023                                 /* Create short cuts to the data within the packet. */\r
1024                                 pxUDPHeader = &( pxUDPPacket->xUDPHeader );\r
1025                                 pxIPHeader = &( pxUDPPacket->xIPHeader );\r
1026                                 pxFragmentParameters = ( xIPFragmentParameters_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipFRAGMENTATION_PARAMETERS_OFFSET ] );\r
1027 \r
1028                                 /* IP header source and destination addresses must be set\r
1029                                 before the UDP checksum is calculated. */\r
1030                                 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;\r
1031                                 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1032 \r
1033                                 /* If the packet is not fragmented, or if the packet is the\r
1034                                 first in a fragmented packet, then a UDP header is required. */\r
1035                                 if( ( pxFragmentParameters->ucSocketOptions & FREERTOS_FRAGMENTED_PACKET ) == 0 )\r
1036                                 {\r
1037                                         eFragmentStatus = eNotFragment;\r
1038 \r
1039                                         #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1040                                         {\r
1041                                                 /* Is it possible that the packet is not actually a UDP\r
1042                                                 packet after all, but an ICMP packet. */\r
1043                                                 if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )\r
1044                                                 {\r
1045                                                         prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );\r
1046                                                 }\r
1047                                         }\r
1048                                         #else /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1049                                         {\r
1050                                                 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );\r
1051                                         }\r
1052                                         #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1053 \r
1054 \r
1055                                         usFragmentLength = 0U;\r
1056 \r
1057                                         /* The identifier is incremented as this is a new and\r
1058                                         unfragmented IP packet. */\r
1059                                         usPacketIdentifier++;\r
1060                                 }\r
1061                                 else if( pxFragmentParameters->usFragmentedPacketOffset == 0 )\r
1062                                 {\r
1063                                         eFragmentStatus = eFirstFragment;\r
1064                                         prvCalculateFragmentOffsetAndLength( pxFragmentParameters, &usFragmentOffset, &usFragmentLength );\r
1065                                         /* Note FREERTOS_SO_UDPCKSUM_OUT is used because checksums\r
1066                                         cannot currently be used on fragmented packets. */\r
1067                                         pxFragmentParameters->ucSocketOptions &= ~FREERTOS_SO_UDPCKSUM_OUT;\r
1068                                         prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxFragmentParameters->ucSocketOptions );\r
1069 \r
1070                                         /* The identifier is incremented because, although this is a\r
1071                                         fragmented packet, it is the first in the fragmentation\r
1072                                         set. */\r
1073                                         usPacketIdentifier++;\r
1074                                 }\r
1075                                 else\r
1076                                 {\r
1077                                         eFragmentStatus = eFollowingFragment;\r
1078                                         prvCalculateFragmentOffsetAndLength( pxFragmentParameters, &usFragmentOffset, &usFragmentLength );\r
1079                                 }\r
1080 \r
1081                                 /* memcpy() the constant parts of the header information into the\r
1082                                 correct location within the packet.  This fills in:\r
1083                                         xEthernetHeader.xSourceAddress\r
1084                                         xEthernetHeader.usFrameType\r
1085                                         xIPHeader.ucVersionHeaderLength\r
1086                                         xIPHeader.ucDifferentiatedServicesCode\r
1087                                         xIPHeader.usLength\r
1088                                         xIPHeader.usIdentification\r
1089                                         xIPHeader.usFragmentOffset\r
1090                                         xIPHeader.ucTimeToLive\r
1091                                         xIPHeader.ucProtocol\r
1092                                 and\r
1093                                         xIPHeader.usHeaderChecksum\r
1094                                 */\r
1095                                 memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xDefaultPartUDPPacketHeader ) );\r
1096 \r
1097                                 /* The fragment status is used to complete the length and\r
1098                                 fragment offset fields. */\r
1099                                 if( eFragmentStatus == eNotFragment )\r
1100                                 {\r
1101                                         pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );\r
1102                                 }\r
1103                                 else if( eFragmentStatus == eFirstFragment )\r
1104                                 {\r
1105                                         pxIPHeader->usFragmentOffset = FreeRTOS_htons( usFragmentOffset );\r
1106                                         pxIPHeader->usLength = ( uint16_t ) ( usFragmentLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );\r
1107                                 }\r
1108                                 else\r
1109                                 {\r
1110                                         pxIPHeader->usFragmentOffset = FreeRTOS_htons( usFragmentOffset );\r
1111                                         pxIPHeader->usLength = ( uint16_t ) ( usFragmentLength + sizeof( xIPHeader_t ) );\r
1112                                 }\r
1113 \r
1114                                 /* The total transmit size adds on the Ethernet header. */\r
1115                                 pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( xEthernetHeader_t );\r
1116                                 pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );\r
1117                                 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;\r
1118                                 pxIPHeader->usIdentification = usPacketIdentifier;\r
1119                                 pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH );\r
1120                         }\r
1121                         else if ( eReturned == eARPCacheMiss )\r
1122                         {\r
1123                                 /* Send an ARP for the required IP address. */\r
1124                                 iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );\r
1125                                 prvGenerateARPRequestPacket( pxNetworkBuffer );\r
1126 \r
1127                                 /* Add an entry to the ARP table with a null hardware address.\r
1128                                 This allows the ARP timer to know that an ARP reply is\r
1129                                 outstanding, and perform retransmissions if necessary. */\r
1130                                 prvRefreshARPCacheEntry( &xNullMACAddress, pxNetworkBuffer->ulIPAddress );\r
1131                         }\r
1132                         else\r
1133                         {\r
1134                                 /* The lookup indicated that an ARP request has already been\r
1135                                 sent out for the queried IP address. */\r
1136                                 eReturned = eCantSendPacket;\r
1137                         }\r
1138                 }\r
1139 \r
1140                 if( eReturned != eCantSendPacket )\r
1141                 {\r
1142                         /* The network driver is responsible for freeing the network buffer\r
1143                         after the packet has been sent. */\r
1144                         xNetworkInterfaceOutput( pxNetworkBuffer );\r
1145                 }\r
1146                 else\r
1147                 {\r
1148                         /* The packet can't be sent (DHCP not completed?).  Just drop the\r
1149                         packet. */\r
1150                         vNetworkBufferRelease( pxNetworkBuffer );\r
1151                 }\r
1152         }\r
1153 \r
1154 #else /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 */\r
1155 \r
1156         static void prvProcessGeneratedPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1157         {\r
1158         xUDPPacket_t *pxUDPPacket;\r
1159         xIPHeader_t *pxIPHeader;\r
1160         eARPLookupResult_t eReturned;\r
1161 \r
1162                 /* Map the UDP packet onto the start of the frame. */\r
1163                 pxUDPPacket = ( xUDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
1164 \r
1165                 /* Determine the ARP cache status for the requested IP address. */\r
1166                 eReturned = prvGetARPCacheEntry( &( pxNetworkBuffer->ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );\r
1167                 if( eReturned != eCantSendPacket )\r
1168                 {\r
1169                         if( eReturned == eARPCacheHit )\r
1170                         {\r
1171                                 iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );\r
1172 \r
1173                                 /* Create short cuts to the data within the packet. */\r
1174                                 pxIPHeader = &( pxUDPPacket->xIPHeader );\r
1175 \r
1176                                 /* IP header source and destination addresses must be set before\r
1177                                 the     UDP checksum is calculated.  The socket options, which\r
1178                                 specify whether a checksum should be calculated or not, are\r
1179                                 passed in the as yet unused part of the packet data. */\r
1180                                 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;\r
1181                                 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1182 \r
1183                                 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1184                                 {\r
1185                                         /* Is it possible that the packet is not actually a UDP packet\r
1186                                         after all, but an ICMP packet. */\r
1187                                         if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA )\r
1188                                         {\r
1189                                                 prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] );\r
1190                                         }\r
1191                                 }\r
1192                                 #else /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1193                                 {\r
1194                                         prvCompleteUDPHeader( pxNetworkBuffer, pxUDPPacket, pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] );\r
1195                                 }\r
1196                                 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1197 \r
1198                                 /* memcpy() the constant parts of the header information into\r
1199                                 the     correct location within the packet.  This fills in:\r
1200                                         xEthernetHeader.xSourceAddress\r
1201                                         xEthernetHeader.usFrameType\r
1202                                         xIPHeader.ucVersionHeaderLength\r
1203                                         xIPHeader.ucDifferentiatedServicesCode\r
1204                                         xIPHeader.usLength\r
1205                                         xIPHeader.usIdentification\r
1206                                         xIPHeader.usFragmentOffset\r
1207                                         xIPHeader.ucTimeToLive\r
1208                                         xIPHeader.ucProtocol\r
1209                                 and\r
1210                                         xIPHeader.usHeaderChecksum\r
1211                                 */\r
1212                                 memcpy( ( void *) &( pxUDPPacket->xEthernetHeader.xSourceAddress ), ( void * ) xDefaultPartUDPPacketHeader, sizeof( xDefaultPartUDPPacketHeader ) );\r
1213 \r
1214                                 #if ipconfigSUPPORT_OUTGOING_PINGS == 1\r
1215                                 {\r
1216                                         if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA )\r
1217                                         {\r
1218                                                 pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;\r
1219                                                 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) );\r
1220                                         }\r
1221                                         else\r
1222                                         {\r
1223                                                 pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );\r
1224                                         }\r
1225                                 }\r
1226                                 #else /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1227                                 {\r
1228                                         pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( xIPHeader_t ) + sizeof( xUDPHeader_t ) );\r
1229                                 }\r
1230                                 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1231 \r
1232                                 /* The total transmit size adds on the Ethernet header. */\r
1233                                 pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( xEthernetHeader_t );\r
1234                                 pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );\r
1235                                 pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;\r
1236                                 pxIPHeader->usHeaderChecksum = prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH );\r
1237                         }\r
1238                         else if ( eReturned == eARPCacheMiss )\r
1239                         {\r
1240                                 /* Generate an ARP for the required IP address. */\r
1241                                 iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );\r
1242                                 prvGenerateARPRequestPacket( pxNetworkBuffer );\r
1243 \r
1244                                 /* Add an entry to the ARP table with a null hardware address.\r
1245                                 This allows the ARP timer to know that an ARP reply is\r
1246                                 outstanding, and perform retransmissions if necessary. */\r
1247                                 prvRefreshARPCacheEntry( &xNullMACAddress, pxNetworkBuffer->ulIPAddress );\r
1248                         }\r
1249                         else\r
1250                         {\r
1251                                 /* The lookup indicated that an ARP request has already been\r
1252                                 sent out for the queried IP address. */\r
1253                                 eReturned = eCantSendPacket;\r
1254                         }\r
1255                 }\r
1256 \r
1257                 if( eReturned != eCantSendPacket )\r
1258                 {\r
1259                         /* The network driver is responsible for freeing the network buffer\r
1260                         after the packet has been sent. */\r
1261                         xNetworkInterfaceOutput( pxNetworkBuffer );\r
1262                 }\r
1263                 else\r
1264                 {\r
1265                         /* The packet can't be sent (DHCP not completed?).  Just drop the\r
1266                         packet. */\r
1267                         vNetworkBufferRelease( pxNetworkBuffer );\r
1268                 }\r
1269         }\r
1270 \r
1271 \r
1272 #endif /* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS == 1 */\r
1273 /*-----------------------------------------------------------*/\r
1274 \r
1275 static void prvGenerateARPRequestPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1276 {\r
1277 xARPPacket_t *pxARPPacket;\r
1278 \r
1279         pxARPPacket = ( xARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
1280 \r
1281         /* memcpy the const part of the header information into the correct\r
1282         location in the packet.  This copies:\r
1283                 xEthernetHeader.ulDestinationAddress\r
1284                 xEthernetHeader.usFrameType;\r
1285                 xARPHeader.usHardwareType;\r
1286                 xARPHeader.usProtocolType;\r
1287                 xARPHeader.ucHardwareAddressLength;\r
1288                 xARPHeader.ucProtocolAddressLength;\r
1289                 xARPHeader.usOperation;\r
1290                 xARPHeader.xTargetHardwareAddress;\r
1291         */\r
1292         memcpy( ( void * ) &( pxARPPacket->xEthernetHeader ), ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );\r
1293         memcpy( ( void * ) &( pxARPPacket->xEthernetHeader.xSourceAddress ) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
1294         memcpy( ( void * ) &( pxARPPacket->xARPHeader.xSenderHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
1295         pxARPPacket->xARPHeader.ulSenderProtocolAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1296         pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;\r
1297 \r
1298         pxNetworkBuffer->xDataLength = sizeof( xARPPacket_t );\r
1299 \r
1300         iptraceCREATING_ARP_REQUEST( ulIPAddress );\r
1301 }\r
1302 /*-----------------------------------------------------------*/\r
1303 \r
1304 eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )\r
1305 {\r
1306 eFrameProcessingResult_t eReturn;\r
1307 const xEthernetHeader_t *pxEthernetHeader;\r
1308 \r
1309         pxEthernetHeader = ( const xEthernetHeader_t * ) pucEthernetBuffer;\r
1310 \r
1311         if( memcmp( ( void * ) &xBroadcastMACAddress, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( xMACAddress_t ) ) == 0 )\r
1312         {\r
1313                 /* The packet was a broadcast - process it. */\r
1314                 eReturn = eProcessBuffer;\r
1315         }\r
1316         else if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( xMACAddress_t ) ) == 0 )\r
1317         {\r
1318                 /* The packet was to this node directly - process it. */\r
1319                 eReturn = eProcessBuffer;\r
1320         }\r
1321         else\r
1322         {\r
1323                 /* The packet was not a broadcast, or for this node, just release\r
1324                 the buffer without taking any other action. */\r
1325                 eReturn = eReleaseBuffer;\r
1326         }\r
1327 \r
1328         #if ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1\r
1329         {\r
1330                 uint16_t usFrameType;\r
1331 \r
1332                         if( eReturn == eProcessBuffer )\r
1333                         {\r
1334                                 usFrameType = pxEthernetHeader->usFrameType;\r
1335                                 usFrameType = FreeRTOS_ntohs( usFrameType );\r
1336 \r
1337                                 if( usFrameType <= 0x600U )\r
1338                                 {\r
1339                                         /* Not an Ethernet II frame. */\r
1340                                         eReturn = eReleaseBuffer;\r
1341                                 }\r
1342                         }\r
1343         }\r
1344         #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1  */\r
1345 \r
1346         return eReturn;\r
1347 }\r
1348 /*-----------------------------------------------------------*/\r
1349 \r
1350 static void prvProcessNetworkDownEvent( void )\r
1351 {\r
1352         /* Stop the ARP timer while there is no network. */\r
1353         xTimerStop( xARPTimer, portMAX_DELAY );\r
1354 \r
1355         #if ipconfigUSE_NETWORK_EVENT_HOOK == 1\r
1356         {\r
1357                 static portBASE_TYPE xCallEventHook = pdFALSE;\r
1358 \r
1359                 /* The first network down event is generated by the IP stack\r
1360                 itself to initialise the network hardware, so do not call the\r
1361                 network down event the first time through. */\r
1362                 if( xCallEventHook == pdTRUE )\r
1363                 {\r
1364                         vApplicationIPNetworkEventHook( eNetworkDown );\r
1365                 }\r
1366                 xCallEventHook = pdTRUE;\r
1367         }\r
1368         #endif\r
1369 \r
1370         /* The network has been disconnected (or is being\r
1371         initialised for the first time).  Perform whatever hardware\r
1372         processing is necessary to bring it up again, or wait for it\r
1373         to be available again.  This is hardware dependent. */\r
1374         if( xNetworkInterfaceInitialise() != pdPASS )\r
1375         {\r
1376                 /* Ideally the network interface initialisation function\r
1377                 will only return when the network is available.  In case\r
1378                 this is not the case, wait a while before retrying the\r
1379                 initialisation. */\r
1380                 vTaskDelay( ipINITIALISATION_RETRY_DELAY );\r
1381                 FreeRTOS_NetworkDown();\r
1382         }\r
1383         else\r
1384         {\r
1385                 /* Start the ARP timer. */\r
1386                 xTimerStart( xARPTimer, portMAX_DELAY );\r
1387 \r
1388                 #if ipconfigUSE_DHCP == 1\r
1389                 {\r
1390                         /* The network is not up until DHCP has completed. */\r
1391                         vDHCPProcess( pdTRUE, ( xMACAddress_t * ) ipLOCAL_MAC_ADDRESS, ipLOCAL_IP_ADDRESS_POINTER, &xNetworkAddressing );\r
1392                         prvSendEventToIPTask( eDHCPEvent );\r
1393                 }\r
1394                 #else\r
1395                 {\r
1396                         #if ipconfigUSE_NETWORK_EVENT_HOOK == 1\r
1397                         {\r
1398                                 vApplicationIPNetworkEventHook( eNetworkUp );\r
1399                         }\r
1400                         #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */\r
1401 \r
1402                         /* Static configuration is being used, so the network is now up. */\r
1403                         #if ipconfigFREERTOS_PLUS_NABTO == 1\r
1404                         {\r
1405                                 /* Return value is used in configASSERT() inside the \r
1406                                 function. */\r
1407                                 ( void ) xStartNabtoTask();\r
1408                         }\r
1409                         #endif /* ipconfigFREERTOS_PLUS_NABTO */\r
1410                 }\r
1411                 #endif\r
1412         }\r
1413 }\r
1414 /*-----------------------------------------------------------*/\r
1415 \r
1416 static void prvProcessEthernetPacket( xNetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1417 {\r
1418 xEthernetHeader_t *pxEthernetHeader;\r
1419 volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */\r
1420 \r
1421         configASSERT( pxNetworkBuffer );\r
1422 \r
1423         /* Interpret the Ethernet frame. */\r
1424         eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );\r
1425         pxEthernetHeader = ( xEthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
1426 \r
1427         if( eReturned == eProcessBuffer )\r
1428         {\r
1429                 /* Interpret the received Ethernet packet. */\r
1430                 switch ( pxEthernetHeader->usFrameType )\r
1431                 {\r
1432                         case ipARP_TYPE :\r
1433                                 /* The Ethernet frame contains an ARP packet. */\r
1434                                 eReturned = prvProcessARPPacket( ( xARPPacket_t * ) pxEthernetHeader );\r
1435                                 break;\r
1436 \r
1437                         case ipIP_TYPE  :\r
1438                                 /* The Ethernet frame contains an IP packet. */\r
1439                                 eReturned = prvProcessIPPacket( ( xIPPacket_t * ) pxEthernetHeader, pxNetworkBuffer );\r
1440                                 break;\r
1441 \r
1442                         default :\r
1443                                 /* No other packet types are handled.  Nothing to do. */\r
1444                                 eReturned = eReleaseBuffer;\r
1445                                 break;\r
1446                 }\r
1447         }\r
1448 \r
1449         /* Perform any actions that resulted from processing the Ethernet\r
1450         frame. */\r
1451         switch( eReturned )\r
1452         {\r
1453                 case eReturnEthernetFrame :\r
1454                         /* The Ethernet frame will have been updated (maybe it was\r
1455                         an ARP request or a PING request?) and should be sent back to\r
1456                         its source. */\r
1457                         prvReturnEthernetFrame( pxNetworkBuffer );\r
1458                         /* The buffer must be released once\r
1459                         the frame has been transmitted. */\r
1460                         break;\r
1461 \r
1462                 case eFrameConsumed :\r
1463                         /* The frame is in use somewhere, don't release the buffer\r
1464                         yet. */\r
1465                         break;\r
1466 \r
1467                 default :\r
1468                         /* The frame is not being used anywhere, and the\r
1469                         xNetworkBufferDescriptor_t structure containing the frame should just be\r
1470                         released back to the list of free buffers. */\r
1471                         vNetworkBufferRelease( pxNetworkBuffer );\r
1472                         break;\r
1473         }\r
1474 }\r
1475 /*-----------------------------------------------------------*/\r
1476 \r
1477 static eFrameProcessingResult_t prvProcessIPPacket( const xIPPacket_t * const pxIPPacket, xNetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1478 {\r
1479 eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
1480 const xIPHeader_t * pxIPHeader;\r
1481 xUDPPacket_t *pxUDPPacket;\r
1482 portBASE_TYPE xChecksumIsCorrect;\r
1483 \r
1484         pxIPHeader = &( pxIPPacket->xIPHeader );\r
1485 \r
1486         /* Is the packet for this node? */\r
1487         if( ( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER ) || ( pxIPHeader->ulDestinationIPAddress == ipBROADCAST_IP_ADDRESS ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0 ) )\r
1488         {\r
1489                 /* Ensure the frame is IPv4 with no options bytes, and that the incoming\r
1490                 packet is not fragmented (only outgoing packets can be fragmented) as\r
1491                 these are the only handled IP frames currently. */\r
1492                 if( ( pxIPHeader->ucVersionHeaderLength == ipIP_VERSION_AND_HEADER_LENGTH_BYTE ) && ( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) == 0U ) )\r
1493                 {\r
1494                         /* Is the IP header checksum correct? */\r
1495                         if( prvGenerateChecksum( ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipIP_HEADER_LENGTH ) == 0 )\r
1496                         {\r
1497                                 /* Add the IP and MAC addresses to the ARP table if they are not\r
1498                                 already there - otherwise refresh the age of the existing\r
1499                                 entry. */\r
1500                                 prvRefreshARPCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );\r
1501                                 switch( pxIPHeader->ucProtocol )\r
1502                                 {\r
1503                                         case ipPROTOCOL_ICMP :\r
1504 \r
1505                                                 /* The IP packet contained an ICMP frame.  Don't bother\r
1506                                                 checking the ICMP checksum, as if it is wrong then the\r
1507                                                 wrong data will also be returned, and the source of the\r
1508                                                 ping will know something went wrong because it will not\r
1509                                                 be able to validate what it receives. */\r
1510                                                 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1511                                                 {\r
1512                                                         if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
1513                                                         {\r
1514                                                                 eReturn = prvProcessICMPPacket( ( xICMPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ) );\r
1515                                                         }\r
1516                                                 }\r
1517                                                 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
1518                                                 break;\r
1519 \r
1520                                         case ipPROTOCOL_UDP :\r
1521 \r
1522                                                 /* The IP packet contained a UDP frame. */\r
1523                                                 pxUDPPacket = ( xUDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1524 \r
1525                                                 /* Note the header values required prior to the\r
1526                                                 checksum generation as the checksum pseudo header\r
1527                                                 may clobber some of these values. */\r
1528                                                 pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( xUDPHeader_t );\r
1529                                                 pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;\r
1530                                                 pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;\r
1531 \r
1532                                                 /* Is the checksum required? */\r
1533                                                 if( pxUDPPacket->xUDPHeader.usChecksum == 0 )\r
1534                                                 {\r
1535                                                         xChecksumIsCorrect = pdTRUE;\r
1536                                                 }\r
1537                                                 else if( prvGenerateUDPChecksum( pxUDPPacket ) == 0 )\r
1538                                                 {\r
1539                                                         xChecksumIsCorrect = pdTRUE;\r
1540                                                 }\r
1541                                                 else\r
1542                                                 {\r
1543                                                         xChecksumIsCorrect = pdFALSE;\r
1544                                                 }\r
1545 \r
1546                                                 /* Is the checksum correct? */\r
1547                                                 if( xChecksumIsCorrect == pdTRUE )\r
1548                                                 {\r
1549                                                         /* Pass the packet payload to the UDP sockets\r
1550                                                         implementation. */\r
1551                                                         if( xProcessReceivedUDPPacket( pxNetworkBuffer, pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )\r
1552                                                         {\r
1553                                                                 eReturn = eFrameConsumed;\r
1554                                                         }\r
1555                                                 }\r
1556                                                 break;\r
1557 \r
1558                                         default :\r
1559 \r
1560                                                 /* Not a supported frame type. */\r
1561                                                 break;\r
1562                                 }\r
1563                         }\r
1564                 }\r
1565         }\r
1566 \r
1567         return eReturn;\r
1568 }\r
1569 /*-----------------------------------------------------------*/\r
1570 \r
1571 static uint16_t prvGenerateUDPChecksum( const xUDPPacket_t * const pxUDPPacket )\r
1572 {\r
1573 xPseudoHeader_t *pxPseudoHeader;\r
1574 uint16_t usLength, usReturn;\r
1575 \r
1576         /* Map the pseudo header into the correct place within the real IP\r
1577         header. */\r
1578         pxPseudoHeader = ( xPseudoHeader_t * ) &( pxUDPPacket->xIPHeader.ucTimeToLive );\r
1579 \r
1580         /* Ordering here is important so as not to overwrite data that is required\r
1581         but has not yet been used as the pseudo header overlaps the information\r
1582         that is being copied into it. */\r
1583         pxPseudoHeader->ulSourceAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;\r
1584         pxPseudoHeader->ulDestinationAddress = pxUDPPacket->xIPHeader.ulDestinationIPAddress;\r
1585         pxPseudoHeader->ucZeros = 0x00;\r
1586         pxPseudoHeader->ucProtocol = ipPROTOCOL_UDP;\r
1587         pxPseudoHeader->usUDPLength = pxUDPPacket->xUDPHeader.usLength;\r
1588 \r
1589         usLength = FreeRTOS_ntohs( pxPseudoHeader->usUDPLength );\r
1590         usReturn = prvGenerateChecksum( ( uint8_t * ) pxPseudoHeader, usLength + sizeof( xPseudoHeader_t ) );\r
1591 \r
1592         return usReturn;\r
1593 }\r
1594 /*-----------------------------------------------------------*/\r
1595 \r
1596 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1597 \r
1598         static void prvProcessICMPEchoReply( xICMPPacket_t * const pxICMPPacket )\r
1599         {\r
1600         ePingReplyStatus_t eStatus = eSuccess;\r
1601         uint16_t usDataLength, usCount;\r
1602         uint8_t *pucByte;\r
1603 \r
1604                 /* Find the total length of the IP packet. */\r
1605                 usDataLength = pxICMPPacket->xIPHeader.usLength;\r
1606                 usDataLength = FreeRTOS_ntohs( usDataLength );\r
1607 \r
1608                 /* Remove the length of the IP headers to obtain the length of the ICMP\r
1609                 message itself. */\r
1610                 usDataLength -= sizeof( xIPHeader_t );\r
1611 \r
1612                 if( prvGenerateChecksum( ( uint8_t * ) &( pxICMPPacket->xICMPHeader ), usDataLength ) != 0 )\r
1613                 {\r
1614                         eStatus = eInvalidChecksum;\r
1615                 }\r
1616                 else\r
1617                 {\r
1618                         /* Remove the length of the ICMP header, to obtain the length of\r
1619                         data contained in the ping. */\r
1620                         usDataLength -= sizeof( xICMPHeader_t );\r
1621 \r
1622                         /* Find the first byte of the data within the ICMP packet. */\r
1623                         pucByte = ( uint8_t * ) pxICMPPacket;\r
1624                         pucByte += sizeof( xICMPPacket_t );\r
1625 \r
1626                         /* Check each byte. */\r
1627                         for( usCount = 0; usCount < usDataLength; usCount++ )\r
1628                         {\r
1629                                 if( *pucByte != ipECHO_DATA_FILL_BYTE )\r
1630                                 {\r
1631                                         eStatus = eInvalidData;\r
1632                                         break;\r
1633                                 }\r
1634 \r
1635                                 pucByte++;\r
1636                         }\r
1637                 }\r
1638 \r
1639                 vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );\r
1640         }\r
1641 \r
1642 #endif\r
1643 /*-----------------------------------------------------------*/\r
1644 \r
1645 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
1646 \r
1647         static eFrameProcessingResult_t prvProcessICMPEchoRequest( xICMPPacket_t * const pxICMPPacket )\r
1648         {\r
1649         xICMPHeader_t *pxICMPHeader;\r
1650         xIPHeader_t *pxIPHeader;\r
1651 \r
1652                 iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );\r
1653 \r
1654                 pxICMPHeader = &( pxICMPPacket->xICMPHeader );\r
1655                 pxIPHeader = &( pxICMPPacket->xIPHeader );\r
1656 \r
1657                 /* The checksum can be checked here - but a ping reply should be\r
1658                 returned even if the checksum is incorrect so the other end can\r
1659                 tell that the ping was received - even if the ping reply contains\r
1660                 invalid data. */\r
1661                 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REPLY;\r
1662                 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;\r
1663                 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1664 \r
1665                 /* Update the checksum because the ucTypeOfMessage member in the\r
1666                 header has been changed to ipICMP_ECHO_REPLY. */\r
1667                 if( pxICMPHeader->usChecksum >= FreeRTOS_htons( ( ( uint16_t ) 0xffffU ) - ( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) ) ) )\r
1668                 {\r
1669                         pxICMPHeader->usChecksum += FreeRTOS_htons( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) ) + ( uint16_t ) 1U;\r
1670                 }\r
1671                 else\r
1672                 {\r
1673                         pxICMPHeader->usChecksum += FreeRTOS_htons( ipICMP_ECHO_REQUEST << ( ( uint16_t ) 8U ) );\r
1674                 }\r
1675 \r
1676                 return eReturnEthernetFrame;\r
1677         }\r
1678 \r
1679 #endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */\r
1680 \r
1681 /*-----------------------------------------------------------*/\r
1682 \r
1683 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1684 \r
1685         static eFrameProcessingResult_t prvProcessICMPPacket( xICMPPacket_t * const pxICMPPacket )\r
1686         {\r
1687         eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
1688 \r
1689                 iptraceICMP_PACKET_RECEIVED();\r
1690 \r
1691                 switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )\r
1692                 {\r
1693                         case ipICMP_ECHO_REQUEST        :\r
1694                                 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
1695                                 {\r
1696                                         eReturn = prvProcessICMPEchoRequest( pxICMPPacket );\r
1697                                 }\r
1698                                 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */\r
1699                                 break;\r
1700 \r
1701                         case ipICMP_ECHO_REPLY          :\r
1702                                 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1703                                 {\r
1704                                         prvProcessICMPEchoReply( pxICMPPacket );\r
1705                                 }\r
1706                                 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1707                                 break;\r
1708 \r
1709                         default :\r
1710                                 break;\r
1711                 }\r
1712 \r
1713                 return eReturn;\r
1714         }\r
1715 \r
1716 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
1717 /*-----------------------------------------------------------*/\r
1718 \r
1719 static uint16_t prvGenerateChecksum( const uint8_t * const pucNextData, const uint16_t usDataLengthBytes )\r
1720 {\r
1721 uint32_t ulChecksum = 0;\r
1722 uint16_t us, usDataLength16BitWords, *pusNextData;\r
1723 \r
1724         /* There are half as many 16 bit words than bytes. */\r
1725         usDataLength16BitWords = ( usDataLengthBytes >> 1U );\r
1726 \r
1727         pusNextData = ( uint16_t * ) pucNextData;\r
1728 \r
1729         for( us = 0U; us < usDataLength16BitWords; us++ )\r
1730         {\r
1731                 ulChecksum += ( uint32_t ) pusNextData[ us ];\r
1732         }\r
1733 \r
1734         if( ( usDataLengthBytes & 0x01U ) != 0x00 )\r
1735         {\r
1736                 /* There is one byte left over. */\r
1737                 #if ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN\r
1738                 {\r
1739                         ulChecksum += ( uint32_t ) pucNextData[ usDataLengthBytes - 1 ];\r
1740                 }\r
1741                 #else\r
1742                 {\r
1743                         us = ( uint16_t ) pucNextData[ usDataLengthBytes - 1 ];\r
1744                         ulChecksum += ( uint32_t ) ( us << 8 );\r
1745                 }\r
1746                 #endif\r
1747         }\r
1748 \r
1749         while( ( ulChecksum >> 16UL ) != 0x00UL )\r
1750         {\r
1751                 ulChecksum = ( ulChecksum & 0xffffUL ) + ( ulChecksum >> 16UL );\r
1752         }\r
1753 \r
1754         return ~( ( uint16_t ) ulChecksum );\r
1755 }\r
1756 /*-----------------------------------------------------------*/\r
1757 \r
1758 static void prvReturnEthernetFrame( xNetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1759 {\r
1760 xEthernetHeader_t *pxEthernetHeader;\r
1761 \r
1762         pxEthernetHeader = ( xEthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1763 \r
1764         /* Swap source and destination MAC addresses. */\r
1765         memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );\r
1766         memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
1767 \r
1768         /* Send! */\r
1769         xNetworkInterfaceOutput( pxNetworkBuffer );\r
1770 }\r
1771 /*-----------------------------------------------------------*/\r
1772 \r
1773 static eFrameProcessingResult_t prvProcessARPPacket( xARPPacket_t * const pxARPFrame )\r
1774 {\r
1775 eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
1776 xARPHeader_t *pxARPHeader;\r
1777 \r
1778         pxARPHeader = &( pxARPFrame->xARPHeader );\r
1779 \r
1780         traceARP_PACKET_RECEIVED();\r
1781 \r
1782         /* Sanity check the protocol type.  Don't do anything if the local IP\r
1783         address is zero because that means a DHCP request has not completed. */\r
1784         if( ( pxARPHeader->usProtocolType == ipARP_PROTOCOL_TYPE ) && ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )\r
1785         {\r
1786                 switch( pxARPHeader->usOperation )\r
1787                 {\r
1788                         case ipARP_REQUEST      :\r
1789                                 /* The packet contained an ARP request.  Was it for the IP\r
1790                                 address of the node running this code? */\r
1791                                 if( pxARPHeader->ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
1792                                 {\r
1793                                         iptraceSENDING_ARP_REPLY( pxARPHeader->ulSenderProtocolAddress );\r
1794 \r
1795                                         /* The request is for the address of this node.  Add the\r
1796                                         entry into the ARP cache, or refresh the entry if it\r
1797                                         already exists. */\r
1798                                         prvRefreshARPCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), pxARPHeader->ulSenderProtocolAddress );\r
1799 \r
1800                                         /* Generate a reply payload in the same buffer. */\r
1801                                         pxARPHeader->usOperation = ipARP_REPLY;\r
1802                                         memcpy( ( void * )  &( pxARPHeader->xTargetHardwareAddress ), ( void * ) &( pxARPHeader->xSenderHardwareAddress ), sizeof( xMACAddress_t ) );\r
1803                                         pxARPHeader->ulTargetProtocolAddress = pxARPHeader->ulSenderProtocolAddress;\r
1804                                         memcpy( ( void * ) &( pxARPHeader->xSenderHardwareAddress ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( xMACAddress_t ) );\r
1805                                         pxARPHeader->ulSenderProtocolAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1806 \r
1807                                         eReturn = eReturnEthernetFrame;\r
1808                                 }\r
1809                                 break;\r
1810 \r
1811                         case ipARP_REPLY :\r
1812                                 iptracePROCESSING_RECEIVED_ARP_REPLY( pxARPHeader->ulTargetProtocolAddress );\r
1813                                 prvRefreshARPCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), pxARPHeader->ulSenderProtocolAddress );\r
1814                                 break;\r
1815 \r
1816                         default :\r
1817                                 /* Invalid. */\r
1818                                 break;\r
1819                 }\r
1820         }\r
1821 \r
1822         return eReturn;\r
1823 }\r
1824 /*-----------------------------------------------------------*/\r
1825 \r
1826 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )\r
1827         uint16_t FreeRTOS_htons( uint16_t usIn )\r
1828         {\r
1829                 return  ( ( usIn & ( uint16_t ) 0x00ff ) << ( uint16_t ) 8U ) |\r
1830                                 ( ( usIn & ( uint16_t ) 0xff00 ) >> ( uint16_t ) 8U );\r
1831         }\r
1832 #endif /* ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN */\r
1833 /*-----------------------------------------------------------*/\r
1834 \r
1835 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )\r
1836         uint32_t FreeRTOS_htonl( uint32_t ulIn )\r
1837         {\r
1838                 return  ( ( ulIn & 0x000000ffUL ) << 24UL ) |\r
1839                                 ( ( ulIn & 0x0000ff00UL ) << 8UL  ) |\r
1840                                 ( ( ulIn & 0x00ff0000UL ) >> 8UL  ) |\r
1841                                 ( ( ulIn & 0xff000000UL ) >> 24UL );\r
1842         }\r
1843 #endif /* ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN */\r
1844 \r
1845 /*-----------------------------------------------------------*/\r
1846 \r