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