xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_IP_Timers.c (revision 2d3f4daa567ffe71aeda2e0f6d0bc02850db0627)
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