]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c
Sync with TCP version from AWS, including:
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_IP.c
1 /*\r
2  * FreeRTOS+TCP V2.0.3\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://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /* Standard includes. */\r
27 #include <stdint.h>\r
28 #include <stdio.h>\r
29 #include <string.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 \r
37 /* FreeRTOS+TCP includes. */\r
38 #include "FreeRTOS_IP.h"\r
39 #include "FreeRTOS_Sockets.h"\r
40 #include "FreeRTOS_IP_Private.h"\r
41 #include "FreeRTOS_ARP.h"\r
42 #include "FreeRTOS_UDP_IP.h"\r
43 #include "FreeRTOS_TCP_IP.h"\r
44 #include "FreeRTOS_DHCP.h"\r
45 #include "NetworkInterface.h"\r
46 #include "NetworkBufferManagement.h"\r
47 #include "FreeRTOS_DNS.h"\r
48 \r
49 \r
50 /* Used to ensure the structure packing is having the desired effect.  The\r
51 'volatile' is used to prevent compiler warnings about comparing a constant with\r
52 a constant. */\r
53 #define ipEXPECTED_EthernetHeader_t_SIZE        ( ( size_t ) 14 )\r
54 #define ipEXPECTED_ARPHeader_t_SIZE                     ( ( size_t ) 28 )\r
55 #define ipEXPECTED_IPHeader_t_SIZE                      ( ( size_t ) 20 )\r
56 #define ipEXPECTED_IGMPHeader__SIZE                     ( ( size_t ) 8 )\r
57 #define ipEXPECTED_ICMPHeader_t_SIZE            ( ( size_t ) 8 )\r
58 #define ipEXPECTED_UDPHeader_t_SIZE                     ( ( size_t ) 8 )\r
59 #define ipEXPECTED_TCPHeader_t_SIZE                     ( ( size_t ) 20 )\r
60 \r
61 \r
62 /* ICMP protocol definitions. */\r
63 #define ipICMP_ECHO_REQUEST                             ( ( uint8_t ) 8 )\r
64 #define ipICMP_ECHO_REPLY                               ( ( uint8_t ) 0 )\r
65 \r
66 \r
67 /* Time delay between repeated attempts to initialise the network hardware. */\r
68 #ifndef ipINITIALISATION_RETRY_DELAY\r
69         #define ipINITIALISATION_RETRY_DELAY    ( pdMS_TO_TICKS( 3000 ) )\r
70 #endif\r
71 \r
72 /* Defines how often the ARP timer callback function is executed.  The time is\r
73 shorted in the Windows simulator as simulated time is not real time. */\r
74 #ifndef ipARP_TIMER_PERIOD_MS\r
75         #ifdef _WINDOWS_\r
76                 #define ipARP_TIMER_PERIOD_MS   ( 500 ) /* For windows simulator builds. */\r
77         #else\r
78                 #define ipARP_TIMER_PERIOD_MS   ( 10000 )\r
79         #endif\r
80 #endif\r
81 \r
82 #ifndef iptraceIP_TASK_STARTING\r
83         #define iptraceIP_TASK_STARTING()       do {} while( 0 )\r
84 #endif\r
85 \r
86 #if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )\r
87         /* When initialising the TCP timer,\r
88         give it an initial time-out of 1 second. */\r
89         #define ipTCP_TIMER_PERIOD_MS   ( 1000 )\r
90 #endif\r
91 \r
92 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet\r
93 driver will filter incoming packets and only pass the stack those packets it\r
94 considers need processing.  In this case ipCONSIDER_FRAME_FOR_PROCESSING() can\r
95 be #defined away.  If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0\r
96 then the Ethernet driver will pass all received packets to the stack, and the\r
97 stack must do the filtering itself.  In this case ipCONSIDER_FRAME_FOR_PROCESSING\r
98 needs to call eConsiderFrameForProcessing. */\r
99 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0\r
100         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )\r
101 #else\r
102         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer\r
103 #endif\r
104 \r
105 /* The character used to fill ICMP echo requests, and therefore also the\r
106 character expected to fill ICMP echo replies. */\r
107 #define ipECHO_DATA_FILL_BYTE                                           'x'\r
108 \r
109 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )\r
110         /* The bits in the two byte IP header field that make up the fragment offset value. */\r
111         #define ipFRAGMENT_OFFSET_BIT_MASK                              ( ( uint16_t ) 0xff0f )\r
112 #else\r
113         /* The bits in the two byte IP header field that make up the fragment offset value. */\r
114         #define ipFRAGMENT_OFFSET_BIT_MASK                              ( ( uint16_t ) 0x0fff )\r
115 #endif /* ipconfigBYTE_ORDER */\r
116 \r
117 /* The maximum time the IP task is allowed to remain in the Blocked state if no\r
118 events are posted to the network event queue. */\r
119 #ifndef ipconfigMAX_IP_TASK_SLEEP_TIME\r
120         #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) )\r
121 #endif\r
122 \r
123 /* When a new TCP connection is established, the value of\r
124 'ulNextInitialSequenceNumber' will be used as the initial sequence number.  It\r
125 is very important that at start-up, 'ulNextInitialSequenceNumber' contains a\r
126 random value.  Also its value must be increased continuously in time, to prevent\r
127 a third party guessing the next sequence number and take-over a TCP connection.\r
128 It is advised to increment it by 1 ever 4us, which makes about 256 times\r
129 per ms: */\r
130 #define ipINITIAL_SEQUENCE_NUMBER_FACTOR        256UL\r
131 \r
132 /* Returned as the (invalid) checksum when the protocol being checked is not\r
133 handled.  The value is chosen simply to be easy to spot when debugging. */\r
134 #define ipUNHANDLED_PROTOCOL            0x4321u\r
135 \r
136 /* Returned to indicate a valid checksum when the checksum does not need to be\r
137 calculated. */\r
138 #define ipCORRECT_CRC                           0xffffu\r
139 \r
140 /* Returned as the (invalid) checksum when the length of the data being checked\r
141 had an invalid length. */\r
142 #define ipINVALID_LENGTH                        0x1234u\r
143 \r
144 /*-----------------------------------------------------------*/\r
145 \r
146 typedef struct xIP_TIMER\r
147 {\r
148         uint32_t\r
149                 bActive : 1,    /* This timer is running and must be processed. */\r
150                 bExpired : 1;   /* Timer has expired and a task must be processed. */\r
151         TimeOut_t xTimeOut;\r
152         TickType_t ulRemainingTime;\r
153         TickType_t ulReloadTime;\r
154 } IPTimer_t;\r
155 \r
156 /* Used in checksum calculation. */\r
157 typedef union _xUnion32\r
158 {\r
159         uint32_t u32;\r
160         uint16_t u16[ 2 ];\r
161         uint8_t u8[ 4 ];\r
162 } xUnion32;\r
163 \r
164 /* Used in checksum calculation. */\r
165 typedef union _xUnionPtr\r
166 {\r
167         uint32_t *u32ptr;\r
168         uint16_t *u16ptr;\r
169         uint8_t *u8ptr;\r
170 } xUnionPtr;\r
171 \r
172 /*-----------------------------------------------------------*/\r
173 \r
174 /*\r
175  * The main TCP/IP stack processing task.  This task receives commands/events\r
176  * from the network hardware drivers and tasks that are using sockets.  It also\r
177  * maintains a set of protocol timers.\r
178  */\r
179 static void prvIPTask( void *pvParameters );\r
180 \r
181 /*\r
182  * Called when new data is available from the network interface.\r
183  */\r
184 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );\r
185 \r
186 /*\r
187  * Process incoming IP packets.\r
188  */\r
189 static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer );\r
190 \r
191 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
192         /*\r
193          * Process incoming ICMP packets.\r
194          */\r
195         static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket );\r
196 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
197 \r
198 /*\r
199  * Turns around an incoming ping request to convert it into a ping reply.\r
200  */\r
201 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
202         static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket );\r
203 #endif /* ipconfigREPLY_TO_INCOMING_PINGS */\r
204 \r
205 /*\r
206  * Processes incoming ping replies.  The application callback function\r
207  * vApplicationPingReplyHook() is called with the results.\r
208  */\r
209 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
210         static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket );\r
211 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
212 \r
213 /*\r
214  * Called to create a network connection when the stack is first started, or\r
215  * when the network connection is lost.\r
216  */\r
217 static void prvProcessNetworkDownEvent( void );\r
218 \r
219 /*\r
220  * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout\r
221  * processing is required.\r
222  */\r
223 static void prvCheckNetworkTimers( void );\r
224 \r
225 /*\r
226  * Determine how long the IP task can sleep for, which depends on when the next\r
227  * periodic or timeout processing must be performed.\r
228  */\r
229 static TickType_t prvCalculateSleepTime( void );\r
230 \r
231 /*\r
232  * The network card driver has received a packet.  In the case that it is part\r
233  * of a linked packet chain, walk through it to handle every message.\r
234  */\r
235 static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer );\r
236 \r
237 /*\r
238  * Utility functions for the light weight IP timers.\r
239  */\r
240 static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime );\r
241 static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer );\r
242 static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime );\r
243 \r
244 static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,\r
245         NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength );\r
246 \r
247 /*-----------------------------------------------------------*/\r
248 \r
249 /* The queue used to pass events into the IP-task for processing. */\r
250 QueueHandle_t xNetworkEventQueue = NULL;\r
251 \r
252 /*_RB_ Requires comment. */\r
253 uint16_t usPacketIdentifier = 0U;\r
254 \r
255 /* For convenience, a MAC address of all 0xffs is defined const for quick\r
256 reference. */\r
257 const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };\r
258 \r
259 /* Structure that stores the netmask, gateway address and DNS server addresses. */\r
260 NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 };\r
261 \r
262 /* Default values for the above struct in case DHCP\r
263 does not lead to a confirmed request. */\r
264 NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };\r
265 \r
266 /* Used to ensure network down events cannot be missed when they cannot be\r
267 posted to the network event queue because the network event queue is already\r
268 full. */\r
269 static BaseType_t xNetworkDownEventPending = pdFALSE;\r
270 \r
271 /* Stores the handle of the task that handles the stack.  The handle is used\r
272 (indirectly) by some utility function to determine if the utility function is\r
273 being called by a task (in which case it is ok to block) or by the IP task\r
274 itself (in which case it is not ok to block). */\r
275 static TaskHandle_t xIPTaskHandle = NULL;\r
276 \r
277 #if( ipconfigUSE_TCP != 0 )\r
278         /* Set to a non-zero value if one or more TCP message have been processed\r
279         within the last round. */\r
280         static BaseType_t xProcessedTCPMessage;\r
281 #endif\r
282 \r
283 /* Simple set to pdTRUE or pdFALSE depending on whether the network is up or\r
284 down (connected, not connected) respectively. */\r
285 static BaseType_t xNetworkUp = pdFALSE;\r
286 \r
287 /*\r
288 A timer for each of the following processes, all of which need attention on a\r
289 regular basis:\r
290         1. ARP, to check its table entries\r
291         2. DPHC, to send requests and to renew a reservation\r
292         3. TCP, to check for timeouts, resends\r
293         4. DNS, to check for timeouts when looking-up a domain.\r
294  */\r
295 static IPTimer_t xARPTimer;\r
296 #if( ipconfigUSE_DHCP != 0 )\r
297         static IPTimer_t xDHCPTimer;\r
298 #endif\r
299 #if( ipconfigUSE_TCP != 0 )\r
300         static IPTimer_t xTCPTimer;\r
301 #endif\r
302 #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
303         static IPTimer_t xDNSTimer;\r
304 #endif\r
305 \r
306 /* Set to pdTRUE when the IP task is ready to start processing packets. */\r
307 static BaseType_t xIPTaskInitialised = pdFALSE;\r
308 \r
309 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
310         /* Keep track of the lowest amount of space in 'xNetworkEventQueue'. */\r
311         static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;\r
312 #endif\r
313 \r
314 /*-----------------------------------------------------------*/\r
315 \r
316 static void prvIPTask( void *pvParameters )\r
317 {\r
318 IPStackEvent_t xReceivedEvent;\r
319 TickType_t xNextIPSleep;\r
320 FreeRTOS_Socket_t *pxSocket;\r
321 struct freertos_sockaddr xAddress;\r
322 \r
323         /* Just to prevent compiler warnings about unused parameters. */\r
324         ( void ) pvParameters;\r
325 \r
326         /* A possibility to set some additional task properties. */\r
327         iptraceIP_TASK_STARTING();\r
328 \r
329         /* Generate a dummy message to say that the network connection has gone\r
330         down.  This will cause this task to initialise the network interface.  After\r
331         this it is the responsibility of the network interface hardware driver to\r
332         send this message if a previously connected network is disconnected. */\r
333         FreeRTOS_NetworkDown();\r
334 \r
335         #if( ipconfigUSE_TCP == 1 )\r
336         {\r
337                 /* Initialise the TCP timer. */\r
338                 prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );\r
339         }\r
340         #endif\r
341 \r
342         /* Initialisation is complete and events can now be processed. */\r
343         xIPTaskInitialised = pdTRUE;\r
344 \r
345         FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );\r
346 \r
347         /* Loop, processing IP events. */\r
348         for( ;; )\r
349         {\r
350                 ipconfigWATCHDOG_TIMER();\r
351 \r
352                 /* Check the ARP, DHCP and TCP timers to see if there is any periodic\r
353                 or timeout processing to perform. */\r
354                 prvCheckNetworkTimers();\r
355 \r
356                 /* Calculate the acceptable maximum sleep time. */\r
357                 xNextIPSleep = prvCalculateSleepTime();\r
358 \r
359                 /* Wait until there is something to do.  The event is initialised to "no\r
360                 event" in case the following call exits due to a time out rather than a\r
361                 message being received. */\r
362                 xReceivedEvent.eEventType = eNoEvent;\r
363                 xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep );\r
364 \r
365                 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
366                 {\r
367                         if( xReceivedEvent.eEventType != eNoEvent )\r
368                         {\r
369                         UBaseType_t uxCount;\r
370 \r
371                                 uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );\r
372                                 if( uxQueueMinimumSpace > uxCount )\r
373                                 {\r
374                                         uxQueueMinimumSpace = uxCount;\r
375                                 }\r
376                         }\r
377                 }\r
378                 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
379 \r
380                 iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );\r
381 \r
382                 switch( xReceivedEvent.eEventType )\r
383                 {\r
384                         case eNetworkDownEvent :\r
385                                 /* Attempt to establish a connection. */\r
386                                 xNetworkUp = pdFALSE;\r
387                                 prvProcessNetworkDownEvent();\r
388                                 break;\r
389 \r
390                         case eNetworkRxEvent:\r
391                                 /* The network hardware driver has received a new packet.  A\r
392                                 pointer to the received buffer is located in the pvData member\r
393                                 of the received event structure. */\r
394                                 prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );\r
395                                 break;\r
396 \r
397                         case eARPTimerEvent :\r
398                                 /* The ARP timer has expired, process the ARP cache. */\r
399                                 vARPAgeCache();\r
400                                 break;\r
401 \r
402                         case eSocketBindEvent:\r
403                                 /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket\r
404                                 to a port. The port number is communicated in the socket field\r
405                                 usLocalPort. vSocketBind() will actually bind the socket and the\r
406                                 API will unblock as soon as the eSOCKET_BOUND event is\r
407                                 triggered. */\r
408                                 pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );\r
409                                 xAddress.sin_addr = 0u; /* For the moment. */\r
410                                 xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );\r
411                                 pxSocket->usLocalPort = 0u;\r
412                                 vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );\r
413 \r
414                                 /* Before 'eSocketBindEvent' was sent it was tested that\r
415                                 ( xEventGroup != NULL ) so it can be used now to wake up the\r
416                                 user. */\r
417                                 pxSocket->xEventBits |= eSOCKET_BOUND;\r
418                                 vSocketWakeUpUser( pxSocket );\r
419                                 break;\r
420 \r
421                         case eSocketCloseEvent :\r
422                                 /* The user API FreeRTOS_closesocket() has sent a message to the\r
423                                 IP-task to actually close a socket. This is handled in\r
424                                 vSocketClose().  As the socket gets closed, there is no way to\r
425                                 report back to the API, so the API won't wait for the result */\r
426                                 vSocketClose( ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ) );\r
427                                 break;\r
428 \r
429                         case eStackTxEvent :\r
430                                 /* The network stack has generated a packet to send.  A\r
431                                 pointer to the generated buffer is located in the pvData\r
432                                 member of the received event structure. */\r
433                                 vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );\r
434                                 break;\r
435 \r
436                         case eDHCPEvent:\r
437                                 /* The DHCP state machine needs processing. */\r
438                                 #if( ipconfigUSE_DHCP == 1 )\r
439                                 {\r
440                                         vDHCPProcess( pdFALSE );\r
441                                 }\r
442                                 #endif /* ipconfigUSE_DHCP */\r
443                                 break;\r
444 \r
445                         case eSocketSelectEvent :\r
446                                 /* FreeRTOS_select() has got unblocked by a socket event,\r
447                                 vSocketSelect() will check which sockets actually have an event\r
448                                 and update the socket field xSocketBits. */\r
449                                 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )\r
450                                 {\r
451                                         vSocketSelect( ( SocketSelect_t * ) ( xReceivedEvent.pvData ) );\r
452                                 }\r
453                                 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */\r
454                                 break;\r
455 \r
456                         case eSocketSignalEvent :\r
457                                 #if( ipconfigSUPPORT_SIGNALS != 0 )\r
458                                 {\r
459                                         /* Some task wants to signal the user of this socket in\r
460                                         order to interrupt a call to recv() or a call to select(). */\r
461                                         FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData );\r
462                                 }\r
463                                 #endif /* ipconfigSUPPORT_SIGNALS */\r
464                                 break;\r
465 \r
466                         case eTCPTimerEvent :\r
467                                 #if( ipconfigUSE_TCP == 1 )\r
468                                 {\r
469                                         /* Simply mark the TCP timer as expired so it gets processed\r
470                                         the next time prvCheckNetworkTimers() is called. */\r
471                                         xTCPTimer.bExpired = pdTRUE_UNSIGNED;\r
472                                 }\r
473                                 #endif /* ipconfigUSE_TCP */\r
474                                 break;\r
475 \r
476                         case eTCPAcceptEvent:\r
477                                 /* The API FreeRTOS_accept() was called, the IP-task will now\r
478                                 check if the listening socket (communicated in pvData) actually\r
479                                 received a new connection. */\r
480                                 #if( ipconfigUSE_TCP == 1 )\r
481                                 {\r
482                                         pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );\r
483 \r
484                                         if( xTCPCheckNewClient( pxSocket ) != pdFALSE )\r
485                                         {\r
486                                                 pxSocket->xEventBits |= eSOCKET_ACCEPT;\r
487                                                 vSocketWakeUpUser( pxSocket );\r
488                                         }\r
489                                 }\r
490                                 #endif /* ipconfigUSE_TCP */\r
491                                 break;\r
492 \r
493                         case eTCPNetStat:\r
494                                 /* FreeRTOS_netstat() was called to have the IP-task print an\r
495                                 overview of all sockets and their connections */\r
496                                 #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )\r
497                                 {\r
498                                         vTCPNetStat();\r
499                                 }\r
500                                 #endif /* ipconfigUSE_TCP */\r
501                                 break;\r
502 \r
503                         default :\r
504                                 /* Should not get here. */\r
505                                 break;\r
506                 }\r
507 \r
508                 if( xNetworkDownEventPending != pdFALSE )\r
509                 {\r
510                         /* A network down event could not be posted to the network event\r
511                         queue because the queue was full.  Try posting again. */\r
512                         FreeRTOS_NetworkDown();\r
513                 }\r
514         }\r
515 }\r
516 /*-----------------------------------------------------------*/\r
517 \r
518 BaseType_t xIsCallingFromIPTask( void )\r
519 {\r
520 BaseType_t xReturn;\r
521 \r
522         if( xTaskGetCurrentTaskHandle() == xIPTaskHandle )\r
523         {\r
524                 xReturn = pdTRUE;\r
525         }\r
526         else\r
527         {\r
528                 xReturn = pdFALSE;\r
529         }\r
530 \r
531         return xReturn;\r
532 }\r
533 /*-----------------------------------------------------------*/\r
534 \r
535 static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer )\r
536 {\r
537         #if( ipconfigUSE_LINKED_RX_MESSAGES == 0 )\r
538         {\r
539                 /* When ipconfigUSE_LINKED_RX_MESSAGES is not set to 0 then only one\r
540                 buffer will be sent at a time.  This is the default way for +TCP to pass\r
541                 messages from the MAC to the TCP/IP stack. */\r
542                 prvProcessEthernetPacket( pxBuffer );\r
543         }\r
544         #else /* ipconfigUSE_LINKED_RX_MESSAGES */\r
545         {\r
546         NetworkBufferDescriptor_t *pxNextBuffer;\r
547 \r
548                 /* An optimisation that is useful when there is high network traffic.\r
549                 Instead of passing received packets into the IP task one at a time the\r
550                 network interface can chain received packets together and pass them into\r
551                 the IP task in one go.  The packets are chained using the pxNextBuffer\r
552                 member.  The loop below walks through the chain processing each packet\r
553                 in the chain in turn. */\r
554                 do\r
555                 {\r
556                         /* Store a pointer to the buffer after pxBuffer for use later on. */\r
557                         pxNextBuffer = pxBuffer->pxNextBuffer;\r
558 \r
559                         /* Make it NULL to avoid using it later on. */\r
560                         pxBuffer->pxNextBuffer = NULL;\r
561 \r
562                         prvProcessEthernetPacket( pxBuffer );\r
563                         pxBuffer = pxNextBuffer;\r
564 \r
565                 /* While there is another packet in the chain. */\r
566                 } while( pxBuffer != NULL );\r
567         }\r
568         #endif /* ipconfigUSE_LINKED_RX_MESSAGES */\r
569 }\r
570 /*-----------------------------------------------------------*/\r
571 \r
572 static TickType_t prvCalculateSleepTime( void )\r
573 {\r
574 TickType_t xMaximumSleepTime;\r
575 \r
576         /* Start with the maximum sleep time, then check this against the remaining\r
577         time in any other timers that are active. */\r
578         xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;\r
579 \r
580         if( xARPTimer.bActive != pdFALSE_UNSIGNED )\r
581         {\r
582                 if( xARPTimer.ulRemainingTime < xMaximumSleepTime )\r
583                 {\r
584                         xMaximumSleepTime = xARPTimer.ulReloadTime;\r
585                 }\r
586         }\r
587 \r
588         #if( ipconfigUSE_DHCP == 1 )\r
589         {\r
590                 if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )\r
591                 {\r
592                         if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime )\r
593                         {\r
594                                 xMaximumSleepTime = xDHCPTimer.ulRemainingTime;\r
595                         }\r
596                 }\r
597         }\r
598         #endif /* ipconfigUSE_DHCP */\r
599 \r
600         #if( ipconfigUSE_TCP == 1 )\r
601         {\r
602                 if( xTCPTimer.ulRemainingTime < xMaximumSleepTime )\r
603                 {\r
604                         xMaximumSleepTime = xTCPTimer.ulRemainingTime;\r
605                 }\r
606         }\r
607         #endif\r
608 \r
609         #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
610         {\r
611                 if( xDNSTimer.bActive != pdFALSE )\r
612                 {\r
613                         if( xDNSTimer.ulRemainingTime < xMaximumSleepTime )\r
614                         {\r
615                                 xMaximumSleepTime = xDNSTimer.ulRemainingTime;\r
616                         }\r
617                 }\r
618         }\r
619         #endif\r
620 \r
621         return xMaximumSleepTime;\r
622 }\r
623 /*-----------------------------------------------------------*/\r
624 \r
625 static void prvCheckNetworkTimers( void )\r
626 {\r
627         /* Is it time for ARP processing? */\r
628         if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )\r
629         {\r
630                 xSendEventToIPTask( eARPTimerEvent );\r
631         }\r
632 \r
633         #if( ipconfigUSE_DHCP == 1 )\r
634         {\r
635                 /* Is it time for DHCP processing? */\r
636                 if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )\r
637                 {\r
638                         xSendEventToIPTask( eDHCPEvent );\r
639                 }\r
640         }\r
641         #endif /* ipconfigUSE_DHCP */\r
642 \r
643         #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
644         {\r
645         extern void vDNSCheckCallBack( void *pvSearchID );\r
646 \r
647                 /* Is it time for DNS processing? */\r
648                 if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )\r
649                 {\r
650                         vDNSCheckCallBack( NULL );\r
651                 }\r
652         }\r
653         #endif /* ipconfigDNS_USE_CALLBACKS */\r
654 \r
655         #if( ipconfigUSE_TCP == 1 )\r
656         {\r
657         BaseType_t xWillSleep;\r
658         /* xStart keeps a copy of the last time this function was active,\r
659         and during every call it will be updated with xTaskGetTickCount()\r
660         '0' means: not yet initialised (although later '0' might be returned\r
661         by xTaskGetTickCount(), which is no problem). */\r
662         static TickType_t xStart = ( TickType_t ) 0;\r
663         TickType_t xTimeNow, xNextTime;\r
664         BaseType_t xCheckTCPSockets;\r
665         extern uint32_t ulNextInitialSequenceNumber;\r
666 \r
667                 if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u )\r
668                 {\r
669                         xWillSleep = pdTRUE;\r
670                 }\r
671                 else\r
672                 {\r
673                         xWillSleep = pdFALSE;\r
674                 }\r
675 \r
676                 xTimeNow = xTaskGetTickCount();\r
677 \r
678                 if( xStart != ( TickType_t ) 0 )\r
679                 {\r
680                         /* It is advised to increment the Initial Sequence Number every 4\r
681                         microseconds which makes 250 times per ms.  This will make it harder\r
682                         for a third party to 'guess' our sequence number and 'take over'\r
683                         a TCP connection */\r
684                         ulNextInitialSequenceNumber += ipINITIAL_SEQUENCE_NUMBER_FACTOR * ( ( xTimeNow - xStart ) * portTICK_PERIOD_MS );\r
685                 }\r
686 \r
687                 xStart = xTimeNow;\r
688 \r
689                 /* Sockets need to be checked if the TCP timer has expired. */\r
690                 xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );\r
691 \r
692                 /* Sockets will also be checked if there are TCP messages but the\r
693                 message queue is empty (indicated by xWillSleep being true). */\r
694                 if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )\r
695                 {\r
696                         xCheckTCPSockets = pdTRUE;\r
697                 }\r
698 \r
699                 if( xCheckTCPSockets != pdFALSE )\r
700                 {\r
701                         /* Attend to the sockets, returning the period after which the\r
702                         check must be repeated. */\r
703                         xNextTime = xTCPTimerCheck( xWillSleep );\r
704                         prvIPTimerStart( &xTCPTimer, xNextTime );\r
705                         xProcessedTCPMessage = 0;\r
706                 }\r
707         }\r
708         #endif /* ipconfigUSE_TCP == 1 */\r
709 }\r
710 /*-----------------------------------------------------------*/\r
711 \r
712 static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime )\r
713 {\r
714         vTaskSetTimeOutState( &pxTimer->xTimeOut );\r
715         pxTimer->ulRemainingTime = xTime;\r
716 \r
717         if( xTime == ( TickType_t ) 0 )\r
718         {\r
719                 pxTimer->bExpired = pdTRUE_UNSIGNED;\r
720         }\r
721         else\r
722         {\r
723                 pxTimer->bExpired = pdFALSE_UNSIGNED;\r
724         }\r
725 \r
726         pxTimer->bActive = pdTRUE_UNSIGNED;\r
727 }\r
728 /*-----------------------------------------------------------*/\r
729 \r
730 static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime )\r
731 {\r
732         pxTimer->ulReloadTime = xTime;\r
733         prvIPTimerStart( pxTimer, xTime );\r
734 }\r
735 /*-----------------------------------------------------------*/\r
736 \r
737 static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer )\r
738 {\r
739 BaseType_t xReturn;\r
740 \r
741         if( pxTimer->bActive == pdFALSE_UNSIGNED )\r
742         {\r
743                 /* The timer is not enabled. */\r
744                 xReturn = pdFALSE;\r
745         }\r
746         else\r
747         {\r
748                 /* The timer might have set the bExpired flag already, if not, check the\r
749                 value of xTimeOut against ulRemainingTime. */\r
750                 if( ( pxTimer->bExpired != pdFALSE_UNSIGNED ) ||\r
751                         ( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE ) )\r
752                 {\r
753                         prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );\r
754                         xReturn = pdTRUE;\r
755                 }\r
756                 else\r
757                 {\r
758                         xReturn = pdFALSE;\r
759                 }\r
760         }\r
761 \r
762         return xReturn;\r
763 }\r
764 /*-----------------------------------------------------------*/\r
765 \r
766 void FreeRTOS_NetworkDown( void )\r
767 {\r
768 static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };\r
769 const TickType_t xDontBlock = ( TickType_t ) 0;\r
770 \r
771         /* Simply send the network task the appropriate event. */\r
772         if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )\r
773         {\r
774                 /* Could not send the message, so it is still pending. */\r
775                 xNetworkDownEventPending = pdTRUE;\r
776         }\r
777         else\r
778         {\r
779                 /* Message was sent so it is not pending. */\r
780                 xNetworkDownEventPending = pdFALSE;\r
781         }\r
782 \r
783         iptraceNETWORK_DOWN();\r
784 }\r
785 /*-----------------------------------------------------------*/\r
786 \r
787 BaseType_t FreeRTOS_NetworkDownFromISR( void )\r
788 {\r
789 static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };\r
790 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
791 \r
792         /* Simply send the network task the appropriate event. */\r
793         if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )\r
794         {\r
795                 xNetworkDownEventPending = pdTRUE;\r
796         }\r
797         else\r
798         {\r
799                 xNetworkDownEventPending = pdFALSE;\r
800         }\r
801 \r
802         iptraceNETWORK_DOWN();\r
803 \r
804         return xHigherPriorityTaskWoken;\r
805 }\r
806 /*-----------------------------------------------------------*/\r
807 \r
808 void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )\r
809 {\r
810 NetworkBufferDescriptor_t *pxNetworkBuffer;\r
811 void *pvReturn;\r
812 \r
813         /* Cap the block time.  The reason for this is explained where\r
814         ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official\r
815         FreeRTOSIPConfig.h header file is being used). */\r
816         if( xBlockTimeTicks > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )\r
817         {\r
818                 xBlockTimeTicks = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;\r
819         }\r
820 \r
821         /* Obtain a network buffer with the required amount of storage. */\r
822         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );\r
823 \r
824         if( pxNetworkBuffer != NULL )\r
825         {\r
826                 /* Leave space for the UPD header. */\r
827                 pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );\r
828         }\r
829         else\r
830         {\r
831                 pvReturn = NULL;\r
832         }\r
833 \r
834         return ( void * ) pvReturn;\r
835 }\r
836 /*-----------------------------------------------------------*/\r
837 \r
838 NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer,\r
839         BaseType_t xNewLength )\r
840 {\r
841 NetworkBufferDescriptor_t * pxNewBuffer;\r
842 \r
843         /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.\r
844         The transmit routine wants to have ownership of the network buffer\r
845         descriptor, because it will pass the buffer straight to DMA. */\r
846         pxNewBuffer = pxGetNetworkBufferWithDescriptor( ( size_t ) xNewLength, ( TickType_t ) 0 );\r
847 \r
848         if( pxNewBuffer != NULL )\r
849         {\r
850                 pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;\r
851                 pxNewBuffer->usPort = pxNetworkBuffer->usPort;\r
852                 pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;\r
853                 memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );\r
854         }\r
855 \r
856         return pxNewBuffer;\r
857 }\r
858 /*-----------------------------------------------------------*/\r
859 \r
860 #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
861 \r
862         NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer )\r
863         {\r
864         uint8_t *pucBuffer;\r
865         NetworkBufferDescriptor_t *pxResult;\r
866 \r
867                 if( pvBuffer == NULL )\r
868                 {\r
869                         pxResult = NULL;\r
870                 }\r
871                 else\r
872                 {\r
873                         /* Obtain the network buffer from the zero copy pointer. */\r
874                         pucBuffer = ( uint8_t * ) pvBuffer;\r
875 \r
876                         /* The input here is a pointer to a payload buffer.  Subtract the\r
877                         size of the header in the network buffer, usually 8 + 2 bytes. */\r
878                         pucBuffer -= ipBUFFER_PADDING;\r
879 \r
880                         /* Here a pointer was placed to the network descriptor.  As a\r
881                         pointer is dereferenced, make sure it is well aligned. */\r
882                         if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - ( size_t ) 1 ) ) == ( uint32_t ) 0 )\r
883                         {\r
884                                 pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );\r
885                         }\r
886                         else\r
887                         {\r
888                                 pxResult = NULL;\r
889                         }\r
890                 }\r
891 \r
892                 return pxResult;\r
893         }\r
894 \r
895 #endif /* ipconfigZERO_COPY_TX_DRIVER != 0 */\r
896 /*-----------------------------------------------------------*/\r
897 \r
898 NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer )\r
899 {\r
900 uint8_t *pucBuffer;\r
901 NetworkBufferDescriptor_t *pxResult;\r
902 \r
903         if( pvBuffer == NULL )\r
904         {\r
905                 pxResult = NULL;\r
906         }\r
907         else\r
908         {\r
909                 /* Obtain the network buffer from the zero copy pointer. */\r
910                 pucBuffer = ( uint8_t * ) pvBuffer;\r
911 \r
912                 /* The input here is a pointer to a payload buffer.  Subtract\r
913                 the total size of a UDP/IP header plus the size of the header in\r
914                 the network buffer, usually 8 + 2 bytes. */\r
915                 pucBuffer -= ( sizeof( UDPPacket_t ) + ipBUFFER_PADDING );\r
916 \r
917                 /* Here a pointer was placed to the network descriptor,\r
918                 As a pointer is dereferenced, make sure it is well aligned */\r
919                 if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - 1 ) ) == 0 )\r
920                 {\r
921                         /* The following statement may trigger a:\r
922                         warning: cast increases required alignment of target type [-Wcast-align].\r
923                         It has been confirmed though that the alignment is suitable. */\r
924                         pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );\r
925                 }\r
926                 else\r
927                 {\r
928                         pxResult = NULL;\r
929                 }\r
930         }\r
931 \r
932         return pxResult;\r
933 }\r
934 /*-----------------------------------------------------------*/\r
935 \r
936 void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )\r
937 {\r
938         vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) );\r
939 }\r
940 /*-----------------------------------------------------------*/\r
941 \r
942 /*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */\r
943 /*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high.\r
944  As that bug has been repaired, there is not an urgent reason to warn.\r
945  It is better though to use the advised priority scheme. */\r
946 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
947 {\r
948 BaseType_t xReturn = pdFALSE;\r
949 \r
950         /* This function should only be called once. */\r
951         configASSERT( xIPIsNetworkTaskReady() == pdFALSE );\r
952         configASSERT( xNetworkEventQueue == NULL );\r
953         configASSERT( xIPTaskHandle == NULL );\r
954 \r
955         /* Check structure packing is correct. */\r
956         configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE );\r
957         configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE );\r
958         configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE );\r
959         configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE );\r
960         configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE );\r
961 \r
962         /* Attempt to create the queue used to communicate with the IP task. */\r
963         xNetworkEventQueue = xQueueCreate( ( UBaseType_t ) ipconfigEVENT_QUEUE_LENGTH, ( UBaseType_t ) sizeof( IPStackEvent_t ) );\r
964         configASSERT( xNetworkEventQueue );\r
965 \r
966         if( xNetworkEventQueue != NULL )\r
967         {\r
968                 #if ( configQUEUE_REGISTRY_SIZE > 0 )\r
969                 {\r
970                         /* A queue registry is normally used to assist a kernel aware\r
971                         debugger.  If one is in use then it will be helpful for the debugger\r
972                         to show information about the network event queue. */\r
973                         vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );\r
974                 }\r
975                 #endif /* configQUEUE_REGISTRY_SIZE */\r
976 \r
977                 if( xNetworkBuffersInitialise() == pdPASS )\r
978                 {\r
979                         /* Store the local IP and MAC address. */\r
980                         xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );\r
981                         xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );\r
982                         xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );\r
983                         xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );\r
984                         xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;\r
985 \r
986                         memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) );\r
987 \r
988                         #if ipconfigUSE_DHCP == 1\r
989                         {\r
990                                 /* The IP address is not set until DHCP completes. */\r
991                                 *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;\r
992                         }\r
993                         #else\r
994                         {\r
995                                 /* The IP address is set from the value passed in. */\r
996                                 *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;\r
997 \r
998                                 /* Added to prevent ARP flood to gateway.  Ensure the\r
999                                 gateway is on the same subnet as the IP address. */\r
1000                                 if( xNetworkAddressing.ulGatewayAddress != 0ul )\r
1001                                 {\r
1002                                         configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );\r
1003                                 }\r
1004                         }\r
1005                         #endif /* ipconfigUSE_DHCP == 1 */\r
1006 \r
1007                         /* The MAC address is stored in the start of the default packet\r
1008                         header fragment, which is used when sending UDP packets. */\r
1009                         memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
1010 \r
1011                         /* Prepare the sockets interface. */\r
1012                         vNetworkSocketsInit();\r
1013 \r
1014                         /* Create the task that processes Ethernet and stack events. */\r
1015                         xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t ) ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t ) ipconfigIP_TASK_PRIORITY, &xIPTaskHandle );\r
1016                 }\r
1017                 else\r
1018                 {\r
1019                         FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n") );\r
1020 \r
1021                         /* Clean up. */\r
1022                         vQueueDelete( xNetworkEventQueue );\r
1023                         xNetworkEventQueue = NULL;\r
1024                 }\r
1025         }\r
1026         else\r
1027         {\r
1028                 FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n") );\r
1029         }\r
1030 \r
1031         return xReturn;\r
1032 }\r
1033 /*-----------------------------------------------------------*/\r
1034 \r
1035 void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )\r
1036 {\r
1037         /* Return the address configuration to the caller. */\r
1038 \r
1039         if( pulIPAddress != NULL )\r
1040         {\r
1041                 *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1042         }\r
1043 \r
1044         if( pulNetMask != NULL )\r
1045         {\r
1046                 *pulNetMask = xNetworkAddressing.ulNetMask;\r
1047         }\r
1048 \r
1049         if( pulGatewayAddress != NULL )\r
1050         {\r
1051                 *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;\r
1052         }\r
1053 \r
1054         if( pulDNSServerAddress != NULL )\r
1055         {\r
1056                 *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;\r
1057         }\r
1058 }\r
1059 /*-----------------------------------------------------------*/\r
1060 \r
1061 void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress )\r
1062 {\r
1063         /* Update the address configuration. */\r
1064 \r
1065         if( pulIPAddress != NULL )\r
1066         {\r
1067                 *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress;\r
1068         }\r
1069 \r
1070         if( pulNetMask != NULL )\r
1071         {\r
1072                 xNetworkAddressing.ulNetMask = *pulNetMask;\r
1073         }\r
1074 \r
1075         if( pulGatewayAddress != NULL )\r
1076         {\r
1077                 xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress;\r
1078         }\r
1079 \r
1080         if( pulDNSServerAddress != NULL )\r
1081         {\r
1082                 xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress;\r
1083         }\r
1084 }\r
1085 /*-----------------------------------------------------------*/\r
1086 \r
1087 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1088 \r
1089         BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks )\r
1090         {\r
1091         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
1092         ICMPHeader_t *pxICMPHeader;\r
1093         BaseType_t xReturn = pdFAIL;\r
1094         static uint16_t usSequenceNumber = 0;\r
1095         uint8_t *pucChar;\r
1096         IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };\r
1097 \r
1098                 if( (xNumberOfBytesToSend >= 1 ) && ( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_t ) ) - sizeof( ICMPHeader_t ) ) ) && ( uxGetNumberOfFreeNetworkBuffers() >= 3 ) )\r
1099                 {\r
1100                         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xNumberOfBytesToSend + sizeof( ICMPPacket_t ), xBlockTimeTicks );\r
1101 \r
1102                         if( pxNetworkBuffer != NULL )\r
1103                         {\r
1104                                 pxICMPHeader = ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] );\r
1105                                 usSequenceNumber++;\r
1106 \r
1107                                 /* Fill in the basic header information. */\r
1108                                 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;\r
1109                                 pxICMPHeader->ucTypeOfService = 0;\r
1110                                 pxICMPHeader->usIdentifier = usSequenceNumber;\r
1111                                 pxICMPHeader->usSequenceNumber = usSequenceNumber;\r
1112 \r
1113                                 /* Find the start of the data. */\r
1114                                 pucChar = ( uint8_t * ) pxICMPHeader;\r
1115                                 pucChar += sizeof( ICMPHeader_t );\r
1116 \r
1117                                 /* Just memset the data to a fixed value. */\r
1118                                 memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );\r
1119 \r
1120                                 /* The message is complete, IP and checksum's are handled by\r
1121                                 vProcessGeneratedUDPPacket */\r
1122                                 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;\r
1123                                 pxNetworkBuffer->ulIPAddress = ulIPAddress;\r
1124                                 pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;\r
1125                                 pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPHeader_t );\r
1126 \r
1127                                 /* Send to the stack. */\r
1128                                 xStackTxEvent.pvData = pxNetworkBuffer;\r
1129 \r
1130                                 if( xSendEventStructToIPTask( &xStackTxEvent, xBlockTimeTicks) != pdPASS )\r
1131                                 {\r
1132                                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
1133                                         iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );\r
1134                                 }\r
1135                                 else\r
1136                                 {\r
1137                                         xReturn = usSequenceNumber;\r
1138                                 }\r
1139                         }\r
1140                 }\r
1141                 else\r
1142                 {\r
1143                         /* The requested number of bytes will not fit in the available space\r
1144                         in the network buffer. */\r
1145                 }\r
1146 \r
1147                 return xReturn;\r
1148         }\r
1149 \r
1150 #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */\r
1151 /*-----------------------------------------------------------*/\r
1152 \r
1153 BaseType_t xSendEventToIPTask( eIPEvent_t eEvent )\r
1154 {\r
1155 IPStackEvent_t xEventMessage;\r
1156 const TickType_t xDontBlock = ( TickType_t ) 0;\r
1157 \r
1158         xEventMessage.eEventType = eEvent;\r
1159         xEventMessage.pvData = ( void* )NULL;\r
1160 \r
1161         return xSendEventStructToIPTask( &xEventMessage, xDontBlock );\r
1162 }\r
1163 /*-----------------------------------------------------------*/\r
1164 \r
1165 BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout )\r
1166 {\r
1167 BaseType_t xReturn, xSendMessage;\r
1168 \r
1169         if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) )\r
1170         {\r
1171                 /* Only allow eNetworkDownEvent events if the IP task is not ready\r
1172                 yet.  Not going to attempt to send the message so the send failed. */\r
1173                 xReturn = pdFAIL;\r
1174         }\r
1175         else\r
1176         {\r
1177                 xSendMessage = pdTRUE;\r
1178 \r
1179                 #if( ipconfigUSE_TCP == 1 )\r
1180                 {\r
1181                         if( pxEvent->eEventType == eTCPTimerEvent )\r
1182                         {\r
1183                                 /* TCP timer events are sent to wake the timer task when\r
1184                                 xTCPTimer has expired, but there is no point sending them if the\r
1185                                 IP task is already awake processing other message. */\r
1186                                 xTCPTimer.bExpired = pdTRUE_UNSIGNED;\r
1187 \r
1188                                 if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0u )\r
1189                                 {\r
1190                                         /* Not actually going to send the message but this is not a\r
1191                                         failure as the message didn't need to be sent. */\r
1192                                         xSendMessage = pdFALSE;\r
1193                                 }\r
1194                         }\r
1195                 }\r
1196                 #endif /* ipconfigUSE_TCP */\r
1197 \r
1198                 if( xSendMessage != pdFALSE )\r
1199                 {\r
1200                         /* The IP task cannot block itself while waiting for itself to\r
1201                         respond. */\r
1202                         if( ( xIsCallingFromIPTask() == pdTRUE ) && ( xTimeout > ( TickType_t ) 0 ) )\r
1203                         {\r
1204                                 xTimeout = ( TickType_t ) 0;\r
1205                         }\r
1206 \r
1207                         xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, xTimeout );\r
1208 \r
1209                         if( xReturn == pdFAIL )\r
1210                         {\r
1211                                 /* A message should have been sent to the IP task, but wasn't. */\r
1212                                 FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) );\r
1213                                 iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType );\r
1214                         }\r
1215                 }\r
1216                 else\r
1217                 {\r
1218                         /* It was not necessary to send the message to process the event so\r
1219                         even though the message was not sent the call was successful. */\r
1220                         xReturn = pdPASS;\r
1221                 }\r
1222         }\r
1223 \r
1224         return xReturn;\r
1225 }\r
1226 /*-----------------------------------------------------------*/\r
1227 \r
1228 eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )\r
1229 {\r
1230 eFrameProcessingResult_t eReturn;\r
1231 const EthernetHeader_t *pxEthernetHeader;\r
1232 \r
1233         pxEthernetHeader = ( const EthernetHeader_t * ) pucEthernetBuffer;\r
1234 \r
1235         if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( MACAddress_t ) ) == 0 )\r
1236         {\r
1237                 /* The packet was directed to this node directly - process it. */\r
1238                 eReturn = eProcessBuffer;\r
1239         }\r
1240         else if( memcmp( ( void * ) xBroadcastMACAddress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )\r
1241         {\r
1242                 /* The packet was a broadcast - process it. */\r
1243                 eReturn = eProcessBuffer;\r
1244         }\r
1245         else\r
1246 #if( ipconfigUSE_LLMNR == 1 )\r
1247         if( memcmp( ( void * ) xLLMNR_MacAdress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )\r
1248         {\r
1249                 /* The packet is a request for LLMNR - process it. */\r
1250                 eReturn = eProcessBuffer;\r
1251         }\r
1252         else\r
1253 #endif /* ipconfigUSE_LLMNR */\r
1254         {\r
1255                 /* The packet was not a broadcast, or for this node, just release\r
1256                 the buffer without taking any other action. */\r
1257                 eReturn = eReleaseBuffer;\r
1258         }\r
1259 \r
1260         #if( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 )\r
1261         {\r
1262         uint16_t usFrameType;\r
1263 \r
1264                 if( eReturn == eProcessBuffer )\r
1265                 {\r
1266                         usFrameType = pxEthernetHeader->usFrameType;\r
1267                         usFrameType = FreeRTOS_ntohs( usFrameType );\r
1268 \r
1269                         if( usFrameType <= 0x600U )\r
1270                         {\r
1271                                 /* Not an Ethernet II frame. */\r
1272                                 eReturn = eReleaseBuffer;\r
1273                         }\r
1274                 }\r
1275         }\r
1276         #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1  */\r
1277 \r
1278         return eReturn;\r
1279 }\r
1280 /*-----------------------------------------------------------*/\r
1281 \r
1282 static void prvProcessNetworkDownEvent( void )\r
1283 {\r
1284         /* Stop the ARP timer while there is no network. */\r
1285         xARPTimer.bActive = pdFALSE_UNSIGNED;\r
1286 \r
1287         #if ipconfigUSE_NETWORK_EVENT_HOOK == 1\r
1288         {\r
1289                 static BaseType_t xCallEventHook = pdFALSE;\r
1290 \r
1291                 /* The first network down event is generated by the IP stack itself to\r
1292                 initialise the network hardware, so do not call the network down event\r
1293                 the first time through. */\r
1294                 if( xCallEventHook == pdTRUE )\r
1295                 {\r
1296                         vApplicationIPNetworkEventHook( eNetworkDown );\r
1297                 }\r
1298                 xCallEventHook = pdTRUE;\r
1299         }\r
1300         #endif\r
1301 \r
1302         /* The network has been disconnected (or is being initialised for the first\r
1303         time).  Perform whatever hardware processing is necessary to bring it up\r
1304         again, or wait for it to be available again.  This is hardware dependent. */\r
1305         if( xNetworkInterfaceInitialise() != pdPASS )\r
1306         {\r
1307                 /* Ideally the network interface initialisation function will only\r
1308                 return when the network is available.  In case this is not the case,\r
1309                 wait a while before retrying the initialisation. */\r
1310                 vTaskDelay( ipINITIALISATION_RETRY_DELAY );\r
1311                 FreeRTOS_NetworkDown();\r
1312         }\r
1313         else\r
1314         {\r
1315                 /* Set remaining time to 0 so it will become active immediately. */\r
1316                 #if ipconfigUSE_DHCP == 1\r
1317                 {\r
1318                         /* The network is not up until DHCP has completed. */\r
1319                         vDHCPProcess( pdTRUE );\r
1320                         xSendEventToIPTask( eDHCPEvent );\r
1321                 }\r
1322                 #else\r
1323                 {\r
1324                         /* Perform any necessary 'network up' processing. */\r
1325                         vIPNetworkUpCalls();\r
1326                 }\r
1327                 #endif\r
1328         }\r
1329 }\r
1330 /*-----------------------------------------------------------*/\r
1331 \r
1332 void vIPNetworkUpCalls( void )\r
1333 {\r
1334         xNetworkUp = pdTRUE;\r
1335 \r
1336         #if( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )\r
1337         {\r
1338                 vApplicationIPNetworkEventHook( eNetworkUp );\r
1339         }\r
1340         #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */\r
1341 \r
1342         #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
1343         {\r
1344                 /* The following function is declared in FreeRTOS_DNS.c and 'private' to\r
1345                 this library */\r
1346                 extern void vDNSInitialise( void );\r
1347                 vDNSInitialise();\r
1348         }\r
1349         #endif /* ipconfigDNS_USE_CALLBACKS != 0 */\r
1350 \r
1351         /* Set remaining time to 0 so it will become active immediately. */\r
1352         prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );\r
1353 }\r
1354 /*-----------------------------------------------------------*/\r
1355 \r
1356 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1357 {\r
1358 EthernetHeader_t *pxEthernetHeader;\r
1359 volatile eFrameProcessingResult_t eReturned; /* Volatile to prevent complier warnings when ipCONSIDER_FRAME_FOR_PROCESSING just sets it to eProcessBuffer. */\r
1360 \r
1361         configASSERT( pxNetworkBuffer );\r
1362 \r
1363         /* Interpret the Ethernet frame. */\r
1364         eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );\r
1365         pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1366 \r
1367         if( eReturned == eProcessBuffer )\r
1368         {\r
1369                 /* Interpret the received Ethernet packet. */\r
1370                 switch( pxEthernetHeader->usFrameType )\r
1371                 {\r
1372                         case ipARP_FRAME_TYPE :\r
1373                                 /* The Ethernet frame contains an ARP packet. */\r
1374                                 eReturned = eARPProcessPacket( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );\r
1375                                 break;\r
1376 \r
1377                         case ipIPv4_FRAME_TYPE :\r
1378                                 /* The Ethernet frame contains an IP packet. */\r
1379                                 eReturned = prvProcessIPPacket( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );\r
1380                                 break;\r
1381 \r
1382                         default :\r
1383                                 /* No other packet types are handled.  Nothing to do. */\r
1384                                 eReturned = eReleaseBuffer;\r
1385                                 break;\r
1386                 }\r
1387         }\r
1388 \r
1389         /* Perform any actions that resulted from processing the Ethernet frame. */\r
1390         switch( eReturned )\r
1391         {\r
1392                 case eReturnEthernetFrame :\r
1393                         /* The Ethernet frame will have been updated (maybe it was\r
1394                         an ARP request or a PING request?) and should be sent back to\r
1395                         its source. */\r
1396                         vReturnEthernetFrame( pxNetworkBuffer, pdTRUE );\r
1397                         /* parameter pdTRUE: the buffer must be released once\r
1398                         the frame has been transmitted */\r
1399                         break;\r
1400 \r
1401                 case eFrameConsumed :\r
1402                         /* The frame is in use somewhere, don't release the buffer\r
1403                         yet. */\r
1404                         break;\r
1405 \r
1406                 default :\r
1407                         /* The frame is not being used anywhere, and the\r
1408                         NetworkBufferDescriptor_t structure containing the frame should\r
1409                         just be released back to the list of free buffers. */\r
1410                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
1411                         break;\r
1412         }\r
1413 }\r
1414 /*-----------------------------------------------------------*/\r
1415 \r
1416 static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,\r
1417         NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength )\r
1418 {\r
1419 eFrameProcessingResult_t eReturn = eProcessBuffer;\r
1420 \r
1421 #if( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )\r
1422         const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );\r
1423 #else\r
1424         /* or else, the parameter won't be used and the function will be optimised\r
1425         away */\r
1426         ( void ) pxIPPacket;\r
1427 #endif\r
1428 \r
1429         #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )\r
1430         {\r
1431                 /* In systems with a very small amount of RAM, it might be advantageous\r
1432                 to have incoming messages checked earlier, by the network card driver.\r
1433                 This method may decrease the usage of sparse network buffers. */\r
1434                 uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;\r
1435 \r
1436                         /* Ensure that the incoming packet is not fragmented (fragmentation\r
1437                         was only supported for outgoing packets, and is not currently\r
1438                         not supported at all). */\r
1439                         if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )\r
1440                         {\r
1441                                 /* Can not handle, fragmented packet. */\r
1442                                 eReturn = eReleaseBuffer;\r
1443                         }\r
1444                         /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes\r
1445                          * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */\r
1446                         else if( ( pxIPHeader->ucVersionHeaderLength < 0x45u ) || ( pxIPHeader->ucVersionHeaderLength > 0x4Fu ) )\r
1447                         {\r
1448                                 /* Can not handle, unknown or invalid header version. */\r
1449                                 eReturn = eReleaseBuffer;\r
1450                         }\r
1451                                 /* Is the packet for this IP address? */\r
1452                         else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&\r
1453                                 /* Is it the global broadcast address 255.255.255.255 ? */\r
1454                                 ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) &&\r
1455                                 /* Is it a specific broadcast address 192.168.1.255 ? */\r
1456                                 ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) &&\r
1457                         #if( ipconfigUSE_LLMNR == 1 )\r
1458                                 /* Is it the LLMNR multicast address? */\r
1459                                 ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&\r
1460                         #endif\r
1461                                 /* Or (during DHCP negotiation) we have no IP-address yet? */\r
1462                                 ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )\r
1463                         {\r
1464                                 /* Packet is not for this node, release it */\r
1465                                 eReturn = eReleaseBuffer;\r
1466                         }\r
1467         }\r
1468         #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */\r
1469 \r
1470         #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 )\r
1471         {\r
1472                 /* Some drivers of NIC's with checksum-offloading will enable the above\r
1473                 define, so that the checksum won't be checked again here */\r
1474                 if (eReturn == eProcessBuffer )\r
1475                 {\r
1476                         /* Is the IP header checksum correct? */\r
1477                         if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) &&\r
1478                                 ( usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC ) )\r
1479                         {\r
1480                                 /* Check sum in IP-header not correct. */\r
1481                                 eReturn = eReleaseBuffer;\r
1482                         }\r
1483                         /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */\r
1484                         else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pdFALSE ) != ipCORRECT_CRC )\r
1485                         {\r
1486                                 /* Protocol checksum not accepted. */\r
1487                                 eReturn = eReleaseBuffer;\r
1488                         }\r
1489                 }\r
1490         }\r
1491         #else\r
1492         {\r
1493                 /* to avoid warning unused parameters */\r
1494                 ( void ) pxNetworkBuffer;\r
1495                 ( void ) uxHeaderLength;\r
1496         }\r
1497         #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */\r
1498 \r
1499         return eReturn;\r
1500 }\r
1501 /*-----------------------------------------------------------*/\r
1502 \r
1503 static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
1504 {\r
1505 eFrameProcessingResult_t eReturn;\r
1506 const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );\r
1507 UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 );\r
1508 uint8_t ucProtocol;\r
1509 \r
1510         ucProtocol = pxIPPacket->xIPHeader.ucProtocol;\r
1511         /* Check if the IP headers are acceptable and if it has our destination. */\r
1512         eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );\r
1513 \r
1514         if( eReturn == eProcessBuffer )\r
1515         {\r
1516                 if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )\r
1517                 {\r
1518                         /* All structs of headers expect a IP header size of 20 bytes\r
1519                          * IP header options were included, we'll ignore them and cut them out\r
1520                          * Note: IP options are mostly use in Multi-cast protocols */\r
1521                         const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;\r
1522                         /* From: the previous start of UDP/ICMP/TCP data */\r
1523                         uint8_t *pucSource = ( ( uint8_t * ) pxIPHeader ) + uxHeaderLength;\r
1524                         /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */\r
1525                         uint8_t *pucTarget = ( ( uint8_t * ) pxIPHeader ) + ipSIZE_OF_IPv4_HEADER;\r
1526                         /* How many: total length minus the options and the lower headers */\r
1527                         const size_t  xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER;\r
1528 \r
1529                         memmove( pucTarget, pucSource, xMoveLen );\r
1530                         pxNetworkBuffer->xDataLength -= optlen;\r
1531                 }\r
1532                 /* Add the IP and MAC addresses to the ARP table if they are not\r
1533                 already there - otherwise refresh the age of the existing\r
1534                 entry. */\r
1535                 if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )\r
1536                 {\r
1537                         /* Refresh the ARP cache with the IP/MAC-address of the received packet\r
1538                          * For UDP packets, this will be done later in xProcessReceivedUDPPacket()\r
1539                          * as soon as know that the message will be handled by someone\r
1540                          * This will prevent that the ARP cache will get overwritten\r
1541                          * with the IP-address of useless broadcast packets\r
1542                          */\r
1543                         vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );\r
1544                 }\r
1545                 switch( ucProtocol )\r
1546                 {\r
1547                         case ipPROTOCOL_ICMP :\r
1548                                 /* The IP packet contained an ICMP frame.  Don't bother\r
1549                                 checking the ICMP checksum, as if it is wrong then the\r
1550                                 wrong data will also be returned, and the source of the\r
1551                                 ping will know something went wrong because it will not\r
1552                                 be able to validate what it receives. */\r
1553                                 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1554                                 {\r
1555                                         ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1556                                         if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
1557                                         {\r
1558                                                 eReturn = prvProcessICMPPacket( pxICMPPacket );\r
1559                                         }\r
1560                                 }\r
1561                                 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
1562                                 break;\r
1563 \r
1564                         case ipPROTOCOL_UDP :\r
1565                                 {\r
1566                                         /* The IP packet contained a UDP frame. */\r
1567                                         UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1568 \r
1569                                         /* Note the header values required prior to the\r
1570                                         checksum generation as the checksum pseudo header\r
1571                                         may clobber some of these values. */\r
1572                                         pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t );\r
1573                                         /* HT:endian: fields in pxNetworkBuffer (usPort, ulIPAddress) were network order */\r
1574                                         pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;\r
1575                                         pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;\r
1576 \r
1577                                         /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:\r
1578                                          * In some cases, the upper-layer checksum has been calculated\r
1579                                          * by the NIC driver */\r
1580                                         /* Pass the packet payload to the UDP sockets implementation. */\r
1581                                         /* HT:endian: xProcessReceivedUDPPacket wanted network order */\r
1582                                         if( xProcessReceivedUDPPacket( pxNetworkBuffer, pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )\r
1583                                         {\r
1584                                                 eReturn = eFrameConsumed;\r
1585                                         }\r
1586                                 }\r
1587                                 break;\r
1588 \r
1589 #if ipconfigUSE_TCP == 1\r
1590                         case ipPROTOCOL_TCP :\r
1591                                 {\r
1592 \r
1593                                         if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )\r
1594                                         {\r
1595                                                 eReturn = eFrameConsumed;\r
1596                                         }\r
1597 \r
1598                                         /* Setting this variable will cause xTCPTimerCheck()\r
1599                                         to be called just before the IP-task blocks. */\r
1600                                         xProcessedTCPMessage++;\r
1601                                 }\r
1602                                 break;\r
1603 #endif\r
1604                         default :\r
1605                                 /* Not a supported frame type. */\r
1606                                 break;\r
1607                 }\r
1608         }\r
1609 \r
1610         return eReturn;\r
1611 }\r
1612 /*-----------------------------------------------------------*/\r
1613 \r
1614 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1615 \r
1616         static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket )\r
1617         {\r
1618         ePingReplyStatus_t eStatus = eSuccess;\r
1619         uint16_t usDataLength, usCount;\r
1620         uint8_t *pucByte;\r
1621 \r
1622                 /* Find the total length of the IP packet. */\r
1623                 usDataLength = pxICMPPacket->xIPHeader.usLength;\r
1624                 usDataLength = FreeRTOS_ntohs( usDataLength );\r
1625 \r
1626                 /* Remove the length of the IP headers to obtain the length of the ICMP\r
1627                 message itself. */\r
1628                 usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER );\r
1629 \r
1630                 /* Remove the length of the ICMP header, to obtain the length of\r
1631                 data contained in the ping. */\r
1632                 usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER );\r
1633 \r
1634                 /* Checksum has already been checked before in prvProcessIPPacket */\r
1635 \r
1636                 /* Find the first byte of the data within the ICMP packet. */\r
1637                 pucByte = ( uint8_t * ) pxICMPPacket;\r
1638                 pucByte += sizeof( ICMPPacket_t );\r
1639 \r
1640                 /* Check each byte. */\r
1641                 for( usCount = 0; usCount < usDataLength; usCount++ )\r
1642                 {\r
1643                         if( *pucByte != ipECHO_DATA_FILL_BYTE )\r
1644                         {\r
1645                                 eStatus = eInvalidData;\r
1646                                 break;\r
1647                         }\r
1648 \r
1649                         pucByte++;\r
1650                 }\r
1651 \r
1652                 /* Call back into the application to pass it the result. */\r
1653                 vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );\r
1654         }\r
1655 \r
1656 #endif\r
1657 /*-----------------------------------------------------------*/\r
1658 \r
1659 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
1660 \r
1661         static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket )\r
1662         {\r
1663         ICMPHeader_t *pxICMPHeader;\r
1664         IPHeader_t *pxIPHeader;\r
1665         uint16_t usRequest;\r
1666 \r
1667                 pxICMPHeader = &( pxICMPPacket->xICMPHeader );\r
1668                 pxIPHeader = &( pxICMPPacket->xIPHeader );\r
1669 \r
1670                 /* HT:endian: changed back */\r
1671                 iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );\r
1672 \r
1673                 /* The checksum can be checked here - but a ping reply should be\r
1674                 returned even if the checksum is incorrect so the other end can\r
1675                 tell that the ping was received - even if the ping reply contains\r
1676                 invalid data. */\r
1677                 pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY;\r
1678                 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;\r
1679                 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;\r
1680 \r
1681                 /* Update the checksum because the ucTypeOfMessage member in the header\r
1682                 has been changed to ipICMP_ECHO_REPLY.  This is faster than calling\r
1683                 usGenerateChecksum(). */\r
1684 \r
1685                 /* due to compiler warning "integer operation result is out of range" */\r
1686 \r
1687                 usRequest = ( uint16_t ) ( ( uint16_t )ipICMP_ECHO_REQUEST << 8 );\r
1688 \r
1689                 if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFu - usRequest ) )\r
1690                 {\r
1691                         pxICMPHeader->usChecksum = ( uint16_t )\r
1692                                 ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +\r
1693                                         FreeRTOS_htons( usRequest + 1UL ) );\r
1694                 }\r
1695                 else\r
1696                 {\r
1697                         pxICMPHeader->usChecksum = ( uint16_t )\r
1698                                 ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +\r
1699                                         FreeRTOS_htons( usRequest ) );\r
1700                 }\r
1701                 return eReturnEthernetFrame;\r
1702         }\r
1703 \r
1704 #endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */\r
1705 /*-----------------------------------------------------------*/\r
1706 \r
1707 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1708 \r
1709         static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket )\r
1710         {\r
1711         eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
1712 \r
1713                 iptraceICMP_PACKET_RECEIVED();\r
1714                 switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )\r
1715                 {\r
1716                         case ipICMP_ECHO_REQUEST        :\r
1717                                 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )\r
1718                                 {\r
1719                                         eReturn = prvProcessICMPEchoRequest( pxICMPPacket );\r
1720                                 }\r
1721                                 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */\r
1722                                 break;\r
1723 \r
1724                         case ipICMP_ECHO_REPLY          :\r
1725                                 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )\r
1726                                 {\r
1727                                         prvProcessICMPEchoReply( pxICMPPacket );\r
1728                                 }\r
1729                                 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */\r
1730                                 break;\r
1731 \r
1732                         default :\r
1733                                 break;\r
1734                 }\r
1735 \r
1736                 return eReturn;\r
1737         }\r
1738 \r
1739 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */\r
1740 /*-----------------------------------------------------------*/\r
1741 \r
1742 uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, BaseType_t xOutgoingPacket )\r
1743 {\r
1744 uint32_t ulLength;\r
1745 uint16_t usChecksum, *pusChecksum;\r
1746 const IPPacket_t * pxIPPacket;\r
1747 UBaseType_t uxIPHeaderLength;\r
1748 ProtocolPacket_t *pxProtPack;\r
1749 uint8_t ucProtocol;\r
1750 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1751         const char *pcType;\r
1752 #endif\r
1753 \r
1754         pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;\r
1755         uxIPHeaderLength = ( UBaseType_t ) ( 4u * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); /*_RB_ Why 4? */\r
1756         pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );\r
1757         ucProtocol = pxIPPacket->xIPHeader.ucProtocol;\r
1758 \r
1759         if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )\r
1760         {\r
1761                 pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );\r
1762                 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1763                 {\r
1764                         pcType = "UDP";\r
1765                 }\r
1766                 #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
1767         }\r
1768         else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )\r
1769         {\r
1770                 pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );\r
1771                 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1772                 {\r
1773                         pcType = "TCP";\r
1774                 }\r
1775                 #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
1776         }\r
1777         else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||\r
1778                         ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )\r
1779         {\r
1780                 pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );\r
1781 \r
1782                 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1783                 {\r
1784                         if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )\r
1785                         {\r
1786                                 pcType = "ICMP";\r
1787                         }\r
1788                         else\r
1789                         {\r
1790                                 pcType = "IGMP";\r
1791                         }\r
1792                 }\r
1793                 #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
1794         }\r
1795         else\r
1796         {\r
1797                 /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */\r
1798                 return ipUNHANDLED_PROTOCOL;\r
1799         }\r
1800 \r
1801         if( xOutgoingPacket != pdFALSE )\r
1802         {\r
1803                 /* This is an outgoing packet. Before calculating the checksum, set it\r
1804                 to zero. */\r
1805                 *( pusChecksum ) = 0u;\r
1806         }\r
1807         else if( ( *pusChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )\r
1808         {\r
1809                 /* Sender hasn't set the checksum, no use to calculate it. */\r
1810                 return ipCORRECT_CRC;\r
1811         }\r
1812 \r
1813         ulLength = ( uint32_t )\r
1814                 ( FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) - ( ( uint16_t ) uxIPHeaderLength ) ); /* normally minus 20 */\r
1815 \r
1816         if( ( ulLength < sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ||\r
1817                 ( ulLength > ( uint32_t )( ipconfigNETWORK_MTU - uxIPHeaderLength ) ) )\r
1818         {\r
1819                 #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1820                 {\r
1821                         FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) );\r
1822                 }\r
1823                 #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
1824 \r
1825                 /* Again, in a 16-bit return value there is no space to indicate an\r
1826                 error.  For incoming packets, 0x1234 will cause dropping of the packet.\r
1827                 For outgoing packets, there is a serious problem with the\r
1828                 format/length */\r
1829                 return ipINVALID_LENGTH;\r
1830         }\r
1831         if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP )\r
1832         {\r
1833                 /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */\r
1834                 usChecksum = ( uint16_t )\r
1835                         ( ~usGenerateChecksum( 0UL,\r
1836                                 ( uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) );\r
1837         }\r
1838         else\r
1839         {\r
1840                 /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length\r
1841                 fields */\r
1842                 usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) );\r
1843 \r
1844                 /* And then continue at the IPv4 source and destination addresses. */\r
1845                 usChecksum = ( uint16_t )\r
1846                         ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ),\r
1847                                 ( size_t )( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) );\r
1848 \r
1849                 /* Sum TCP header and data. */\r
1850         }\r
1851 \r
1852         if( xOutgoingPacket == pdFALSE )\r
1853         {\r
1854                 /* This is in incoming packet. If the CRC is correct, it should be zero. */\r
1855                 if( usChecksum == 0u )\r
1856                 {\r
1857                         usChecksum = ( uint16_t )ipCORRECT_CRC;\r
1858                 }\r
1859         }\r
1860         else\r
1861         {\r
1862                 if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )\r
1863                 {\r
1864                         /* In case of UDP, a calculated checksum of 0x0000 is transmitted\r
1865                         as 0xffff. A value of zero would mean that the checksum is not used. */\r
1866                         #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1867                         {\r
1868                                 if( xOutgoingPacket != pdFALSE )\r
1869                                 {\r
1870                                         FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) );\r
1871                                 }\r
1872                         }\r
1873                         #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
1874 \r
1875                         usChecksum = ( uint16_t )0xffffu;\r
1876                 }\r
1877         }\r
1878         usChecksum = FreeRTOS_htons( usChecksum );\r
1879 \r
1880         if( xOutgoingPacket != pdFALSE )\r
1881         {\r
1882                 *( pusChecksum ) = usChecksum;\r
1883         }\r
1884         #if( ipconfigHAS_DEBUG_PRINTF != 0 )\r
1885         else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) )\r
1886         {\r
1887                 FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n",\r
1888                         pcType,\r
1889                         FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ),\r
1890                         FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ),\r
1891                         FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ),\r
1892                         FreeRTOS_ntohs( *pusChecksum ) ) );\r
1893         }\r
1894         #endif  /* ipconfigHAS_DEBUG_PRINTF != 0 */\r
1895 \r
1896         return usChecksum;\r
1897 }\r
1898 /*-----------------------------------------------------------*/\r
1899 \r
1900 uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes )\r
1901 {\r
1902 xUnion32 xSum2, xSum, xTerm;\r
1903 xUnionPtr xSource;              /* Points to first byte */\r
1904 xUnionPtr xLastSource;  /* Points to last byte plus one */\r
1905 uint32_t ulAlignBits, ulCarry = 0ul;\r
1906 \r
1907         /* Small MCUs often spend up to 30% of the time doing checksum calculations\r
1908         This function is optimised for 32-bit CPUs; Each time it will try to fetch\r
1909         32-bits, sums it with an accumulator and counts the number of carries. */\r
1910 \r
1911         /* Swap the input (little endian platform only). */\r
1912         xSum.u32 = FreeRTOS_ntohs( ulSum );\r
1913         xTerm.u32 = 0ul;\r
1914 \r
1915         xSource.u8ptr = ( uint8_t * ) pucNextData;\r
1916         ulAlignBits = ( ( ( uint32_t ) pucNextData ) & 0x03u ); /* gives 0, 1, 2, or 3 */\r
1917 \r
1918         /* If byte (8-bit) aligned... */\r
1919         if( ( ( ulAlignBits & 1ul ) != 0ul ) && ( uxDataLengthBytes >= ( size_t ) 1 ) )\r
1920         {\r
1921                 xTerm.u8[ 1 ] = *( xSource.u8ptr );\r
1922                 ( xSource.u8ptr )++;\r
1923                 uxDataLengthBytes--;\r
1924                 /* Now xSource is word (16-bit) aligned. */\r
1925         }\r
1926 \r
1927         /* If half-word (16-bit) aligned... */\r
1928         if( ( ( ulAlignBits == 1u ) || ( ulAlignBits == 2u ) ) && ( uxDataLengthBytes >= 2u ) )\r
1929         {\r
1930                 xSum.u32 += *(xSource.u16ptr);\r
1931                 ( xSource.u16ptr )++;\r
1932                 uxDataLengthBytes -= 2u;\r
1933                 /* Now xSource is word (32-bit) aligned. */\r
1934         }\r
1935 \r
1936         /* Word (32-bit) aligned, do the most part. */\r
1937         xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4u ) ) - 3u;\r
1938 \r
1939         /* In this loop, four 32-bit additions will be done, in total 16 bytes.\r
1940         Indexing with constants (0,1,2,3) gives faster code than using\r
1941         post-increments. */\r
1942         while( xSource.u32ptr < xLastSource.u32ptr )\r
1943         {\r
1944                 /* Use a secondary Sum2, just to see if the addition produced an\r
1945                 overflow. */\r
1946                 xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];\r
1947                 if( xSum2.u32 < xSum.u32 )\r
1948                 {\r
1949                         ulCarry++;\r
1950                 }\r
1951 \r
1952                 /* Now add the secondary sum to the major sum, and remember if there was\r
1953                 a carry. */\r
1954                 xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];\r
1955                 if( xSum2.u32 > xSum.u32 )\r
1956                 {\r
1957                         ulCarry++;\r
1958                 }\r
1959 \r
1960                 /* And do the same trick once again for indexes 2 and 3 */\r
1961                 xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];\r
1962                 if( xSum2.u32 < xSum.u32 )\r
1963                 {\r
1964                         ulCarry++;\r
1965                 }\r
1966 \r
1967                 xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];\r
1968 \r
1969                 if( xSum2.u32 > xSum.u32 )\r
1970                 {\r
1971                         ulCarry++;\r
1972                 }\r
1973 \r
1974                 /* And finally advance the pointer 4 * 4 = 16 bytes. */\r
1975                 xSource.u32ptr += 4;\r
1976         }\r
1977 \r
1978         /* Now add all carries. */\r
1979         xSum.u32 = ( uint32_t )xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;\r
1980 \r
1981         uxDataLengthBytes %= 16u;\r
1982         xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) );\r
1983 \r
1984         /* Half-word aligned. */\r
1985         while( xSource.u16ptr < xLastSource.u16ptr )\r
1986         {\r
1987                 /* At least one more short. */\r
1988                 xSum.u32 += xSource.u16ptr[ 0 ];\r
1989                 xSource.u16ptr++;\r
1990         }\r
1991 \r
1992         if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0u )        /* Maybe one more ? */\r
1993         {\r
1994                 xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];\r
1995         }\r
1996         xSum.u32 += xTerm.u32;\r
1997 \r
1998         /* Now add all carries again. */\r
1999         xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];\r
2000 \r
2001         /* The previous summation might have given a 16-bit carry. */\r
2002         xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];\r
2003 \r
2004         if( ( ulAlignBits & 1u ) != 0u )\r
2005         {\r
2006                 /* Quite unlikely, but pucNextData might be non-aligned, which would\r
2007                  mean that a checksum is calculated starting at an odd position. */\r
2008                 xSum.u32 = ( ( xSum.u32 & 0xffu ) << 8 ) | ( ( xSum.u32 & 0xff00u ) >> 8 );\r
2009         }\r
2010 \r
2011         /* swap the output (little endian platform only). */\r
2012         return FreeRTOS_htons( ( (uint16_t) xSum.u32 ) );\r
2013 }\r
2014 /*-----------------------------------------------------------*/\r
2015 \r
2016 void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend )\r
2017 {\r
2018 EthernetHeader_t *pxEthernetHeader;\r
2019 \r
2020 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
2021         NetworkBufferDescriptor_t *pxNewBuffer;\r
2022 #endif\r
2023 \r
2024         #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
2025         {\r
2026                 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
2027                 {\r
2028                 BaseType_t xIndex;\r
2029 \r
2030                         FreeRTOS_printf( ( "vReturnEthernetFrame: length %lu\n", ( uint32_t )pxNetworkBuffer->xDataLength ) );\r
2031                         for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )\r
2032                         {\r
2033                                 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;\r
2034                         }\r
2035                         pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;\r
2036                 }\r
2037         }\r
2038         #endif\r
2039 \r
2040 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
2041 \r
2042         if( xReleaseAfterSend == pdFALSE )\r
2043         {\r
2044                 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );\r
2045                 xReleaseAfterSend = pdTRUE;\r
2046                 pxNetworkBuffer = pxNewBuffer;\r
2047         }\r
2048 \r
2049         if( pxNetworkBuffer != NULL )\r
2050 #endif\r
2051         {\r
2052                 pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
2053 \r
2054                 /* Swap source and destination MAC addresses. */\r
2055                 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );\r
2056                 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
2057 \r
2058                 /* Send! */\r
2059                 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );\r
2060         }\r
2061 }\r
2062 /*-----------------------------------------------------------*/\r
2063 \r
2064 uint32_t FreeRTOS_GetIPAddress( void )\r
2065 {\r
2066         /* Returns the IP address of the NIC. */\r
2067         return *ipLOCAL_IP_ADDRESS_POINTER;\r
2068 }\r
2069 /*-----------------------------------------------------------*/\r
2070 \r
2071 void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )\r
2072 {\r
2073         /* Sets the IP address of the NIC. */\r
2074         *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress;\r
2075 }\r
2076 /*-----------------------------------------------------------*/\r
2077 \r
2078 uint32_t FreeRTOS_GetGatewayAddress( void )\r
2079 {\r
2080         return xNetworkAddressing.ulGatewayAddress;\r
2081 }\r
2082 /*-----------------------------------------------------------*/\r
2083 \r
2084 uint32_t FreeRTOS_GetDNSServerAddress( void )\r
2085 {\r
2086         return xNetworkAddressing.ulDNSServerAddress;\r
2087 }\r
2088 /*-----------------------------------------------------------*/\r
2089 \r
2090 uint32_t FreeRTOS_GetNetmask( void )\r
2091 {\r
2092         return xNetworkAddressing.ulNetMask;\r
2093 }\r
2094 /*-----------------------------------------------------------*/\r
2095 \r
2096 void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] )\r
2097 {\r
2098         /* Copy the MAC address at the start of the default packet header fragment. */\r
2099         memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES );\r
2100 }\r
2101 /*-----------------------------------------------------------*/\r
2102 \r
2103 const uint8_t * FreeRTOS_GetMACAddress( void )\r
2104 {\r
2105         return ipLOCAL_MAC_ADDRESS;\r
2106 }\r
2107 /*-----------------------------------------------------------*/\r
2108 \r
2109 void FreeRTOS_SetNetmask ( uint32_t ulNetmask )\r
2110 {\r
2111         xNetworkAddressing.ulNetMask = ulNetmask;\r
2112 }\r
2113 /*-----------------------------------------------------------*/\r
2114 \r
2115 void FreeRTOS_SetGatewayAddress ( uint32_t ulGatewayAddress )\r
2116 {\r
2117         xNetworkAddressing.ulGatewayAddress = ulGatewayAddress;\r
2118 }\r
2119 /*-----------------------------------------------------------*/\r
2120 \r
2121 #if( ipconfigUSE_DHCP == 1 )\r
2122         void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )\r
2123         {\r
2124                 if( xEnableState != pdFALSE )\r
2125                 {\r
2126                         xDHCPTimer.bActive = pdTRUE_UNSIGNED;\r
2127                 }\r
2128                 else\r
2129                 {\r
2130                         xDHCPTimer.bActive = pdFALSE_UNSIGNED;\r
2131                 }\r
2132         }\r
2133 #endif /* ipconfigUSE_DHCP */\r
2134 /*-----------------------------------------------------------*/\r
2135 \r
2136 #if( ipconfigUSE_DHCP == 1 )\r
2137         void vIPReloadDHCPTimer( uint32_t ulLeaseTime )\r
2138         {\r
2139                 prvIPTimerReload( &xDHCPTimer, ulLeaseTime );\r
2140         }\r
2141 #endif /* ipconfigUSE_DHCP */\r
2142 /*-----------------------------------------------------------*/\r
2143 \r
2144 #if( ipconfigDNS_USE_CALLBACKS == 1 )\r
2145         void vIPSetDnsTimerEnableState( BaseType_t xEnableState )\r
2146         {\r
2147                 if( xEnableState != 0 )\r
2148                 {\r
2149                         xDNSTimer.bActive = pdTRUE;\r
2150                 }\r
2151                 else\r
2152                 {\r
2153                         xDNSTimer.bActive = pdFALSE;\r
2154                 }\r
2155         }\r
2156 #endif /* ipconfigUSE_DHCP */\r
2157 /*-----------------------------------------------------------*/\r
2158 \r
2159 #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
2160         void vIPReloadDNSTimer( uint32_t ulCheckTime )\r
2161         {\r
2162                 prvIPTimerReload( &xDNSTimer, ulCheckTime );\r
2163         }\r
2164 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */\r
2165 /*-----------------------------------------------------------*/\r
2166 \r
2167 BaseType_t xIPIsNetworkTaskReady( void )\r
2168 {\r
2169         return xIPTaskInitialised;\r
2170 }\r
2171 /*-----------------------------------------------------------*/\r
2172 \r
2173 BaseType_t FreeRTOS_IsNetworkUp( void )\r
2174 {\r
2175         return xNetworkUp;\r
2176 }\r
2177 /*-----------------------------------------------------------*/\r
2178 \r
2179 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
2180         UBaseType_t uxGetMinimumIPQueueSpace( void )\r
2181         {\r
2182                 return uxQueueMinimumSpace;\r
2183         }\r
2184 #endif\r
2185 /*-----------------------------------------------------------*/\r