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