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