1d4f2939cSRui Paulo /*
2d4f2939cSRui Paulo * wpa_supplicant D-Bus control interface - common functionality
3d4f2939cSRui Paulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4d4f2939cSRui Paulo * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
5d4f2939cSRui Paulo * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6d4f2939cSRui Paulo *
7d4f2939cSRui Paulo * This software may be distributed under the terms of the BSD license.
8d4f2939cSRui Paulo * See README for more details.
9d4f2939cSRui Paulo */
10d4f2939cSRui Paulo
11d4f2939cSRui Paulo #include "utils/includes.h"
12d4f2939cSRui Paulo #include <dbus/dbus.h>
13d4f2939cSRui Paulo
14d4f2939cSRui Paulo #include "utils/common.h"
15d4f2939cSRui Paulo #include "utils/eloop.h"
16d4f2939cSRui Paulo #include "dbus_common.h"
17d4f2939cSRui Paulo #include "dbus_common_i.h"
18d4f2939cSRui Paulo #include "dbus_new.h"
195b9c547cSRui Paulo #include "../wpa_supplicant_i.h"
20d4f2939cSRui Paulo
21d4f2939cSRui Paulo
22d4f2939cSRui Paulo #ifndef SIGPOLL
23d4f2939cSRui Paulo #ifdef SIGIO
24d4f2939cSRui Paulo /*
25d4f2939cSRui Paulo * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
26d4f2939cSRui Paulo * FreeBSD.
27d4f2939cSRui Paulo */
28d4f2939cSRui Paulo #define SIGPOLL SIGIO
29d4f2939cSRui Paulo #endif
30d4f2939cSRui Paulo #endif
31d4f2939cSRui Paulo
32d4f2939cSRui Paulo
dispatch_data(DBusConnection * con)33d4f2939cSRui Paulo static void dispatch_data(DBusConnection *con)
34d4f2939cSRui Paulo {
35d4f2939cSRui Paulo while (dbus_connection_get_dispatch_status(con) ==
36d4f2939cSRui Paulo DBUS_DISPATCH_DATA_REMAINS)
37d4f2939cSRui Paulo dbus_connection_dispatch(con);
38d4f2939cSRui Paulo }
39d4f2939cSRui Paulo
40d4f2939cSRui Paulo
41d4f2939cSRui Paulo /**
42d4f2939cSRui Paulo * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
43d4f2939cSRui Paulo * claiming bus name
44d4f2939cSRui Paulo * @eloop_ctx: the DBusConnection to dispatch on
45d4f2939cSRui Paulo * @timeout_ctx: unused
46d4f2939cSRui Paulo *
47d4f2939cSRui Paulo * If clients are quick to notice that service claimed its bus name,
48d4f2939cSRui Paulo * there may have been messages that came in before initialization was
49d4f2939cSRui Paulo * all finished. Dispatch those here.
50d4f2939cSRui Paulo */
dispatch_initial_dbus_messages(void * eloop_ctx,void * timeout_ctx)51d4f2939cSRui Paulo static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
52d4f2939cSRui Paulo {
53d4f2939cSRui Paulo DBusConnection *con = eloop_ctx;
54d4f2939cSRui Paulo dispatch_data(con);
55d4f2939cSRui Paulo }
56d4f2939cSRui Paulo
57d4f2939cSRui Paulo
process_watch(struct wpas_dbus_priv * priv,DBusWatch * watch,eloop_event_type type)58d4f2939cSRui Paulo static void process_watch(struct wpas_dbus_priv *priv,
59d4f2939cSRui Paulo DBusWatch *watch, eloop_event_type type)
60d4f2939cSRui Paulo {
61d4f2939cSRui Paulo dbus_connection_ref(priv->con);
62d4f2939cSRui Paulo
63d4f2939cSRui Paulo priv->should_dispatch = 0;
64d4f2939cSRui Paulo
65d4f2939cSRui Paulo if (type == EVENT_TYPE_READ)
66d4f2939cSRui Paulo dbus_watch_handle(watch, DBUS_WATCH_READABLE);
67d4f2939cSRui Paulo else if (type == EVENT_TYPE_WRITE)
68d4f2939cSRui Paulo dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
69d4f2939cSRui Paulo else if (type == EVENT_TYPE_EXCEPTION)
70d4f2939cSRui Paulo dbus_watch_handle(watch, DBUS_WATCH_ERROR);
71d4f2939cSRui Paulo
72d4f2939cSRui Paulo if (priv->should_dispatch) {
73d4f2939cSRui Paulo dispatch_data(priv->con);
74d4f2939cSRui Paulo priv->should_dispatch = 0;
75d4f2939cSRui Paulo }
76d4f2939cSRui Paulo
77d4f2939cSRui Paulo dbus_connection_unref(priv->con);
78d4f2939cSRui Paulo }
79d4f2939cSRui Paulo
80d4f2939cSRui Paulo
process_watch_exception(int sock,void * eloop_ctx,void * sock_ctx)81d4f2939cSRui Paulo static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
82d4f2939cSRui Paulo {
83d4f2939cSRui Paulo process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
84d4f2939cSRui Paulo }
85d4f2939cSRui Paulo
86d4f2939cSRui Paulo
process_watch_read(int sock,void * eloop_ctx,void * sock_ctx)87d4f2939cSRui Paulo static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
88d4f2939cSRui Paulo {
89d4f2939cSRui Paulo process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
90d4f2939cSRui Paulo }
91d4f2939cSRui Paulo
92d4f2939cSRui Paulo
process_watch_write(int sock,void * eloop_ctx,void * sock_ctx)93d4f2939cSRui Paulo static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
94d4f2939cSRui Paulo {
95d4f2939cSRui Paulo process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
96d4f2939cSRui Paulo }
97d4f2939cSRui Paulo
98d4f2939cSRui Paulo
add_watch(DBusWatch * watch,void * data)99d4f2939cSRui Paulo static dbus_bool_t add_watch(DBusWatch *watch, void *data)
100d4f2939cSRui Paulo {
101d4f2939cSRui Paulo struct wpas_dbus_priv *priv = data;
102d4f2939cSRui Paulo unsigned int flags;
103d4f2939cSRui Paulo int fd;
104d4f2939cSRui Paulo
105d4f2939cSRui Paulo if (!dbus_watch_get_enabled(watch))
106d4f2939cSRui Paulo return TRUE;
107d4f2939cSRui Paulo
108d4f2939cSRui Paulo flags = dbus_watch_get_flags(watch);
109d4f2939cSRui Paulo fd = dbus_watch_get_unix_fd(watch);
110d4f2939cSRui Paulo
111*c1d255d3SCy Schubert if (eloop_register_sock(fd, EVENT_TYPE_EXCEPTION,
112*c1d255d3SCy Schubert process_watch_exception, priv, watch) < 0)
113*c1d255d3SCy Schubert return FALSE;
114d4f2939cSRui Paulo
115*c1d255d3SCy Schubert if ((flags & DBUS_WATCH_READABLE) &&
116d4f2939cSRui Paulo eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
117*c1d255d3SCy Schubert priv, watch) < 0)
118*c1d255d3SCy Schubert return FALSE;
119*c1d255d3SCy Schubert if ((flags & DBUS_WATCH_WRITABLE) &&
120d4f2939cSRui Paulo eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
121*c1d255d3SCy Schubert priv, watch) < 0)
122*c1d255d3SCy Schubert return FALSE;
123d4f2939cSRui Paulo
124d4f2939cSRui Paulo dbus_watch_set_data(watch, priv, NULL);
125d4f2939cSRui Paulo
126d4f2939cSRui Paulo return TRUE;
127d4f2939cSRui Paulo }
128d4f2939cSRui Paulo
129d4f2939cSRui Paulo
remove_watch(DBusWatch * watch,void * data)130d4f2939cSRui Paulo static void remove_watch(DBusWatch *watch, void *data)
131d4f2939cSRui Paulo {
132d4f2939cSRui Paulo unsigned int flags;
133d4f2939cSRui Paulo int fd;
134d4f2939cSRui Paulo
135d4f2939cSRui Paulo flags = dbus_watch_get_flags(watch);
136d4f2939cSRui Paulo fd = dbus_watch_get_unix_fd(watch);
137d4f2939cSRui Paulo
138d4f2939cSRui Paulo eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
139d4f2939cSRui Paulo
140d4f2939cSRui Paulo if (flags & DBUS_WATCH_READABLE)
141d4f2939cSRui Paulo eloop_unregister_sock(fd, EVENT_TYPE_READ);
142d4f2939cSRui Paulo if (flags & DBUS_WATCH_WRITABLE)
143d4f2939cSRui Paulo eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
144d4f2939cSRui Paulo
145d4f2939cSRui Paulo dbus_watch_set_data(watch, NULL, NULL);
146d4f2939cSRui Paulo }
147d4f2939cSRui Paulo
148d4f2939cSRui Paulo
watch_toggled(DBusWatch * watch,void * data)149d4f2939cSRui Paulo static void watch_toggled(DBusWatch *watch, void *data)
150d4f2939cSRui Paulo {
151d4f2939cSRui Paulo if (dbus_watch_get_enabled(watch))
152d4f2939cSRui Paulo add_watch(watch, data);
153d4f2939cSRui Paulo else
154d4f2939cSRui Paulo remove_watch(watch, data);
155d4f2939cSRui Paulo }
156d4f2939cSRui Paulo
157d4f2939cSRui Paulo
process_timeout(void * eloop_ctx,void * sock_ctx)158d4f2939cSRui Paulo static void process_timeout(void *eloop_ctx, void *sock_ctx)
159d4f2939cSRui Paulo {
160d4f2939cSRui Paulo DBusTimeout *timeout = sock_ctx;
161d4f2939cSRui Paulo dbus_timeout_handle(timeout);
162d4f2939cSRui Paulo }
163d4f2939cSRui Paulo
164d4f2939cSRui Paulo
add_timeout(DBusTimeout * timeout,void * data)165d4f2939cSRui Paulo static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
166d4f2939cSRui Paulo {
167d4f2939cSRui Paulo struct wpas_dbus_priv *priv = data;
1685b9c547cSRui Paulo
169d4f2939cSRui Paulo if (!dbus_timeout_get_enabled(timeout))
170d4f2939cSRui Paulo return TRUE;
171d4f2939cSRui Paulo
172d4f2939cSRui Paulo eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
173d4f2939cSRui Paulo process_timeout, priv, timeout);
174d4f2939cSRui Paulo
175d4f2939cSRui Paulo dbus_timeout_set_data(timeout, priv, NULL);
176d4f2939cSRui Paulo
177d4f2939cSRui Paulo return TRUE;
178d4f2939cSRui Paulo }
179d4f2939cSRui Paulo
180d4f2939cSRui Paulo
remove_timeout(DBusTimeout * timeout,void * data)181d4f2939cSRui Paulo static void remove_timeout(DBusTimeout *timeout, void *data)
182d4f2939cSRui Paulo {
183d4f2939cSRui Paulo struct wpas_dbus_priv *priv = data;
1845b9c547cSRui Paulo
185d4f2939cSRui Paulo eloop_cancel_timeout(process_timeout, priv, timeout);
186d4f2939cSRui Paulo dbus_timeout_set_data(timeout, NULL, NULL);
187d4f2939cSRui Paulo }
188d4f2939cSRui Paulo
189d4f2939cSRui Paulo
timeout_toggled(DBusTimeout * timeout,void * data)190d4f2939cSRui Paulo static void timeout_toggled(DBusTimeout *timeout, void *data)
191d4f2939cSRui Paulo {
192d4f2939cSRui Paulo if (dbus_timeout_get_enabled(timeout))
193d4f2939cSRui Paulo add_timeout(timeout, data);
194d4f2939cSRui Paulo else
195d4f2939cSRui Paulo remove_timeout(timeout, data);
196d4f2939cSRui Paulo }
197d4f2939cSRui Paulo
198d4f2939cSRui Paulo
process_wakeup_main(int sig,void * signal_ctx)199d4f2939cSRui Paulo static void process_wakeup_main(int sig, void *signal_ctx)
200d4f2939cSRui Paulo {
201d4f2939cSRui Paulo struct wpas_dbus_priv *priv = signal_ctx;
202d4f2939cSRui Paulo
203d4f2939cSRui Paulo if (sig != SIGPOLL || !priv->con)
204d4f2939cSRui Paulo return;
205d4f2939cSRui Paulo
206d4f2939cSRui Paulo if (dbus_connection_get_dispatch_status(priv->con) !=
207d4f2939cSRui Paulo DBUS_DISPATCH_DATA_REMAINS)
208d4f2939cSRui Paulo return;
209d4f2939cSRui Paulo
210d4f2939cSRui Paulo /* Only dispatch once - we do not want to starve other events */
211d4f2939cSRui Paulo dbus_connection_ref(priv->con);
212d4f2939cSRui Paulo dbus_connection_dispatch(priv->con);
213d4f2939cSRui Paulo dbus_connection_unref(priv->con);
214d4f2939cSRui Paulo }
215d4f2939cSRui Paulo
216d4f2939cSRui Paulo
217d4f2939cSRui Paulo /**
218d4f2939cSRui Paulo * wakeup_main - Attempt to wake our mainloop up
219d4f2939cSRui Paulo * @data: dbus control interface private data
220d4f2939cSRui Paulo *
221d4f2939cSRui Paulo * Try to wake up the main eloop so it will process
222d4f2939cSRui Paulo * dbus events that may have happened.
223d4f2939cSRui Paulo */
wakeup_main(void * data)224d4f2939cSRui Paulo static void wakeup_main(void *data)
225d4f2939cSRui Paulo {
226d4f2939cSRui Paulo struct wpas_dbus_priv *priv = data;
227d4f2939cSRui Paulo
228d4f2939cSRui Paulo /* Use SIGPOLL to break out of the eloop select() */
229d4f2939cSRui Paulo raise(SIGPOLL);
230d4f2939cSRui Paulo priv->should_dispatch = 1;
231d4f2939cSRui Paulo }
232d4f2939cSRui Paulo
233d4f2939cSRui Paulo
234d4f2939cSRui Paulo /**
235d4f2939cSRui Paulo * integrate_with_eloop - Register our mainloop integration with dbus
236d4f2939cSRui Paulo * @connection: connection to the system message bus
237d4f2939cSRui Paulo * @priv: a dbus control interface data structure
238d4f2939cSRui Paulo * Returns: 0 on success, -1 on failure
239d4f2939cSRui Paulo */
integrate_with_eloop(struct wpas_dbus_priv * priv)240d4f2939cSRui Paulo static int integrate_with_eloop(struct wpas_dbus_priv *priv)
241d4f2939cSRui Paulo {
242d4f2939cSRui Paulo if (!dbus_connection_set_watch_functions(priv->con, add_watch,
243d4f2939cSRui Paulo remove_watch, watch_toggled,
244d4f2939cSRui Paulo priv, NULL) ||
245d4f2939cSRui Paulo !dbus_connection_set_timeout_functions(priv->con, add_timeout,
246d4f2939cSRui Paulo remove_timeout,
247d4f2939cSRui Paulo timeout_toggled, priv,
248d4f2939cSRui Paulo NULL)) {
2495b9c547cSRui Paulo wpa_printf(MSG_ERROR, "dbus: Failed to set callback functions");
250d4f2939cSRui Paulo return -1;
251d4f2939cSRui Paulo }
252d4f2939cSRui Paulo
253d4f2939cSRui Paulo if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv))
254d4f2939cSRui Paulo return -1;
255d4f2939cSRui Paulo dbus_connection_set_wakeup_main_function(priv->con, wakeup_main,
256d4f2939cSRui Paulo priv, NULL);
257d4f2939cSRui Paulo
258d4f2939cSRui Paulo return 0;
259d4f2939cSRui Paulo }
260d4f2939cSRui Paulo
261d4f2939cSRui Paulo
disconnect_filter(DBusConnection * conn,DBusMessage * message,void * data)2625b9c547cSRui Paulo static DBusHandlerResult disconnect_filter(DBusConnection *conn,
2635b9c547cSRui Paulo DBusMessage *message, void *data)
2645b9c547cSRui Paulo {
2655b9c547cSRui Paulo struct wpas_dbus_priv *priv = data;
2665b9c547cSRui Paulo
2675b9c547cSRui Paulo if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
2685b9c547cSRui Paulo "Disconnected")) {
2695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
2705b9c547cSRui Paulo dbus_connection_set_exit_on_disconnect(conn, FALSE);
2715b9c547cSRui Paulo wpa_supplicant_terminate_proc(priv->global);
2725b9c547cSRui Paulo return DBUS_HANDLER_RESULT_HANDLED;
2735b9c547cSRui Paulo } else
2745b9c547cSRui Paulo return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2755b9c547cSRui Paulo }
2765b9c547cSRui Paulo
2775b9c547cSRui Paulo
wpas_dbus_init_common(struct wpas_dbus_priv * priv)278d4f2939cSRui Paulo static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
279d4f2939cSRui Paulo {
280d4f2939cSRui Paulo DBusError error;
281d4f2939cSRui Paulo int ret = 0;
282d4f2939cSRui Paulo
283d4f2939cSRui Paulo /* Get a reference to the system bus */
284d4f2939cSRui Paulo dbus_error_init(&error);
285d4f2939cSRui Paulo priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
2865b9c547cSRui Paulo if (priv->con) {
2875b9c547cSRui Paulo dbus_connection_add_filter(priv->con, disconnect_filter, priv,
2885b9c547cSRui Paulo NULL);
2895b9c547cSRui Paulo } else {
2905b9c547cSRui Paulo wpa_printf(MSG_ERROR,
2915b9c547cSRui Paulo "dbus: Could not acquire the system bus: %s - %s",
2925b9c547cSRui Paulo error.name, error.message);
293d4f2939cSRui Paulo ret = -1;
294d4f2939cSRui Paulo }
295d4f2939cSRui Paulo dbus_error_free(&error);
296d4f2939cSRui Paulo
297d4f2939cSRui Paulo return ret;
298d4f2939cSRui Paulo }
299d4f2939cSRui Paulo
300d4f2939cSRui Paulo
wpas_dbus_init_common_finish(struct wpas_dbus_priv * priv)301d4f2939cSRui Paulo static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
302d4f2939cSRui Paulo {
303d4f2939cSRui Paulo /* Tell dbus about our mainloop integration functions */
304d4f2939cSRui Paulo integrate_with_eloop(priv);
305d4f2939cSRui Paulo
306d4f2939cSRui Paulo /*
307d4f2939cSRui Paulo * Dispatch initial DBus messages that may have come in since the bus
308d4f2939cSRui Paulo * name was claimed above. Happens when clients are quick to notice the
309d4f2939cSRui Paulo * service.
310d4f2939cSRui Paulo *
311d4f2939cSRui Paulo * FIXME: is there a better solution to this problem?
312d4f2939cSRui Paulo */
313d4f2939cSRui Paulo eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
314d4f2939cSRui Paulo priv->con, NULL);
315d4f2939cSRui Paulo
316d4f2939cSRui Paulo return 0;
317d4f2939cSRui Paulo }
318d4f2939cSRui Paulo
319d4f2939cSRui Paulo
wpas_dbus_deinit_common(struct wpas_dbus_priv * priv)320d4f2939cSRui Paulo static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
321d4f2939cSRui Paulo {
322d4f2939cSRui Paulo if (priv->con) {
323d4f2939cSRui Paulo eloop_cancel_timeout(dispatch_initial_dbus_messages,
324d4f2939cSRui Paulo priv->con, NULL);
3255b9c547cSRui Paulo eloop_cancel_timeout(process_timeout, priv, ELOOP_ALL_CTX);
3265b9c547cSRui Paulo
327d4f2939cSRui Paulo dbus_connection_set_watch_functions(priv->con, NULL, NULL,
328d4f2939cSRui Paulo NULL, NULL, NULL);
329d4f2939cSRui Paulo dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
330d4f2939cSRui Paulo NULL, NULL, NULL);
3315b9c547cSRui Paulo dbus_connection_remove_filter(priv->con, disconnect_filter,
3325b9c547cSRui Paulo priv);
3335b9c547cSRui Paulo
334d4f2939cSRui Paulo dbus_connection_unref(priv->con);
335d4f2939cSRui Paulo }
336d4f2939cSRui Paulo
337d4f2939cSRui Paulo os_free(priv);
338d4f2939cSRui Paulo }
339d4f2939cSRui Paulo
340d4f2939cSRui Paulo
wpas_dbus_init(struct wpa_global * global)341d4f2939cSRui Paulo struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
342d4f2939cSRui Paulo {
343d4f2939cSRui Paulo struct wpas_dbus_priv *priv;
344d4f2939cSRui Paulo
345d4f2939cSRui Paulo priv = os_zalloc(sizeof(*priv));
346d4f2939cSRui Paulo if (priv == NULL)
347d4f2939cSRui Paulo return NULL;
348d4f2939cSRui Paulo priv->global = global;
349d4f2939cSRui Paulo
3505b9c547cSRui Paulo if (wpas_dbus_init_common(priv) < 0 ||
351d4f2939cSRui Paulo #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
3525b9c547cSRui Paulo wpas_dbus_ctrl_iface_init(priv) < 0 ||
353d4f2939cSRui Paulo #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
3545b9c547cSRui Paulo wpas_dbus_init_common_finish(priv) < 0) {
355d4f2939cSRui Paulo wpas_dbus_deinit(priv);
356d4f2939cSRui Paulo return NULL;
357d4f2939cSRui Paulo }
358d4f2939cSRui Paulo
359d4f2939cSRui Paulo return priv;
360d4f2939cSRui Paulo }
361d4f2939cSRui Paulo
362d4f2939cSRui Paulo
wpas_dbus_deinit(struct wpas_dbus_priv * priv)363d4f2939cSRui Paulo void wpas_dbus_deinit(struct wpas_dbus_priv *priv)
364d4f2939cSRui Paulo {
365d4f2939cSRui Paulo if (priv == NULL)
366d4f2939cSRui Paulo return;
367d4f2939cSRui Paulo
368d4f2939cSRui Paulo #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
369d4f2939cSRui Paulo wpas_dbus_ctrl_iface_deinit(priv);
370d4f2939cSRui Paulo #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
371d4f2939cSRui Paulo
372d4f2939cSRui Paulo wpas_dbus_deinit_common(priv);
373d4f2939cSRui Paulo }
374