1 /*
2 * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "lwip/opt.h"
33
34 #if LWIP_LOWPOWER
35 #include "lwip/priv/tcp_priv.h"
36
37 #include "lwip/def.h"
38 #include "lwip/memp.h"
39 #include "lwip/priv/tcpip_priv.h"
40
41 #include "lwip/ip4_frag.h"
42 #include "lwip/etharp.h"
43 #include "lwip/dhcp.h"
44 #include "lwip/autoip.h"
45 #include "lwip/igmp.h"
46 #include "lwip/dns.h"
47 #include "lwip/nd6.h"
48 #include "lwip/ip6_frag.h"
49 #include "lwip/mld6.h"
50 #include "lwip/dhcp6.h"
51 #include "lwip/sys.h"
52 #include "lwip/pbuf.h"
53 #include "netif/lowpan6.h"
54 #include "lwip/api.h"
55
56 #include "lwip/lowpower.h"
57
58 #define TIMEOUT_MAX 120000 /* two mins */
59 #define SYS_TIMEOUT_WAIT_TICKS 30
60 #define SYS_TIMEOUT_WAIT_TIME_MS 3
61
62 static u32_t g_wake_up_time = TIMEOUT_MAX;
63 static enum lowpower_mod g_lowpower_switch = LOW_TMR_LOWPOWER_MOD;
64 static struct timer_entry *g_timer_header = NULL;
65 static struct timer_mng g_timer_mng = { LOW_TMR_TIMER_HANDLING, 0 };
66 static u32_t g_last_check_timeout = 0;
67
68 static const struct timer_handler lowpower_timer_handler[] = {
69 #if LWIP_TCP
70 /*
71 * The TCP timer is a special case: it does not have to run always and
72 * is triggered to start from TCP using tcp_timer_needed()
73 */
74 {TCP_FAST_INTERVAL, tcp_fasttmr, tcp_fast_tmr_tick TCP_FASTTMR_NAME},
75 {TCP_SLOW_INTERVAL, tcp_slowtmr, tcp_slow_tmr_tick TCP_SLOWTMR_NAME},
76 #endif /* LWIP_TCP */
77
78 #if LWIP_IPV4
79 #if IP_REASSEMBLY
80 {IP_TMR_INTERVAL, ip_reass_tmr, ip_reass_tmr_tick IP_REASSTRM_NAME},
81 #endif /* IP_REASSEMBLY */
82
83 #if LWIP_ARP
84 {ARP_TMR_INTERVAL, etharp_tmr, etharp_tmr_tick ETHARPTMR_NAME},
85 #endif /* LWIP_ARP */
86
87 #if LWIP_DHCP
88 {DHCP_FINE_TIMER_MSECS, dhcp_fine_tmr, dhcp_fine_tmr_tick DHCP_FINETMR_NAME},
89 {DHCP_COARSE_TIMER_MSECS, dhcp_coarse_tmr, dhcp_coarse_tmr_tick DHCP_COARSETMR_NAME},
90 #endif /* LWIP_DHCP */
91
92 #if LWIP_AUTOIP
93 {AUTOIP_TMR_INTERVAL, autoip_tmr, autoip_tmr_tick AUTOIPTMR_NAME},
94 #endif /* LWIP_AUTOIP */
95
96 #if LWIP_IGMP
97 {IGMP_TMR_INTERVAL, igmp_tmr, igmp_tmr_tick IGMPTMR_NAME},
98 #endif /* LWIP_IGMP */
99 #endif /* LWIP_IPV4 */
100
101 #if LWIP_DNS
102 {DNS_TMR_INTERVAL, dns_tmr, dns_tmr_tick DNSTMR_NAME},
103 #endif /* LWIP_DNS */
104
105 #if LWIP_IPV6
106 {ND6_TMR_INTERVAL, nd6_tmr, nd6_tmr_tick ND6TMR_NAME},
107 #if LWIP_IPV6_REASS
108 {IP6_REASS_TMR_INTERVAL, ip6_reass_tmr, ip6_reass_tmr_tick IP6_TREASSTMR_NAME},
109 #endif /* LWIP_IPV6_REASS */
110
111 #if LWIP_IPV6_MLD
112 {MLD6_TMR_INTERVAL, mld6_tmr, mld6_tmr_tick MLD6TMR_NAME},
113 #endif /* LWIP_IPV6_MLD */
114
115 #if LWIP_IPV6_DHCP6
116 {DHCP6_TIMER_MSECS, dhcp6_tmr, dhcp6_tmr_tick DHCP6TMR_NAME},
117 #endif /* LWIP_IPV6_DHCP6 */
118
119 #if LWIP_6LOWPAN
120 {LOWPAN6_TMR_INTERVAL, lowpan6_tmr, lowpan6_tmr_tick LOWPAN6TMR_NAME},
121 #endif /* LWIP_6LOWPAN */
122 #endif /* LWIP_IPV6 */
123 };
124
125 void
set_timer_state(enum timer_state state,u32_t waiting_time)126 set_timer_state(enum timer_state state, u32_t waiting_time)
127 {
128 g_timer_mng.waiting_time = waiting_time;
129 g_timer_mng.state = state;
130 }
131
132 /* should not call by tcpip_thread */
133 u8_t
sys_timeout_waiting_long(void)134 sys_timeout_waiting_long(void)
135 {
136 u8_t i = 0;
137 u8_t j = 0;
138
139 while (g_timer_mng.state == LOW_TMR_GETING_TICKS) {
140 i++;
141 if (i == SYS_TIMEOUT_WAIT_TICKS) {
142 i = 0;
143 j++;
144 if (j == SYS_TIMEOUT_WAIT_TIME_MS) {
145 break;
146 }
147 sys_msleep(1);
148 }
149 }
150
151 if (g_timer_mng.state == LOW_TMR_TIMER_WAITING) {
152 return ((g_timer_mng.waiting_time > TIMEOUT_TICK) ? 1 : 0);
153 }
154
155 return 0;
156 }
157
158 err_t
sys_timeout_reg(u32_t msec,sys_timeout_handler handler,void * arg,char * name,get_next_timeout next_tick)159 sys_timeout_reg(
160 u32_t msec,
161 sys_timeout_handler handler,
162 void *arg,
163 #if LOWPOWER_TIMER_DEBUG
164 char *name,
165 #endif
166 get_next_timeout next_tick)
167 {
168 struct timer_entry *timeout = NULL;
169 struct timer_entry *temp = NULL;
170
171 if (handler == NULL) {
172 return -1;
173 }
174
175 timeout = (struct timer_entry *)memp_malloc(MEMP_SYS_TIMEOUT);
176 if (timeout == NULL) {
177 LWIP_DEBUGF(LOWPOWER_DEBUG, ("sys_timeout_reg: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty"));
178 return -1;
179 }
180
181 timeout->handler = handler;
182 timeout->clock_max = msec / TIMEOUT_TICK; /* time interval */
183 timeout->next_tick = next_tick;
184 timeout->timeout = sys_now();
185 timeout->args = arg;
186 timeout->enable = 0;
187
188 #if LOWPOWER_TIMER_DEBUG
189 timeout->name = name;
190 #endif
191
192 /* add list tail */
193 timeout->next = NULL;
194 if (g_timer_header == NULL) {
195 g_timer_header = timeout;
196 } else {
197 temp = g_timer_header;
198 while (temp->next != NULL) {
199 temp = temp->next;
200 }
201 temp->next = timeout;
202 }
203
204 return 0;
205 }
206
207 /* deal timeout and return next timer prev */
208 static void
timeout_handler(struct timer_entry * t,u32_t now)209 timeout_handler(struct timer_entry *t, u32_t now)
210 {
211 #if LOWPOWER_TIMER_DEBUG
212 if (t->name != NULL) {
213 LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s timeout: now:%u\n", t->name, now));
214 }
215 #endif
216
217 t->handler(t->args);
218 LWIP_UNUSED_ARG(now);
219 t->timeout += t->clock_max * TIMEOUT_TICK;
220 }
221
222 static u32_t
get_timer_tick(struct timer_entry * t)223 get_timer_tick(struct timer_entry *t)
224 {
225 u32_t tick;
226
227 /* disable lowpower, need to timeout once a tick */
228 if (g_lowpower_switch == LOW_TMR_NORMAL_MOD) {
229 return t->clock_max;
230 }
231
232 if (t->next_tick != NULL) {
233 tick = t->next_tick();
234 } else {
235 tick = 1;
236 LWIP_DEBUGF(LOWPOWER_DEBUG, ("next->tick is NULL\n"));
237 }
238 tick *= t->clock_max;
239 return tick;
240 }
241
242 static void
handle_timer_and_free(struct timer_entry ** pt,struct timer_entry ** pn,struct timer_entry * p)243 handle_timer_and_free(struct timer_entry **pt, struct timer_entry **pn, struct timer_entry *p)
244 {
245 struct timer_entry *t = *pt;
246 struct timer_entry *n = *pn;
247 /* insert after previous node or as the header */
248 if (p == NULL) {
249 g_timer_header = n;
250 } else {
251 p->next = n;
252 }
253
254 t->next = NULL;
255 sys_timeout_handler handler = t->handler;
256 void *args = t->args;
257 memp_free(MEMP_SYS_TIMEOUT, t);
258 *pt = NULL;
259 handler(args);
260
261 /* the last entry */
262 if ((n == NULL) && (p != NULL)) {
263 *pn = p->next;
264 }
265 }
266
267 static u32_t
get_sleep_time(u32_t now)268 get_sleep_time(u32_t now)
269 {
270 struct timer_entry *t = NULL;
271 struct timer_entry *n = NULL;
272 struct timer_entry *p = NULL;
273 u32_t msec = TIMEOUT_MAX;
274 u32_t tick;
275 u32_t temp;
276
277 LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n*******get_sleep_time*****************\n"));
278
279 for (t = g_timer_header, p = NULL; t != NULL; t = n) {
280 n = t->next;
281 again:
282 tick = get_timer_tick(t);
283 if (tick == 0) {
284 t->enable = 0;
285 p = t;
286 continue;
287 }
288
289 if (t->enable == 0) {
290 t->timeout = now;
291 }
292 t->enable = 1;
293 temp = tick * TIMEOUT_TICK;
294
295 if (temp <= now - t->timeout) {
296 if (t->next_tick == NULL) {
297 handle_timer_and_free(&t, &n, p);
298 /* t is free p=p */
299 continue;
300 }
301 timeout_handler(t, now);
302 goto again;
303 }
304
305 temp = temp - (now - t->timeout);
306 msec = msec > temp ? temp : msec;
307 p = t;
308 }
309
310 LWIP_DEBUGF(LOWPOWER_DEBUG, ("msec = %u now = %u\n", msec, now));
311 return msec;
312 }
313
314 static void
check_timeout(u32_t now)315 check_timeout(u32_t now)
316 {
317 struct timer_entry *t = NULL;
318 struct timer_entry *n = NULL;
319 struct timer_entry *p = NULL;
320 u32_t msec;
321 u32_t ticks;
322 u32_t i;
323
324 LWIP_DEBUGF(LOWPOWER_DEBUG, ("\n**********timeout**************\n"));
325 LWIP_DEBUGF(LOWPOWER_DEBUG, ("now = %u\n", now));
326
327 for (t = g_timer_header, p = NULL; t != NULL; t = n) {
328 n = t->next;
329 if (t->enable == 0) {
330 p = t;
331 continue;
332 }
333
334 msec = now - t->timeout;
335 ticks = msec / TIMEOUT_TICK;
336 ticks = ticks / t->clock_max;
337
338 for (i = 0; i < ticks; i++) {
339 /* remove timer_entry form list */
340 if (t->next_tick == NULL) {
341 handle_timer_and_free(&t, &n, p);
342 break;
343 }
344 timeout_handler(t, now);
345 PBUF_CHECK_FREE_OOSEQ();
346 }
347 if (t != NULL) {
348 p = t;
349 }
350 }
351 }
352
353 void
tcpip_timeouts_mbox_fetch(sys_mbox_t * mbox,void ** msg)354 tcpip_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
355 {
356 u32_t sleeptime;
357 u32_t ret;
358 u32_t now;
359
360 again:
361 if (g_timer_header == NULL) {
362 UNLOCK_TCPIP_CORE();
363 (void)sys_arch_mbox_fetch(mbox, msg, 0);
364 LOCK_TCPIP_CORE();
365 return;
366 }
367
368 set_timer_state(LOW_TMR_GETING_TICKS, 0);
369 sleeptime = get_sleep_time(sys_now());
370 sleeptime = sleeptime > sys_timeout_get_wake_time() ? sys_timeout_get_wake_time() : sleeptime;
371 set_timer_state(LOW_TMR_TIMER_WAITING, sleeptime);
372
373 sys_timeout_set_wake_time(TIMEOUT_MAX);
374 UNLOCK_TCPIP_CORE();
375 ret = sys_arch_mbox_fetch(mbox, msg, sleeptime);
376 LOCK_TCPIP_CORE();
377 set_timer_state(LOW_TMR_TIMER_HANDLING, 0);
378 now = sys_now();
379 if ((now - g_last_check_timeout) >= TIMEOUT_CHECK) {
380 check_timeout(sys_now());
381 g_last_check_timeout = sys_now();
382 }
383
384 if (ret == SYS_ARCH_TIMEOUT) {
385 goto again;
386 }
387 }
388
389 void
lowpower_cycle_tmr(void * args)390 lowpower_cycle_tmr(void *args)
391 {
392 struct timer_handler *handler = (struct timer_handler *)args;
393
394 handler->handler();
395 }
396
397 err_t
set_timer_interval(u8_t i,u32_t interval)398 set_timer_interval(u8_t i, u32_t interval)
399 {
400 if (i >= LWIP_ARRAYSIZE(lowpower_timer_handler)) {
401 return -1;
402 }
403 return sys_timeout_reg(interval, lowpower_cycle_tmr,
404 (void *)(&lowpower_timer_handler[i]),
405 #if LOWPOWER_TIMER_DEBUG
406 lowpower_timer_handler[i].name,
407 #endif
408 lowpower_timer_handler[i].next_tick);
409 }
410
411 /* registed when init */
412 void
tcp_timer_needed(void)413 tcp_timer_needed(void)
414 {}
415
416 void
sys_timeouts_init(void)417 sys_timeouts_init(void)
418 {
419 u8_t i;
420
421 for (i = 0; i < LWIP_ARRAYSIZE(lowpower_timer_handler); i++) {
422 if (set_timer_interval(i, lowpower_timer_handler[i].interval) != 0) {
423 LWIP_DEBUGF(LOWPOWER_DEBUG, ("ERROR:regist timer faild! i = %u\n", i));
424 }
425 }
426 }
427
428 void
sys_untimeout(sys_timeout_handler handler,void * arg)429 sys_untimeout(sys_timeout_handler handler, void *arg)
430 {
431 struct timer_entry *t = NULL;
432 struct timer_entry *p = NULL;
433 struct timer_entry *n = NULL;
434
435 for (t = g_timer_header, p = NULL; t != NULL; t = n) {
436 n = t->next;
437 if ((t->handler == handler) && (t->args == arg)) {
438 if (p == NULL) {
439 g_timer_header = t->next;
440 } else {
441 p->next = t->next;
442 }
443 t->next = NULL;
444 memp_free(MEMP_SYS_TIMEOUT, t);
445 t = NULL;
446 }
447 if (t != NULL) {
448 p = t;
449 }
450 }
451 }
452 void
sys_restart_timeouts(void)453 sys_restart_timeouts(void)
454 {}
455
456 err_t
sys_timeout(u32_t msecs,sys_timeout_handler handler,void * arg)457 sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
458 {
459 return sys_timeout_reg(msecs, handler, arg,
460 #if LOWPOWER_TIMER_DEBUG
461 NULL,
462 #endif
463 NULL);
464 }
465
466 void
sys_timeout_set_wake_time(u32_t val)467 sys_timeout_set_wake_time(u32_t val)
468 {
469 g_wake_up_time = val;
470 }
471
472 u32_t
sys_timeout_get_wake_time(void)473 sys_timeout_get_wake_time(void)
474 {
475 return g_wake_up_time;
476 }
477
478 void
set_lowpower_mod(enum lowpower_mod sw)479 set_lowpower_mod(enum lowpower_mod sw)
480 {
481 g_lowpower_switch = sw;
482 }
483
484 enum lowpower_mod
get_lowpowper_mod(void)485 get_lowpowper_mod(void)
486 {
487 return g_lowpower_switch;
488 }
489 #endif /* LWIP_LOWPOWER */
490