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