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