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