2 * wpa_supplicant D-Bus control interface - common functionality
3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4 * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
5 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * Alternatively, this software may be distributed under the terms of BSD
14 * See README and COPYING for more details.
17 #include "utils/includes.h"
18 #include <dbus/dbus.h>
20 #include "utils/common.h"
21 #include "utils/eloop.h"
22 #include "dbus_common.h"
23 #include "dbus_common_i.h"
29 * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
31 * @eloop_ctx: the DBusConnection to dispatch on
32 * @timeout_ctx: unused
34 * If clients are quick to notice that service claimed its bus name,
35 * there may have been messages that came in before initialization was
36 * all finished. Dispatch those here.
38 static void dispatch_initial_dbus_messages(void *eloop_ctx
, void *timeout_ctx
)
40 DBusConnection
*con
= eloop_ctx
;
42 while (dbus_connection_get_dispatch_status(con
) ==
43 DBUS_DISPATCH_DATA_REMAINS
)
44 dbus_connection_dispatch(con
);
48 static void process_watch(struct wpas_dbus_priv
*priv
,
49 DBusWatch
*watch
, eloop_event_type type
)
51 dbus_connection_ref(priv
->con
);
53 priv
->should_dispatch
= 0;
55 if (type
== EVENT_TYPE_READ
)
56 dbus_watch_handle(watch
, DBUS_WATCH_READABLE
);
57 else if (type
== EVENT_TYPE_WRITE
)
58 dbus_watch_handle(watch
, DBUS_WATCH_WRITABLE
);
59 else if (type
== EVENT_TYPE_EXCEPTION
)
60 dbus_watch_handle(watch
, DBUS_WATCH_ERROR
);
62 if (priv
->should_dispatch
) {
63 while (dbus_connection_get_dispatch_status(priv
->con
) ==
64 DBUS_DISPATCH_DATA_REMAINS
)
65 dbus_connection_dispatch(priv
->con
);
66 priv
->should_dispatch
= 0;
69 dbus_connection_unref(priv
->con
);
73 static void process_watch_exception(int sock
, void *eloop_ctx
, void *sock_ctx
)
75 process_watch(eloop_ctx
, sock_ctx
, EVENT_TYPE_EXCEPTION
);
79 static void process_watch_read(int sock
, void *eloop_ctx
, void *sock_ctx
)
81 process_watch(eloop_ctx
, sock_ctx
, EVENT_TYPE_READ
);
85 static void process_watch_write(int sock
, void *eloop_ctx
, void *sock_ctx
)
87 process_watch(eloop_ctx
, sock_ctx
, EVENT_TYPE_WRITE
);
91 static void connection_setup_add_watch(struct wpas_dbus_priv
*priv
,
97 if (!dbus_watch_get_enabled(watch
))
100 flags
= dbus_watch_get_flags(watch
);
101 fd
= dbus_watch_get_unix_fd(watch
);
103 eloop_register_sock(fd
, EVENT_TYPE_EXCEPTION
, process_watch_exception
,
106 if (flags
& DBUS_WATCH_READABLE
) {
107 eloop_register_sock(fd
, EVENT_TYPE_READ
, process_watch_read
,
110 if (flags
& DBUS_WATCH_WRITABLE
) {
111 eloop_register_sock(fd
, EVENT_TYPE_WRITE
, process_watch_write
,
115 dbus_watch_set_data(watch
, priv
, NULL
);
119 static void connection_setup_remove_watch(struct wpas_dbus_priv
*priv
,
125 flags
= dbus_watch_get_flags(watch
);
126 fd
= dbus_watch_get_unix_fd(watch
);
128 eloop_unregister_sock(fd
, EVENT_TYPE_EXCEPTION
);
130 if (flags
& DBUS_WATCH_READABLE
)
131 eloop_unregister_sock(fd
, EVENT_TYPE_READ
);
132 if (flags
& DBUS_WATCH_WRITABLE
)
133 eloop_unregister_sock(fd
, EVENT_TYPE_WRITE
);
135 dbus_watch_set_data(watch
, NULL
, NULL
);
139 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
)
141 connection_setup_add_watch(data
, watch
);
146 static void remove_watch(DBusWatch
*watch
, void *data
)
148 connection_setup_remove_watch(data
, watch
);
152 static void watch_toggled(DBusWatch
*watch
, void *data
)
154 if (dbus_watch_get_enabled(watch
))
155 add_watch(watch
, data
);
157 remove_watch(watch
, data
);
161 static void process_timeout(void *eloop_ctx
, void *sock_ctx
)
163 DBusTimeout
*timeout
= sock_ctx
;
165 dbus_timeout_handle(timeout
);
169 static void connection_setup_add_timeout(struct wpas_dbus_priv
*priv
,
170 DBusTimeout
*timeout
)
172 if (!dbus_timeout_get_enabled(timeout
))
175 eloop_register_timeout(0, dbus_timeout_get_interval(timeout
) * 1000,
176 process_timeout
, priv
, timeout
);
178 dbus_timeout_set_data(timeout
, priv
, NULL
);
182 static void connection_setup_remove_timeout(struct wpas_dbus_priv
*priv
,
183 DBusTimeout
*timeout
)
185 eloop_cancel_timeout(process_timeout
, priv
, timeout
);
186 dbus_timeout_set_data(timeout
, NULL
, NULL
);
190 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
)
192 if (!dbus_timeout_get_enabled(timeout
))
195 connection_setup_add_timeout(data
, timeout
);
201 static void remove_timeout(DBusTimeout
*timeout
, void *data
)
203 connection_setup_remove_timeout(data
, timeout
);
207 static void timeout_toggled(DBusTimeout
*timeout
, void *data
)
209 if (dbus_timeout_get_enabled(timeout
))
210 add_timeout(timeout
, data
);
212 remove_timeout(timeout
, data
);
216 static void process_wakeup_main(int sig
, void *signal_ctx
)
218 struct wpas_dbus_priv
*priv
= signal_ctx
;
220 if (sig
!= SIGPOLL
|| !priv
->con
)
223 if (dbus_connection_get_dispatch_status(priv
->con
) !=
224 DBUS_DISPATCH_DATA_REMAINS
)
227 /* Only dispatch once - we do not want to starve other events */
228 dbus_connection_ref(priv
->con
);
229 dbus_connection_dispatch(priv
->con
);
230 dbus_connection_unref(priv
->con
);
235 * wakeup_main - Attempt to wake our mainloop up
236 * @data: dbus control interface private data
238 * Try to wake up the main eloop so it will process
239 * dbus events that may have happened.
241 static void wakeup_main(void *data
)
243 struct wpas_dbus_priv
*priv
= data
;
245 /* Use SIGPOLL to break out of the eloop select() */
247 priv
->should_dispatch
= 1;
252 * connection_setup_wakeup_main - Tell dbus about our wakeup_main function
253 * @priv: dbus control interface private data
254 * Returns: 0 on success, -1 on failure
256 * Register our wakeup_main handler with dbus
258 static int connection_setup_wakeup_main(struct wpas_dbus_priv
*priv
)
260 if (eloop_register_signal(SIGPOLL
, process_wakeup_main
, priv
))
263 dbus_connection_set_wakeup_main_function(priv
->con
, wakeup_main
,
271 * integrate_with_eloop - Register our mainloop integration with dbus
272 * @connection: connection to the system message bus
273 * @priv: a dbus control interface data structure
274 * Returns: 0 on success, -1 on failure
276 * We register our mainloop integration functions with dbus here.
278 static int integrate_with_eloop(struct wpas_dbus_priv
*priv
)
280 if (!dbus_connection_set_watch_functions(priv
->con
, add_watch
,
281 remove_watch
, watch_toggled
,
283 perror("dbus_connection_set_watch_functions[dbus]");
284 wpa_printf(MSG_ERROR
, "Not enough memory to set up dbus.");
288 if (!dbus_connection_set_timeout_functions(priv
->con
, add_timeout
,
290 timeout_toggled
, priv
,
292 perror("dbus_connection_set_timeout_functions[dbus]");
293 wpa_printf(MSG_ERROR
, "Not enough memory to set up dbus.");
297 if (connection_setup_wakeup_main(priv
) < 0) {
298 perror("connection_setup_wakeup_main[dbus]");
299 wpa_printf(MSG_ERROR
, "Could not setup main wakeup function.");
307 static int wpas_dbus_init_common(struct wpas_dbus_priv
*priv
)
311 /* Get a reference to the system bus */
312 dbus_error_init(&error
);
313 priv
->con
= dbus_bus_get(DBUS_BUS_SYSTEM
, &error
);
314 dbus_error_free(&error
);
316 wpa_printf(MSG_ERROR
, "dbus: Could not acquire the system "
317 "bus: %s", strerror(errno
));
325 static int wpas_dbus_init_common_finish(struct wpas_dbus_priv
*priv
)
327 /* Tell dbus about our mainloop integration functions */
328 integrate_with_eloop(priv
);
331 * Dispatch initial DBus messages that may have come in since the bus
332 * name was claimed above. Happens when clients are quick to notice the
335 * FIXME: is there a better solution to this problem?
337 eloop_register_timeout(0, 50, dispatch_initial_dbus_messages
,
344 static void wpas_dbus_deinit_common(struct wpas_dbus_priv
*priv
)
347 eloop_cancel_timeout(dispatch_initial_dbus_messages
,
349 dbus_connection_set_watch_functions(priv
->con
, NULL
, NULL
,
351 dbus_connection_set_timeout_functions(priv
->con
, NULL
, NULL
,
353 dbus_connection_unref(priv
->con
);
360 struct wpas_dbus_priv
* wpas_dbus_init(struct wpa_global
*global
)
362 struct wpas_dbus_priv
*priv
;
364 priv
= os_zalloc(sizeof(*priv
));
367 priv
->global
= global
;
369 if (wpas_dbus_init_common(priv
) < 0) {
370 wpas_dbus_deinit(priv
);
374 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
375 if (wpas_dbus_ctrl_iface_init(priv
) < 0) {
376 wpas_dbus_deinit(priv
);
379 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
381 #ifdef CONFIG_CTRL_IFACE_DBUS
382 if (wpa_supplicant_dbus_ctrl_iface_init(priv
) < 0) {
383 wpas_dbus_deinit(priv
);
386 #endif /* CONFIG_CTRL_IFACE_DBUS */
388 if (wpas_dbus_init_common_finish(priv
) < 0) {
389 wpas_dbus_deinit(priv
);
397 void wpas_dbus_deinit(struct wpas_dbus_priv
*priv
)
402 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
403 wpas_dbus_ctrl_iface_deinit(priv
);
404 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
406 #ifdef CONFIG_CTRL_IFACE_DBUS
407 /* TODO: is any deinit needed? */
408 #endif /* CONFIG_CTRL_IFACE_DBUS */
410 wpas_dbus_deinit_common(priv
);