1 /*
2 * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 /**
29 * @file FreeRTOS_IP_Timers.c
30 * @brief Implements the Internet Control Message Protocol for the FreeRTOS+TCP network stack.
31 */
32
33 /* Standard includes. */
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <string.h>
37
38 /* FreeRTOS includes. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 #include "queue.h"
42 #include "semphr.h"
43
44 /* FreeRTOS+TCP includes. */
45 #include "FreeRTOS_IP.h"
46 #include "FreeRTOS_IP_Timers.h"
47 #include "FreeRTOS_IP_Utils.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "FreeRTOS_ARP.h"
51 #include "FreeRTOS_ND.h"
52 #include "FreeRTOS_UDP_IP.h"
53 #include "FreeRTOS_DHCP.h"
54 #include "NetworkInterface.h"
55 #include "NetworkBufferManagement.h"
56 #include "FreeRTOS_Routing.h"
57 #include "FreeRTOS_DNS.h"
58 /*-----------------------------------------------------------*/
59
60 /** @brief 'xAllNetworksUp' becomes pdTRUE as soon as all network interfaces have
61 * been initialised. */
62 /* MISRA Ref 8.9.1 [File scoped variables] */
63 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
64 /* coverity[misra_c_2012_rule_8_9_violation] */
65 static BaseType_t xAllNetworksUp = pdFALSE;
66
67 /*-----------------------------------------------------------*/
68
69 /*
70 * Utility functions for the light weight IP timers.
71 */
72
73 /**
74 * Start an IP timer. The IP-task has its own implementation of a timer
75 * called 'IPTimer_t', which is based on the FreeRTOS 'TimeOut_t'.
76 */
77 static void prvIPTimerStart( IPTimer_t * pxTimer,
78 TickType_t xTime );
79
80 /**
81 * Check the IP timer to see whether an IP event should be processed or not.
82 */
83 static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer );
84
85 /**
86 * Sets the reload time of an IP timer and restarts it.
87 */
88 static void prvIPTimerReload( IPTimer_t * pxTimer,
89 TickType_t xTime );
90 /*-----------------------------------------------------------*/
91
92 /*
93 * A timer for each of the following processes, all of which need attention on a
94 * regular basis
95 */
96
97 /** @brief Timer to limit the maximum time a packet should be stored while
98 * awaiting an ARP resolution. */
99 static IPTimer_t xARPResolutionTimer;
100
101 /** @brief ARP timer, to check its table entries. */
102 static IPTimer_t xARPTimer;
103
104 #if ( ipconfigUSE_TCP != 0 )
105 /** @brief TCP timer, to check for timeouts, resends. */
106 static IPTimer_t xTCPTimer;
107 #endif
108 #if ( ipconfigDNS_USE_CALLBACKS != 0 )
109 /** @brief DNS timer, to check for timeouts when looking-up a domain. */
110 static IPTimer_t xDNSTimer;
111 #endif
112
113 /** @brief As long as not all networks are up, repeat initialisation by calling the
114 * xNetworkInterfaceInitialise() function of the interfaces that are not ready. */
115
116 /* MISRA Ref 8.9.1 [File scoped variables] */
117 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
118 /* coverity[misra_c_2012_rule_8_9_violation] */
119 static IPTimer_t xNetworkTimer;
120 struct xNetworkEndpoint;
121
122 /*-----------------------------------------------------------*/
123
124 /**
125 * @brief Calculate the maximum sleep time remaining. It will go through all
126 * timers to see which timer will expire first. That will be the amount
127 * of time to block in the next call to xQueueReceive().
128 *
129 * @return The maximum sleep time or ipconfigMAX_IP_TASK_SLEEP_TIME,
130 * whichever is smaller.
131 */
xCalculateSleepTime(void)132 TickType_t xCalculateSleepTime( void )
133 {
134 TickType_t uxMaximumSleepTime;
135
136 /* Start with the maximum sleep time, then check this against the remaining
137 * time in any other timers that are active. */
138 uxMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
139
140 if( xARPTimer.bActive != pdFALSE_UNSIGNED )
141 {
142 if( xARPTimer.ulRemainingTime < uxMaximumSleepTime )
143 {
144 uxMaximumSleepTime = xARPTimer.ulRemainingTime;
145 }
146 }
147
148 #if ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 )
149 {
150 const NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
151
152 while( pxEndPoint != NULL )
153 {
154 if( pxEndPoint->xDHCP_RATimer.bActive != pdFALSE_UNSIGNED )
155 {
156 if( pxEndPoint->xDHCP_RATimer.ulRemainingTime < uxMaximumSleepTime )
157 {
158 uxMaximumSleepTime = pxEndPoint->xDHCP_RATimer.ulRemainingTime;
159 }
160 }
161
162 pxEndPoint = pxEndPoint->pxNext;
163 }
164 }
165 #endif /* ipconfigUSE_DHCP */
166
167 #if ( ipconfigUSE_TCP == 1 )
168 {
169 if( xTCPTimer.bActive != pdFALSE_UNSIGNED )
170 {
171 if( xTCPTimer.ulRemainingTime < uxMaximumSleepTime )
172 {
173 uxMaximumSleepTime = xTCPTimer.ulRemainingTime;
174 }
175 }
176 }
177 #endif
178
179 #if ( ipconfigDNS_USE_CALLBACKS != 0 )
180 {
181 if( xDNSTimer.bActive != pdFALSE_UNSIGNED )
182 {
183 if( xDNSTimer.ulRemainingTime < uxMaximumSleepTime )
184 {
185 uxMaximumSleepTime = xDNSTimer.ulRemainingTime;
186 }
187 }
188 }
189 #endif
190
191 return uxMaximumSleepTime;
192 }
193 /*-----------------------------------------------------------*/
194
195 /**
196 * @brief Check the network timers (ARP/DHCP/DNS/TCP) and if they are
197 * expired, send an event to the IP-Task.
198 */
199 /* MISRA Ref 8.9.1 [File scoped variables] */
200 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
201 /* coverity[misra_c_2012_rule_8_9_violation] */
202 /* coverity[single_use] */
vCheckNetworkTimers(void)203 void vCheckNetworkTimers( void )
204 {
205 NetworkInterface_t * pxInterface;
206
207 /* Is it time for ARP processing? */
208 if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
209 {
210 ( void ) xSendEventToIPTask( eARPTimerEvent );
211 }
212
213 /* Is the ARP resolution timer expired? */
214 if( prvIPTimerCheck( &xARPResolutionTimer ) != pdFALSE )
215 {
216 if( pxARPWaitingNetworkBuffer != NULL )
217 {
218 /* Disable the ARP resolution timer. */
219 vIPSetARPResolutionTimerEnableState( pdFALSE );
220
221 /* We have waited long enough for the ARP response. Now, free the network
222 * buffer. */
223 vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer );
224
225 /* Clear the pointer. */
226 pxARPWaitingNetworkBuffer = NULL;
227
228 iptraceDELAYED_ARP_TIMER_EXPIRED();
229 }
230 }
231
232 #if ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 )
233 {
234 /* Is it time for DHCP processing? */
235 NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
236
237 while( pxEndPoint != NULL )
238 {
239 if( prvIPTimerCheck( &( pxEndPoint->xDHCP_RATimer ) ) != pdFALSE )
240 {
241 #if ( ipconfigUSE_DHCP == 1 )
242 if( END_POINT_USES_DHCP( pxEndPoint ) )
243 {
244 ( void ) xSendDHCPEvent( pxEndPoint );
245 }
246 #endif /* ( ipconfigUSE_DHCP == 1 ) */
247
248 #if ( ( ipconfigUSE_RA != 0 ) && ( ipconfigUSE_IPv6 != 0 ) )
249 if( END_POINT_USES_RA( pxEndPoint ) )
250 {
251 vRAProcess( pdFALSE, pxEndPoint );
252 }
253 #endif /* ( ipconfigUSE_RA != 0 ) */
254 }
255
256 pxEndPoint = pxEndPoint->pxNext;
257 }
258 }
259 #endif /* ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA != 0 ) */
260
261 #if ( ipconfigDNS_USE_CALLBACKS != 0 )
262 {
263 /* Is it time for DNS processing? */
264 if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
265 {
266 vDNSCheckCallBack( NULL );
267 }
268 }
269 #endif /* ipconfigDNS_USE_CALLBACKS */
270
271 #if ( ipconfigUSE_TCP == 1 )
272 {
273 BaseType_t xWillSleep;
274 TickType_t xNextTime;
275 BaseType_t xCheckTCPSockets;
276
277 /* If the IP task has messages waiting to be processed then
278 * it will not sleep in any case. */
279 if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0U )
280 {
281 xWillSleep = pdTRUE;
282 }
283 else
284 {
285 xWillSleep = pdFALSE;
286 }
287
288 /* Sockets need to be checked if the TCP timer has expired. */
289 xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
290
291 /* Sockets will also be checked if there are TCP messages but the
292 * message queue is empty (indicated by xWillSleep being true). */
293 if( xWillSleep != pdFALSE )
294 {
295 xCheckTCPSockets = pdTRUE;
296 }
297
298 if( xCheckTCPSockets != pdFALSE )
299 {
300 /* Attend to the sockets, returning the period after which the
301 * check must be repeated. */
302 xNextTime = xTCPTimerCheck( xWillSleep );
303 prvIPTimerStart( &xTCPTimer, xNextTime );
304 xProcessedTCPMessage = 0;
305 }
306 }
307
308 /* See if any socket was planned to be closed. */
309 vSocketCloseNextTime( NULL );
310
311 /* See if any reusable socket needs to go back to 'eTCP_LISTEN' state. */
312 vSocketListenNextTime( NULL );
313 #endif /* ipconfigUSE_TCP == 1 */
314
315 /* Is it time to trigger the repeated NetworkDown events? */
316 if( xAllNetworksUp == pdFALSE )
317 {
318 if( prvIPTimerCheck( &( xNetworkTimer ) ) != pdFALSE )
319 {
320 BaseType_t xUp = pdTRUE;
321
322 for( pxInterface = pxNetworkInterfaces; pxInterface != NULL; pxInterface = pxInterface->pxNext )
323 {
324 if( pxInterface->bits.bInterfaceUp == pdFALSE_UNSIGNED )
325 {
326 xUp = pdFALSE;
327 FreeRTOS_NetworkDown( pxInterface );
328 }
329 }
330
331 xAllNetworksUp = xUp;
332 }
333 }
334 }
335 /*-----------------------------------------------------------*/
336
337 /**
338 * @brief Start an IP timer. The IP-task has its own implementation of a timer
339 * called 'IPTimer_t', which is based on the FreeRTOS 'TimeOut_t'.
340 *
341 * @param[in] pxTimer Pointer to the IP timer. When zero, the timer is marked
342 * as expired.
343 * @param[in] xTime Time to be loaded into the IP timer.
344 */
prvIPTimerStart(IPTimer_t * pxTimer,TickType_t xTime)345 static void prvIPTimerStart( IPTimer_t * pxTimer,
346 TickType_t xTime )
347 {
348 vTaskSetTimeOutState( &pxTimer->xTimeOut );
349 pxTimer->ulRemainingTime = xTime;
350
351 if( xTime == ( TickType_t ) 0 )
352 {
353 pxTimer->bExpired = pdTRUE_UNSIGNED;
354 }
355 else
356 {
357 pxTimer->bExpired = pdFALSE_UNSIGNED;
358 }
359
360 pxTimer->bActive = pdTRUE_UNSIGNED;
361 }
362 /*-----------------------------------------------------------*/
363
364 /**
365 * @brief Start an ARP Resolution timer.
366 *
367 * @param[in] xTime Time to be loaded into the ARP Resolution timer.
368 */
vIPTimerStartARPResolution(TickType_t xTime)369 void vIPTimerStartARPResolution( TickType_t xTime )
370 {
371 prvIPTimerStart( &( xARPResolutionTimer ), xTime );
372 }
373 /*-----------------------------------------------------------*/
374
375 /**
376 * @brief Sets the reload time of an IP timer and restarts it.
377 *
378 * @param[in] pxTimer Pointer to the IP timer.
379 * @param[in] xTime Time to be reloaded into the IP timer.
380 */
prvIPTimerReload(IPTimer_t * pxTimer,TickType_t xTime)381 static void prvIPTimerReload( IPTimer_t * pxTimer,
382 TickType_t xTime )
383 {
384 pxTimer->ulReloadTime = xTime;
385 prvIPTimerStart( pxTimer, xTime );
386 }
387 /*-----------------------------------------------------------*/
388
389 #if ( ipconfigUSE_TCP == 1 )
390
391 /**
392 * @brief Sets the reload time of the TCP timer and restarts it.
393 *
394 * @param[in] xTime Time to be reloaded into the TCP timer.
395 */
vTCPTimerReload(TickType_t xTime)396 void vTCPTimerReload( TickType_t xTime )
397 {
398 prvIPTimerReload( &xTCPTimer, xTime );
399 }
400 #endif
401 /*-----------------------------------------------------------*/
402
403 /**
404 * @brief Sets the reload time of the ARP timer and restarts it.
405 *
406 * @param[in] xTime Time to be reloaded into the ARP timer.
407 */
vARPTimerReload(TickType_t xTime)408 void vARPTimerReload( TickType_t xTime )
409 {
410 prvIPTimerReload( &xARPTimer, xTime );
411 }
412
413 /*-----------------------------------------------------------*/
414
415 #if ( ipconfigDNS_USE_CALLBACKS != 0 )
416
417 /**
418 * @brief Reload the DNS timer.
419 *
420 * @param[in] ulCheckTime The reload value.
421 */
vDNSTimerReload(uint32_t ulCheckTime)422 void vDNSTimerReload( uint32_t ulCheckTime )
423 {
424 prvIPTimerReload( &xDNSTimer, ulCheckTime );
425 }
426 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
427 /*-----------------------------------------------------------*/
428
429 #if ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 )
430
431 /**
432 * @brief Set the reload time of the DHCP/DHCPv6/RA timer.
433 *
434 * @param[in] pxEndPoint The end-point that needs to acquire an IP-address.
435 * @param[in] uxClockTicks The number of clock-ticks after which the timer should expire.
436 */
437
vDHCP_RATimerReload(NetworkEndPoint_t * pxEndPoint,TickType_t uxClockTicks)438 void vDHCP_RATimerReload( NetworkEndPoint_t * pxEndPoint,
439 TickType_t uxClockTicks )
440 {
441 FreeRTOS_printf( ( "vDHCP_RATimerReload: %lu\n", uxClockTicks ) );
442 prvIPTimerReload( &( pxEndPoint->xDHCP_RATimer ), uxClockTicks );
443 }
444 #endif /* ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 ) */
445 /*-----------------------------------------------------------*/
446
447 /**
448 * @brief Reload the Network timer.
449 *
450 * @param[in] xTime Time to be reloaded into the Network timer.
451 */
vNetworkTimerReload(TickType_t xTime)452 void vNetworkTimerReload( TickType_t xTime )
453 {
454 prvIPTimerReload( &xNetworkTimer, xTime );
455 }
456 /*-----------------------------------------------------------*/
457
458 /**
459 * @brief Check the IP timer to see whether an IP event should be processed or not.
460 *
461 * @param[in] pxTimer Pointer to the IP timer.
462 *
463 * @return If the timer is expired then pdTRUE is returned. Else pdFALSE.
464 */
prvIPTimerCheck(IPTimer_t * pxTimer)465 static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer )
466 {
467 BaseType_t xReturn;
468
469 if( pxTimer->bActive == pdFALSE_UNSIGNED )
470 {
471 /* The timer is not enabled. */
472 xReturn = pdFALSE;
473 }
474 else
475 {
476 /* The timer might have set the bExpired flag already, if not, check the
477 * value of xTimeOut against ulRemainingTime. */
478 if( pxTimer->bExpired == pdFALSE_UNSIGNED )
479 {
480 if( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE )
481 {
482 pxTimer->bExpired = pdTRUE_UNSIGNED;
483 }
484 }
485
486 if( pxTimer->bExpired != pdFALSE_UNSIGNED )
487 {
488 prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
489 xReturn = pdTRUE;
490 }
491 else
492 {
493 xReturn = pdFALSE;
494 }
495 }
496
497 return xReturn;
498 }
499 /*-----------------------------------------------------------*/
500
501 #if ( ipconfigUSE_TCP == 1 )
502
503 /**
504 * @brief Enable/disable the TCP timer.
505 *
506 * @param[in] xExpiredState pdTRUE - set as expired; pdFALSE - set as non-expired.
507 */
vIPSetTCPTimerExpiredState(BaseType_t xExpiredState)508 void vIPSetTCPTimerExpiredState( BaseType_t xExpiredState )
509 {
510 xTCPTimer.bActive = pdTRUE_UNSIGNED;
511
512 if( xExpiredState != pdFALSE )
513 {
514 xTCPTimer.bExpired = pdTRUE_UNSIGNED;
515 }
516 else
517 {
518 xTCPTimer.bExpired = pdFALSE_UNSIGNED;
519 }
520 }
521 #endif /* if ( ipconfigUSE_TCP == 1 ) */
522 /*-----------------------------------------------------------*/
523
524 /**
525 * @brief Enable/disable the ARP timer.
526 *
527 * @param[in] xEnableState pdTRUE - enable timer; pdFALSE - disable timer.
528 */
vIPSetARPTimerEnableState(BaseType_t xEnableState)529 void vIPSetARPTimerEnableState( BaseType_t xEnableState )
530 {
531 if( xEnableState != pdFALSE )
532 {
533 xARPTimer.bActive = pdTRUE_UNSIGNED;
534 }
535 else
536 {
537 xARPTimer.bActive = pdFALSE_UNSIGNED;
538 }
539 }
540 /*-----------------------------------------------------------*/
541
542 /**
543 * @brief Enable or disable the ARP resolution timer.
544 *
545 * @param[in] xEnableState pdTRUE if the timer must be enabled, pdFALSE otherwise.
546 */
vIPSetARPResolutionTimerEnableState(BaseType_t xEnableState)547 void vIPSetARPResolutionTimerEnableState( BaseType_t xEnableState )
548 {
549 if( xEnableState != pdFALSE )
550 {
551 xARPResolutionTimer.bActive = pdTRUE_UNSIGNED;
552 }
553 else
554 {
555 xARPResolutionTimer.bActive = pdFALSE_UNSIGNED;
556 }
557 }
558 /*-----------------------------------------------------------*/
559
560 #if ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 ) || ( ipconfigUSE_DHCPv6 == 1 )
561
562 /**
563 * @brief Enable or disable the DHCP/DHCPv6/RA timer.
564 *
565 * @param[in] pxEndPoint The end-point that needs to acquire an IP-address.
566 * @param[in] xEnableState pdTRUE if the timer must be enabled, pdFALSE otherwise.
567 */
vIPSetDHCP_RATimerEnableState(NetworkEndPoint_t * pxEndPoint,BaseType_t xEnableState)568 void vIPSetDHCP_RATimerEnableState( NetworkEndPoint_t * pxEndPoint,
569 BaseType_t xEnableState )
570 {
571 FreeRTOS_printf( ( "vIPSetDHCP_RATimerEnableState: %s\n", ( xEnableState != 0 ) ? "On" : "Off" ) );
572
573 /* 'xDHCP_RATimer' is shared between DHCP (IPv4) and RA/SLAAC (IPv6). */
574 if( xEnableState != 0 )
575 {
576 pxEndPoint->xDHCP_RATimer.bActive = pdTRUE_UNSIGNED;
577 }
578 else
579 {
580 pxEndPoint->xDHCP_RATimer.bActive = pdFALSE_UNSIGNED;
581 }
582 }
583 #endif /* if ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 ) || ( ipconfigUSE_DHCPv6 == 1 ) */
584 /*-----------------------------------------------------------*/
585
586 #if ( ipconfigDNS_USE_CALLBACKS == 1 )
587
588 /**
589 * @brief Enable/disable the DNS timer.
590 *
591 * @param[in] xEnableState pdTRUE - enable timer; pdFALSE - disable timer.
592 */
vIPSetDNSTimerEnableState(BaseType_t xEnableState)593 void vIPSetDNSTimerEnableState( BaseType_t xEnableState )
594 {
595 if( xEnableState != 0 )
596 {
597 xDNSTimer.bActive = pdTRUE_UNSIGNED;
598 }
599 else
600 {
601 xDNSTimer.bActive = pdFALSE_UNSIGNED;
602 }
603 }
604
605 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */
606 /*-----------------------------------------------------------*/
607