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