• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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