xref: /FreeRTOS-Plus-TCP-v3.1.0/source/FreeRTOS_IP_Timers.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
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_ICMP.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_UDP_IP.h"
52 #include "FreeRTOS_DHCP.h"
53 #include "NetworkInterface.h"
54 #include "NetworkBufferManagement.h"
55 #include "FreeRTOS_DNS.h"
56 
57 /*
58  * Utility functions for the light weight IP timers.
59  */
60 static void prvIPTimerStart( IPTimer_t * pxTimer,
61                              TickType_t xTime );
62 static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer );
63 static void prvIPTimerReload( IPTimer_t * pxTimer,
64                               TickType_t xTime );
65 
66 /*
67  * A timer for each of the following processes, all of which need attention on a
68  * regular basis
69  */
70 
71 /** @brief Timer to limit the maximum time a packet should be stored while
72  *         awaiting an ARP resolution. */
73 static IPTimer_t xARPResolutionTimer;
74 
75 /** @brief ARP timer, to check its table entries. */
76 static IPTimer_t xARPTimer;
77 #if ( ipconfigUSE_DHCP != 0 )
78     /** @brief DHCP timer, to send requests and to renew a reservation.  */
79     static IPTimer_t xDHCPTimer;
80 #endif
81 #if ( ipconfigUSE_TCP != 0 )
82     /** @brief TCP timer, to check for timeouts, resends. */
83     static IPTimer_t xTCPTimer;
84 #endif
85 #if ( ipconfigDNS_USE_CALLBACKS != 0 )
86     /** @brief DNS timer, to check for timeouts when looking-up a domain. */
87     static IPTimer_t xDNSTimer;
88 #endif
89 
90 /**
91  * @brief Calculate the maximum sleep time remaining. It will go through all
92  *        timers to see which timer will expire first. That will be the amount
93  *        of time to block in the next call to xQueueReceive().
94  *
95  * @return The maximum sleep time or ipconfigMAX_IP_TASK_SLEEP_TIME,
96  *         whichever is smaller.
97  */
xCalculateSleepTime(void)98 TickType_t xCalculateSleepTime( void )
99 {
100     TickType_t uxMaximumSleepTime;
101 
102     /* Start with the maximum sleep time, then check this against the remaining
103      * time in any other timers that are active. */
104     uxMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
105 
106     if( xARPTimer.bActive != pdFALSE_UNSIGNED )
107     {
108         if( xARPTimer.ulRemainingTime < uxMaximumSleepTime )
109         {
110             uxMaximumSleepTime = xARPTimer.ulRemainingTime;
111         }
112     }
113 
114     #if ( ipconfigUSE_DHCP == 1 )
115         {
116             if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )
117             {
118                 if( xDHCPTimer.ulRemainingTime < uxMaximumSleepTime )
119                 {
120                     uxMaximumSleepTime = xDHCPTimer.ulRemainingTime;
121                 }
122             }
123         }
124     #endif /* ipconfigUSE_DHCP */
125 
126     #if ( ipconfigUSE_TCP == 1 )
127         {
128             if( xTCPTimer.bActive != pdFALSE_UNSIGNED )
129             {
130                 if( xTCPTimer.ulRemainingTime < uxMaximumSleepTime )
131                 {
132                     uxMaximumSleepTime = xTCPTimer.ulRemainingTime;
133                 }
134             }
135         }
136     #endif
137 
138     #if ( ipconfigDNS_USE_CALLBACKS != 0 )
139         {
140             if( xDNSTimer.bActive != pdFALSE_UNSIGNED )
141             {
142                 if( xDNSTimer.ulRemainingTime < uxMaximumSleepTime )
143                 {
144                     uxMaximumSleepTime = xDNSTimer.ulRemainingTime;
145                 }
146             }
147         }
148     #endif
149 
150     return uxMaximumSleepTime;
151 }
152 /*-----------------------------------------------------------*/
153 
154 /**
155  * @brief Check the network timers (ARP/DHCP/DNS/TCP) and if they are
156  *        expired, send an event to the IP-Task.
157  */
vCheckNetworkTimers(void)158 void vCheckNetworkTimers( void )
159 {
160     /* Is it time for ARP processing? */
161     if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
162     {
163         ( void ) xSendEventToIPTask( eARPTimerEvent );
164     }
165 
166     /* Is the ARP resolution timer expired? */
167     if( prvIPTimerCheck( &xARPResolutionTimer ) != pdFALSE )
168     {
169         if( pxARPWaitingNetworkBuffer != NULL )
170         {
171             /* Disable the ARP resolution timer. */
172             vIPSetARPResolutionTimerEnableState( pdFALSE );
173 
174             /* We have waited long enough for the ARP response. Now, free the network
175              * buffer. */
176             vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer );
177 
178             /* Clear the pointer. */
179             pxARPWaitingNetworkBuffer = NULL;
180 
181             iptraceDELAYED_ARP_TIMER_EXPIRED();
182         }
183     }
184 
185     #if ( ipconfigUSE_DHCP == 1 )
186         {
187             /* Is it time for DHCP processing? */
188             if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )
189             {
190                 ( void ) xSendDHCPEvent();
191             }
192         }
193     #endif /* ipconfigUSE_DHCP */
194 
195     #if ( ipconfigDNS_USE_CALLBACKS != 0 )
196         {
197             /* Is it time for DNS processing? */
198             if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
199             {
200                 vDNSCheckCallBack( NULL );
201             }
202         }
203     #endif /* ipconfigDNS_USE_CALLBACKS */
204 
205     #if ( ipconfigUSE_TCP == 1 )
206         {
207             BaseType_t xWillSleep;
208             TickType_t xNextTime;
209             BaseType_t xCheckTCPSockets;
210 
211             /* If the IP task has messages waiting to be processed then
212              * it will not sleep in any case. */
213             if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0U )
214             {
215                 xWillSleep = pdTRUE;
216             }
217             else
218             {
219                 xWillSleep = pdFALSE;
220             }
221 
222             /* Sockets need to be checked if the TCP timer has expired. */
223             xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
224 
225             /* Sockets will also be checked if there are TCP messages but the
226             * message queue is empty (indicated by xWillSleep being true). */
227             if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )
228             {
229                 xCheckTCPSockets = pdTRUE;
230             }
231 
232             if( xCheckTCPSockets != pdFALSE )
233             {
234                 /* Attend to the sockets, returning the period after which the
235                  * check must be repeated. */
236                 xNextTime = xTCPTimerCheck( xWillSleep );
237                 prvIPTimerStart( &xTCPTimer, xNextTime );
238                 xProcessedTCPMessage = 0;
239             }
240         }
241 
242         /* See if any socket was planned to be closed. */
243         vSocketCloseNextTime( NULL );
244 
245         /* See if any reusable socket needs to go back to 'eTCP_LISTEN' state. */
246         vSocketListenNextTime( NULL );
247     #endif /* ipconfigUSE_TCP == 1 */
248 }
249 /*-----------------------------------------------------------*/
250 
251 /**
252  * @brief Start an IP timer. The IP-task has its own implementation of a timer
253  *        called 'IPTimer_t', which is based on the FreeRTOS 'TimeOut_t'.
254  *
255  * @param[in] pxTimer: Pointer to the IP timer. When zero, the timer is marked
256  *                     as expired.
257  * @param[in] xTime: Time to be loaded into the IP timer.
258  */
prvIPTimerStart(IPTimer_t * pxTimer,TickType_t xTime)259 static void prvIPTimerStart( IPTimer_t * pxTimer,
260                              TickType_t xTime )
261 {
262     vTaskSetTimeOutState( &pxTimer->xTimeOut );
263     pxTimer->ulRemainingTime = xTime;
264 
265     if( xTime == ( TickType_t ) 0 )
266     {
267         pxTimer->bExpired = pdTRUE_UNSIGNED;
268     }
269     else
270     {
271         pxTimer->bExpired = pdFALSE_UNSIGNED;
272     }
273 
274     pxTimer->bActive = pdTRUE_UNSIGNED;
275 }
276 /*-----------------------------------------------------------*/
277 
vIPTimerStartARPResolution(TickType_t xTime)278 void vIPTimerStartARPResolution( TickType_t xTime )
279 {
280     prvIPTimerStart( &( xARPResolutionTimer ), xTime );
281 }
282 /*-----------------------------------------------------------*/
283 
284 /**
285  * @brief Sets the reload time of an IP timer and restarts it.
286  *
287  * @param[in] pxTimer: Pointer to the IP timer.
288  * @param[in] xTime: Time to be reloaded into the IP timer.
289  */
prvIPTimerReload(IPTimer_t * pxTimer,TickType_t xTime)290 static void prvIPTimerReload( IPTimer_t * pxTimer,
291                               TickType_t xTime )
292 {
293     pxTimer->ulReloadTime = xTime;
294     prvIPTimerStart( pxTimer, xTime );
295 }
296 /*-----------------------------------------------------------*/
297 
298 #if ( ipconfigUSE_TCP == 1 )
vTCPTimerReload(TickType_t xTime)299     void vTCPTimerReload( TickType_t xTime )
300     {
301         prvIPTimerReload( &xTCPTimer, xTime );
302     }
303 #endif
304 /*-----------------------------------------------------------*/
305 
vARPTimerReload(TickType_t xTime)306 void vARPTimerReload( TickType_t xTime )
307 {
308     prvIPTimerReload( &xARPTimer, xTime );
309 }
310 /*-----------------------------------------------------------*/
311 
312 #if ( ipconfigUSE_DHCP == 1 )
313 
314 /**
315  * @brief Reload the DHCP timer.
316  *
317  * @param[in] ulLeaseTime: The reload value.
318  */
vDHCPTimerReload(TickType_t xLeaseTime)319     void vDHCPTimerReload( TickType_t xLeaseTime )
320     {
321         prvIPTimerReload( &xDHCPTimer, xLeaseTime );
322     }
323 #endif /* ipconfigUSE_DHCP */
324 /*-----------------------------------------------------------*/
325 
326 #if ( ipconfigDNS_USE_CALLBACKS != 0 )
327 
328 /**
329  * @brief Reload the DNS timer.
330  *
331  * @param[in] ulCheckTime: The reload value.
332  */
vDNSTimerReload(uint32_t ulCheckTime)333     void vDNSTimerReload( uint32_t ulCheckTime )
334     {
335         prvIPTimerReload( &xDNSTimer, ulCheckTime );
336     }
337 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
338 /*-----------------------------------------------------------*/
339 
340 /**
341  * @brief Check the IP timer to see whether an IP event should be processed or not.
342  *
343  * @param[in] pxTimer: Pointer to the IP timer.
344  *
345  * @return If the timer is expired then pdTRUE is returned. Else pdFALSE.
346  */
prvIPTimerCheck(IPTimer_t * pxTimer)347 static BaseType_t prvIPTimerCheck( IPTimer_t * pxTimer )
348 {
349     BaseType_t xReturn;
350 
351     if( pxTimer->bActive == pdFALSE_UNSIGNED )
352     {
353         /* The timer is not enabled. */
354         xReturn = pdFALSE;
355     }
356     else
357     {
358         /* The timer might have set the bExpired flag already, if not, check the
359          * value of xTimeOut against ulRemainingTime. */
360         if( pxTimer->bExpired == pdFALSE_UNSIGNED )
361         {
362             if( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE )
363             {
364                 pxTimer->bExpired = pdTRUE_UNSIGNED;
365             }
366         }
367 
368         if( pxTimer->bExpired != pdFALSE_UNSIGNED )
369         {
370             prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
371             xReturn = pdTRUE;
372         }
373         else
374         {
375             xReturn = pdFALSE;
376         }
377     }
378 
379     return xReturn;
380 }
381 /*-----------------------------------------------------------*/
382 
383 #if ( ipconfigUSE_TCP == 1 )
384 
385 /**
386  * @brief Enable/disable the TCP timer.
387  *
388  * @param[in] xExpiredState: pdTRUE - set as expired; pdFALSE - set as non-expired.
389  */
vIPSetTCPTimerExpiredState(BaseType_t xExpiredState)390     void vIPSetTCPTimerExpiredState( BaseType_t xExpiredState )
391     {
392         xTCPTimer.bActive = pdTRUE_UNSIGNED;
393 
394         if( xExpiredState != pdFALSE )
395         {
396             xTCPTimer.bExpired = pdTRUE_UNSIGNED;
397         }
398         else
399         {
400             xTCPTimer.bExpired = pdFALSE_UNSIGNED;
401         }
402     }
403 /*-----------------------------------------------------------*/
404 #endif /* if ( ipconfigUSE_TCP == 1 ) */
405 
406 /**
407  * @brief Enable/disable the ARP timer.
408  *
409  * @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
410  */
vIPSetARPTimerEnableState(BaseType_t xEnableState)411 void vIPSetARPTimerEnableState( BaseType_t xEnableState )
412 {
413     if( xEnableState != pdFALSE )
414     {
415         xARPTimer.bActive = pdTRUE_UNSIGNED;
416     }
417     else
418     {
419         xARPTimer.bActive = pdFALSE_UNSIGNED;
420     }
421 }
422 /*-----------------------------------------------------------*/
423 
424 /**
425  * @brief Enable or disable the ARP resolution timer.
426  *
427  * @param[in] xEnableState: pdTRUE if the timer must be enabled, pdFALSE otherwise.
428  */
vIPSetARPResolutionTimerEnableState(BaseType_t xEnableState)429 void vIPSetARPResolutionTimerEnableState( BaseType_t xEnableState )
430 {
431     if( xEnableState != pdFALSE )
432     {
433         xARPResolutionTimer.bActive = pdTRUE_UNSIGNED;
434     }
435     else
436     {
437         xARPResolutionTimer.bActive = pdFALSE_UNSIGNED;
438     }
439 }
440 /*-----------------------------------------------------------*/
441 
442 #if ( ipconfigUSE_DHCP == 1 )
443 
444 /**
445  * @brief Enable/disable the DHCP timer.
446  *
447  * @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
448  */
vIPSetDHCPTimerEnableState(BaseType_t xEnableState)449     void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )
450     {
451         if( xEnableState != pdFALSE )
452         {
453             xDHCPTimer.bActive = pdTRUE_UNSIGNED;
454         }
455         else
456         {
457             xDHCPTimer.bActive = pdFALSE_UNSIGNED;
458         }
459     }
460 #endif /* ipconfigUSE_DHCP */
461 /*-----------------------------------------------------------*/
462 
463 #if ( ipconfigDNS_USE_CALLBACKS == 1 )
464 
465 /**
466  * @brief Enable/disable the DNS timer.
467  *
468  * @param[in] xEnableState: pdTRUE - enable timer; pdFALSE - disable timer.
469  */
vIPSetDNSTimerEnableState(BaseType_t xEnableState)470     void vIPSetDNSTimerEnableState( BaseType_t xEnableState )
471     {
472         if( xEnableState != 0 )
473         {
474             xDNSTimer.bActive = pdTRUE_UNSIGNED;
475         }
476         else
477         {
478             xDNSTimer.bActive = pdFALSE_UNSIGNED;
479         }
480     }
481 
482 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */
483 /*-----------------------------------------------------------*/
484