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