1 /*
2 * Event loop based on select() loop
3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include <assert.h>
10
11 #include "common.h"
12 #include "trace.h"
13 #include "list.h"
14 #include "eloop_ltos.h"
15 #include "wpa_supplicant_if.h"
16 #include "hostapd_if.h"
17 #include "wifi_api.h"
18 #include "wpa_supplicant/ctrl_iface.h"
19 #include "securec.h"
20
21 #define ELOOP_TIMEOUT_REGISTERED 1
22 #ifndef OSS_TICKS_PER_SEC
23 #define OSS_TICKS_PER_SEC 100
24 #endif
25 #define TICKS_TO_MSEC(ticks) (((ticks) * 1000) / OSS_TICKS_PER_SEC)
26 #define MSEC_TO_TICKS(ms) (((ms) * OSS_TICKS_PER_SEC) / 1000)
27
28 struct eloop_timeout {
29 struct dl_list list;
30 struct os_reltime time;
31 void *eloop_data;
32 void *user_data;
33 eloop_timeout_handler handler;
34 WPA_TRACE_REF(eloop);
35 WPA_TRACE_REF(user);
36 WPA_TRACE_INFO
37 };
38
39 struct eloop_message {
40 struct dl_list list;
41 char *buf;
42 };
43
44 static struct eloop_data eloop;
45
eloop_init(eloop_task_type eloop_task)46 int eloop_init(eloop_task_type eloop_task)
47 {
48 if ((eloop_task != ELOOP_TASK_WPA) && (eloop_task != ELOOP_TASK_HOSTAPD))
49 return EXT_WIFI_FAIL;
50
51 if (eloop.events != NULL)
52 return EXT_WIFI_OK;
53 (void)os_memset(&eloop, 0, sizeof(eloop));
54 (void)os_event_init(&eloop.levent, WIFI_EVENT_ELOOP);
55 dl_list_init(&eloop.timeout);
56
57 int ret = os_mux_create(&eloop.mutex_handle);
58 if (ret != WIFI_OS_OK) {
59 wpa_error_log0(MSG_ERROR, "---> eloop_init MuxCreate fail.");
60 return EXT_WIFI_FAIL;
61 }
62 eloop.events = os_zalloc(sizeof(struct eloop_event) * ELOOP_MAX_EVENTS);
63 if (eloop.events == NULL) {
64 (void)os_mux_delete(eloop.mutex_handle);
65 return EXT_WIFI_FAIL;
66 }
67 return EXT_WIFI_OK;
68 }
69
eloop_register_timeout(unsigned int secs,unsigned int usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)70 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
71 eloop_timeout_handler handler,
72 void *eloop_data, void *user_data)
73 {
74 struct eloop_timeout *timeout = NULL;
75 struct eloop_timeout *tmp = NULL;
76 os_time_t now_sec;
77 if (handler == NULL)
78 return EXT_WIFI_FAIL;
79 timeout = os_zalloc(sizeof(*timeout));
80 if (timeout == NULL)
81 return EXT_WIFI_FAIL;
82 if (os_get_reltime(&timeout->time) < 0) {
83 os_free(timeout);
84 return EXT_WIFI_FAIL;
85 }
86 now_sec = timeout->time.sec;
87 timeout->time.sec += (os_time_t)secs;
88 if (timeout->time.sec < now_sec) {
89 /*
90 * Integer overflow - assume long enough timeout to be assumed
91 * to be infinite, i.e., the timeout would never happen.
92 */
93 os_free(timeout);
94 return EXT_WIFI_OK;
95 }
96 timeout->time.usec += (os_time_t)usecs;
97 while (timeout->time.usec >= 1000000) {
98 timeout->time.sec++;
99 timeout->time.usec -= 1000000;
100 }
101 timeout->eloop_data = eloop_data;
102 timeout->user_data = user_data;
103 timeout->handler = handler;
104 wpa_trace_add_ref(timeout, eloop, eloop_data);
105 wpa_trace_add_ref(timeout, user, user_data);
106 wpa_trace_record(timeout);
107
108 /* Maintain timeouts in order of increasing time */
109 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
110 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
111 if (os_reltime_before(&timeout->time, &tmp->time)) {
112 dl_list_add(tmp->list.prev, &timeout->list);
113 (void)os_mux_post(eloop.mutex_handle);
114 return EXT_WIFI_OK;
115 }
116 }
117 dl_list_add_tail(&eloop.timeout, &timeout->list);
118 (void)os_mux_post(eloop.mutex_handle);
119 return EXT_WIFI_OK;
120 }
121
eloop_remove_timeout(struct eloop_timeout * timeout)122 static void eloop_remove_timeout(struct eloop_timeout *timeout)
123 {
124 if (timeout == NULL)
125 return;
126 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
127 dl_list_del(&timeout->list);
128 (void)os_mux_post(eloop.mutex_handle);
129
130 wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
131 wpa_trace_remove_ref(timeout, user, timeout->user_data);
132 os_free(timeout);
133 }
134
eloop_cancel_timeout(eloop_timeout_handler handler,void * eloop_data,void * user_data)135 int eloop_cancel_timeout(eloop_timeout_handler handler,
136 void *eloop_data, void *user_data)
137 {
138 struct eloop_timeout *timeout = NULL;
139 struct eloop_timeout *prev = NULL;
140 int removed = 0;
141
142 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
143 dl_list_for_each_safe(timeout, prev, &eloop.timeout,
144 struct eloop_timeout, list) {
145 if (timeout->handler == handler &&
146 (timeout->eloop_data == eloop_data ||
147 eloop_data == ELOOP_ALL_CTX) &&
148 (timeout->user_data == user_data ||
149 user_data == ELOOP_ALL_CTX)) {
150 eloop_remove_timeout(timeout);
151 removed++;
152 }
153 }
154 (void)os_mux_post(eloop.mutex_handle);
155
156 return removed;
157 }
158
eloop_cancel_timeout_one(eloop_timeout_handler handler,void * eloop_data,void * user_data,struct os_reltime * remaining)159 int eloop_cancel_timeout_one(eloop_timeout_handler handler,
160 void *eloop_data, void *user_data,
161 struct os_reltime *remaining)
162 {
163 struct eloop_timeout *timeout = NULL;
164 struct eloop_timeout *prev = NULL;
165 int removed = 0;
166 struct os_reltime now;
167
168 (void)os_get_reltime(&now);
169 if (remaining == NULL)
170 return EXT_WIFI_FAIL;
171 remaining->sec = 0;
172 remaining->usec = 0;
173
174 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
175 dl_list_for_each_safe(timeout, prev, &eloop.timeout,
176 struct eloop_timeout, list) {
177 if (timeout->handler == handler &&
178 (timeout->eloop_data == eloop_data) &&
179 (timeout->user_data == user_data)) {
180 removed = 1;
181 if (os_reltime_before(&now, &timeout->time))
182 os_reltime_sub(&timeout->time, &now, remaining);
183 eloop_remove_timeout(timeout);
184 break;
185 }
186 }
187 (void)os_mux_post(eloop.mutex_handle);
188 return removed;
189 }
190
eloop_is_timeout_registered(eloop_timeout_handler handler,void * eloop_data,void * user_data)191 int eloop_is_timeout_registered(eloop_timeout_handler handler,
192 void *eloop_data, void *user_data)
193 {
194 struct eloop_timeout *tmp = NULL;
195
196 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
197 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
198 if (tmp->handler == handler &&
199 tmp->eloop_data == eloop_data &&
200 tmp->user_data == user_data) {
201 (void)os_mux_post(eloop.mutex_handle);
202 return ELOOP_TIMEOUT_REGISTERED;
203 }
204 }
205 (void)os_mux_post(eloop.mutex_handle);
206 return EXT_WIFI_OK;
207 }
208
eloop_deplete_timeout(unsigned int req_secs,unsigned int req_usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)209 int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
210 eloop_timeout_handler handler, void *eloop_data,
211 void *user_data)
212 {
213 struct os_reltime now;
214 struct os_reltime requested;
215 struct os_reltime remaining;
216 struct eloop_timeout *tmp = NULL;
217
218 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
219 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
220 if (tmp->handler == handler &&
221 tmp->eloop_data == eloop_data &&
222 tmp->user_data == user_data) {
223 requested.sec = (os_time_t)req_secs;
224 requested.usec = (os_time_t)req_usecs;
225 (void)os_get_reltime(&now);
226 os_reltime_sub(&tmp->time, &now, &remaining);
227 if (os_reltime_before(&requested, &remaining)) {
228 (void)eloop_cancel_timeout(handler, eloop_data,
229 user_data);
230 (void)eloop_register_timeout(requested.sec,
231 requested.usec,
232 handler, eloop_data,
233 user_data);
234 (void)os_mux_post(eloop.mutex_handle);
235 return ELOOP_TIMEOUT_REGISTERED;
236 }
237 (void)os_mux_post(eloop.mutex_handle);
238 return EXT_WIFI_OK;
239 }
240 }
241 (void)os_mux_post(eloop.mutex_handle);
242 return EXT_WIFI_FAIL;
243 }
244
eloop_replenish_timeout(unsigned int req_secs,unsigned int req_usecs,eloop_timeout_handler handler,void * eloop_data,void * user_data)245 int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
246 eloop_timeout_handler handler, void *eloop_data,
247 void *user_data)
248 {
249 struct os_reltime now;
250 struct os_reltime requested;
251 struct os_reltime remaining;
252 struct eloop_timeout *tmp = NULL;
253
254 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
255 dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
256 if (tmp->handler == handler &&
257 tmp->eloop_data == eloop_data &&
258 tmp->user_data == user_data) {
259 requested.sec = (os_time_t)req_secs;
260 requested.usec = (os_time_t)req_usecs;
261 (void)os_get_reltime(&now);
262 os_reltime_sub(&tmp->time, &now, &remaining);
263 if (os_reltime_before(&remaining, &requested)) {
264 (void)eloop_cancel_timeout(handler, eloop_data,
265 user_data);
266 (void)eloop_register_timeout(requested.sec,
267 requested.usec,
268 handler, eloop_data,
269 user_data);
270 (void)os_mux_post(eloop.mutex_handle);
271 return ELOOP_TIMEOUT_REGISTERED;
272 }
273 (void)os_mux_post(eloop.mutex_handle);
274 return EXT_WIFI_OK;
275 }
276 }
277 (void)os_mux_post(eloop.mutex_handle);
278 return EXT_WIFI_FAIL;
279 }
280
eloop_timeout_event_process(struct eloop_timeout * timeout)281 static inline void eloop_timeout_event_process(struct eloop_timeout *timeout)
282 {
283 void *eloop_data = timeout->eloop_data;
284 void *user_data = timeout->user_data;
285 eloop_timeout_handler handler = timeout->handler;
286 eloop_remove_timeout(timeout);
287 if (handler != NULL)
288 handler(eloop_data, user_data);
289 }
290
eloop_run_process_timeout_event(void)291 static inline void eloop_run_process_timeout_event(void)
292 {
293 struct eloop_timeout *timeout = NULL;
294 struct os_reltime now;
295 /* check if some registered timeouts have occurred */
296 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list);
297 if (timeout != NULL) {
298 (void)os_get_reltime(&now);
299 if (!os_reltime_before(&now, &timeout->time))
300 eloop_timeout_event_process(timeout);
301 }
302 }
303
eloop_run(eloop_task_type eloop_task)304 int eloop_run(eloop_task_type eloop_task)
305 {
306 unsigned long time;
307 struct os_reltime tv;
308 struct os_reltime now;
309 int start_flag = WPA_FLAG_ON;
310
311 if (eloop_task >= ELOOP_MAX_TASK_TYPE_NUM)
312 return EXT_WIFI_FAIL;
313
314 if (eloop_start_running(eloop_task) != ELOOP_NOT_RUNNING)
315 return ELOOP_ALREADY_RUNNING;
316
317 while (global_eloop_is_running()) {
318 unsigned int ret_flags;
319 struct eloop_timeout *timeout = NULL;
320 if (start_flag) {
321 start_flag = WPA_FLAG_OFF;
322 (void)os_event_write(g_wpa_event, WPA_EVENT_WPA_START_OK);
323 }
324 #ifdef LOS_CONFIG_SUPPORT_CPUP
325 uapi_cpup_load_check_proc(uapi_task_get_current_id(), LOAD_SLEEP_TIME_DEFAULT);
326 #endif /* LOS_CONFIG_SUPPORT_CPUP */
327 timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list);
328 if (timeout != NULL) {
329 (void)os_get_reltime(&now);
330 if (os_reltime_before(&now, &timeout->time))
331 os_reltime_sub(&timeout->time, &now, &tv);
332 else
333 tv.sec = tv.usec = 0;
334 time = (unsigned long)(tv.sec * 1000 + tv.usec / 1000);
335 if (time)
336 (void)os_event_read(eloop.levent, eloop.flags, &ret_flags, WIFI_WAITMODE_OR, time);
337 else
338 (void)os_event_poll(eloop.levent, eloop.flags, &ret_flags, WIFI_WAITMODE_OR);
339 } else {
340 (void)os_event_read(eloop.levent, eloop.flags, &ret_flags, WIFI_WAITMODE_OR, WIFI_WAIT_FOREVER);
341 }
342
343 (void)os_event_clear(eloop.levent, ~ret_flags);
344
345 eloop_run_process_timeout_event();
346 eloop_run_process_normal_event(&ret_flags, &eloop);
347
348 if (eloop_terminate_wpa_process() == EXT_WIFI_OK) {
349 ret_flags = 0;
350 continue;
351 }
352 }
353 (void)eloop_terminate_wpa_process();
354 return EXT_WIFI_OK;
355 }
356
eloop_destroy(eloop_task_type eloop_task)357 void eloop_destroy(eloop_task_type eloop_task)
358 {
359 struct eloop_timeout *timeout = NULL;
360 struct eloop_timeout *prev = NULL;
361 struct os_reltime now;
362 if ((eloop_task != ELOOP_TASK_WPA) && (eloop_task != ELOOP_TASK_HOSTAPD))
363 return;
364 if (global_eloop_is_running())
365 return;
366 (void)os_get_reltime(&now);
367 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
368 dl_list_for_each_safe(timeout, prev, &eloop.timeout,
369 struct eloop_timeout, list) {
370 eloop_remove_timeout(timeout);
371 }
372 (void)os_mux_post(eloop.mutex_handle);
373 os_free(eloop.events);
374 eloop.events = NULL;
375 (void)os_mux_delete(eloop.mutex_handle);
376 }
377
eloop_register_event(void * event,size_t event_size,eloop_event_handler handler,void * eloop_data,void * user_data)378 int eloop_register_event(void *event, size_t event_size,
379 eloop_event_handler handler, void *eloop_data, void *user_data)
380 {
381 unsigned int i;
382 struct eloop_event *tmp = NULL;
383
384 (void)event_size;
385 if (eloop.event_count >= ELOOP_MAX_EVENTS)
386 return EXT_WIFI_FAIL;
387
388 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
389
390 for (i = 0; i < ELOOP_MAX_EVENTS; i++) {
391 if (eloop.events[i].flag == 0) {
392 tmp = &eloop.events[i];
393 break;
394 }
395 }
396 if ((i == ELOOP_MAX_EVENTS) || (tmp == NULL)) {
397 (void)os_mux_post(eloop.mutex_handle);
398 return EXT_WIFI_FAIL;
399 }
400
401 tmp->eloop_data = eloop_data;
402 tmp->user_data = user_data;
403 tmp->handler = handler;
404 tmp->flag = 1 << i;
405 dl_list_init(&tmp->message);
406
407 eloop.flags |= tmp->flag;
408 eloop.event_count++;
409
410 if (event != NULL)
411 *(struct eloop_event **)event = tmp;
412
413 (void)os_mux_post(eloop.mutex_handle);
414 return EXT_WIFI_OK;
415 }
416
eloop_unregister_event(void * event,size_t size)417 void eloop_unregister_event(void *event, size_t size)
418 {
419 int i;
420 struct eloop_event *tmp = (struct eloop_event *)event;
421 struct eloop_message *message = NULL;
422
423 (void)size;
424 if ((tmp == NULL) || (eloop.event_count == 0))
425 return;
426 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
427 for (i = 0; i < ELOOP_MAX_EVENTS; i++) {
428 if (&eloop.events[i] == tmp)
429 break;
430 }
431 if (i == ELOOP_MAX_EVENTS) {
432 (void)os_mux_post(eloop.mutex_handle);
433 return;
434 }
435 eloop.flags &= ~tmp->flag;
436
437 tmp->flag = 0;
438 tmp->handler = NULL;
439
440 while (1) {
441 message = dl_list_first(&tmp->message, struct eloop_message, list);
442 if (message == NULL)
443 break;
444
445 dl_list_del(&message->list);
446 os_free(message->buf);
447 os_free(message);
448 }
449
450 eloop.event_count--;
451 (void)os_mux_post(eloop.mutex_handle);
452 }
453
eloop_unregister_cli_event(void * event,size_t size)454 void eloop_unregister_cli_event(void *event, size_t size)
455 {
456 int i;
457 struct eloop_event *tmp = (struct eloop_event *)event;
458 struct eloop_message *message = NULL;
459 (void)size;
460 if ((tmp == NULL) || (eloop.event_count == 0))
461 return;
462
463 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
464 for (i = 0; i < ELOOP_MAX_EVENTS; i++) {
465 if (&eloop.events[i] == tmp)
466 break;
467 }
468 if (i == ELOOP_MAX_EVENTS) {
469 (void)os_mux_post(eloop.mutex_handle);
470 return;
471 }
472 eloop.flags &= ~tmp->flag;
473
474 tmp->flag = 0;
475 tmp->handler = NULL;
476
477 while (1) {
478 message = dl_list_first(&tmp->message, struct eloop_message, list);
479 if (message == NULL)
480 break;
481
482 dl_list_del(&message->list);
483 if (message->buf != NULL)
484 os_free(((struct ctrl_iface_event_buf *)(message->buf))->buf);
485 os_free(message->buf);
486 os_free(message);
487 }
488 eloop.event_count--;
489 (void)os_mux_post(eloop.mutex_handle);
490 }
491
eloop_post_event(void * event,void * buf,int set_event)492 int eloop_post_event(void *event, void *buf, int set_event)
493 {
494 unsigned int int_save;
495 int i;
496 struct eloop_event *tmp = (struct eloop_event *)event;
497 struct eloop_message *message = NULL;
498
499 (void)set_event;
500 if (tmp == NULL)
501 return EXT_WIFI_FAIL;
502
503 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
504
505 for (i = 0; i < ELOOP_MAX_EVENTS; i++) {
506 if (&eloop.events[i] == tmp)
507 break;
508 }
509 if (i == ELOOP_MAX_EVENTS) {
510 (void)os_mux_post(eloop.mutex_handle);
511 return EXT_WIFI_FAIL;
512 }
513 if ((eloop.flags & (1 << i)) == 0) {
514 (void)os_mux_post(eloop.mutex_handle);
515 return EXT_WIFI_FAIL;
516 }
517
518 message = os_malloc(sizeof(struct eloop_message));
519 if (message == NULL) {
520 (void)os_mux_post(eloop.mutex_handle);
521 return EXT_WIFI_FAIL;
522 }
523 message->buf = buf;
524 dl_list_add_tail(&tmp->message, &message->list);
525 (void)os_mux_post(eloop.mutex_handle);
526 (void)os_event_write(eloop.levent, tmp->flag);
527 return EXT_WIFI_OK;
528 }
529
eloop_read_event(void * event,int timeout)530 void *eloop_read_event(void *event, int timeout)
531 {
532 unsigned int int_save;
533 void *ret = NULL;
534 int i;
535 struct eloop_event *tmp = (struct eloop_event *)event;
536 struct eloop_message *message = NULL;
537
538 (void)timeout;
539 if (tmp == NULL)
540 return NULL;
541
542 (void)os_mux_pend(eloop.mutex_handle, WIFI_WAIT_FOREVER);
543
544 for (i = 0; i < ELOOP_MAX_EVENTS; i++) {
545 if (&eloop.events[i] == tmp)
546 break;
547 }
548 if (i == ELOOP_MAX_EVENTS) {
549 (void)os_mux_post(eloop.mutex_handle);
550 return NULL;
551 }
552 if ((eloop.flags & (1 << i)) == 0) {
553 (void)os_mux_post(eloop.mutex_handle);
554 return NULL;
555 }
556
557 message = dl_list_first(&tmp->message, struct eloop_message, list);
558 if (message != NULL) {
559 ret = message->buf; // copy data before free.
560
561 dl_list_del(&message->list);
562 os_free(message);
563 }
564 (void)os_mux_post(eloop.mutex_handle);
565 return ret;
566 }
567