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"
31 * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
39 static void dispatch_data(DBusConnection
*con
)
41 while (dbus_connection_get_dispatch_status(con
) ==
42 DBUS_DISPATCH_DATA_REMAINS
)
43 dbus_connection_dispatch(con
);
48 * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
50 * @eloop_ctx: the DBusConnection to dispatch on
51 * @timeout_ctx: unused
53 * If clients are quick to notice that service claimed its bus name,
54 * there may have been messages that came in before initialization was
55 * all finished. Dispatch those here.
57 static void dispatch_initial_dbus_messages(void *eloop_ctx
, void *timeout_ctx
)
59 DBusConnection
*con
= eloop_ctx
;
64 static void process_watch(struct wpas_dbus_priv
*priv
,
65 DBusWatch
*watch
, eloop_event_type type
)
67 dbus_connection_ref(priv
->con
);
69 priv
->should_dispatch
= 0;
71 if (type
== EVENT_TYPE_READ
)
72 dbus_watch_handle(watch
, DBUS_WATCH_READABLE
);
73 else if (type
== EVENT_TYPE_WRITE
)
74 dbus_watch_handle(watch
, DBUS_WATCH_WRITABLE
);
75 else if (type
== EVENT_TYPE_EXCEPTION
)
76 dbus_watch_handle(watch
, DBUS_WATCH_ERROR
);
78 if (priv
->should_dispatch
) {
79 dispatch_data(priv
->con
);
80 priv
->should_dispatch
= 0;
83 dbus_connection_unref(priv
->con
);
87 static void process_watch_exception(int sock
, void *eloop_ctx
, void *sock_ctx
)
89 process_watch(eloop_ctx
, sock_ctx
, EVENT_TYPE_EXCEPTION
);
93 static void process_watch_read(int sock
, void *eloop_ctx
, void *sock_ctx
)
95 process_watch(eloop_ctx
, sock_ctx
, EVENT_TYPE_READ
);
99 static void process_watch_write(int sock
, void *eloop_ctx
, void *sock_ctx
)
101 process_watch(eloop_ctx
, sock_ctx
, EVENT_TYPE_WRITE
);
105 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
)
107 struct wpas_dbus_priv
*priv
= data
;
111 if (!dbus_watch_get_enabled(watch
))
114 flags
= dbus_watch_get_flags(watch
);
115 fd
= dbus_watch_get_unix_fd(watch
);
117 eloop_register_sock(fd
, EVENT_TYPE_EXCEPTION
, process_watch_exception
,
120 if (flags
& DBUS_WATCH_READABLE
) {
121 eloop_register_sock(fd
, EVENT_TYPE_READ
, process_watch_read
,
124 if (flags
& DBUS_WATCH_WRITABLE
) {
125 eloop_register_sock(fd
, EVENT_TYPE_WRITE
, process_watch_write
,
129 dbus_watch_set_data(watch
, priv
, NULL
);
135 static void remove_watch(DBusWatch
*watch
, void *data
)
140 flags
= dbus_watch_get_flags(watch
);
141 fd
= dbus_watch_get_unix_fd(watch
);
143 eloop_unregister_sock(fd
, EVENT_TYPE_EXCEPTION
);
145 if (flags
& DBUS_WATCH_READABLE
)
146 eloop_unregister_sock(fd
, EVENT_TYPE_READ
);
147 if (flags
& DBUS_WATCH_WRITABLE
)
148 eloop_unregister_sock(fd
, EVENT_TYPE_WRITE
);
150 dbus_watch_set_data(watch
, NULL
, NULL
);
154 static void watch_toggled(DBusWatch
*watch
, void *data
)
156 if (dbus_watch_get_enabled(watch
))
157 add_watch(watch
, data
);
159 remove_watch(watch
, data
);
163 static void process_timeout(void *eloop_ctx
, void *sock_ctx
)
165 DBusTimeout
*timeout
= sock_ctx
;
166 dbus_timeout_handle(timeout
);
170 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
)
172 struct wpas_dbus_priv
*priv
= data
;
173 if (!dbus_timeout_get_enabled(timeout
))
176 eloop_register_timeout(0, dbus_timeout_get_interval(timeout
) * 1000,
177 process_timeout
, priv
, timeout
);
179 dbus_timeout_set_data(timeout
, priv
, NULL
);
185 static void remove_timeout(DBusTimeout
*timeout
, void *data
)
187 struct wpas_dbus_priv
*priv
= data
;
188 eloop_cancel_timeout(process_timeout
, priv
, timeout
);
189 dbus_timeout_set_data(timeout
, NULL
, NULL
);
193 static void timeout_toggled(DBusTimeout
*timeout
, void *data
)
195 if (dbus_timeout_get_enabled(timeout
))
196 add_timeout(timeout
, data
);
198 remove_timeout(timeout
, data
);
202 static void process_wakeup_main(int sig
, void *signal_ctx
)
204 struct wpas_dbus_priv
*priv
= signal_ctx
;
206 if (sig
!= SIGPOLL
|| !priv
->con
)
209 if (dbus_connection_get_dispatch_status(priv
->con
) !=
210 DBUS_DISPATCH_DATA_REMAINS
)
213 /* Only dispatch once - we do not want to starve other events */
214 dbus_connection_ref(priv
->con
);
215 dbus_connection_dispatch(priv
->con
);
216 dbus_connection_unref(priv
->con
);
221 * wakeup_main - Attempt to wake our mainloop up
222 * @data: dbus control interface private data
224 * Try to wake up the main eloop so it will process
225 * dbus events that may have happened.
227 static void wakeup_main(void *data
)
229 struct wpas_dbus_priv
*priv
= data
;
231 /* Use SIGPOLL to break out of the eloop select() */
233 priv
->should_dispatch
= 1;
238 * integrate_with_eloop - Register our mainloop integration with dbus
239 * @connection: connection to the system message bus
240 * @priv: a dbus control interface data structure
241 * Returns: 0 on success, -1 on failure
243 static int integrate_with_eloop(struct wpas_dbus_priv
*priv
)
245 if (!dbus_connection_set_watch_functions(priv
->con
, add_watch
,
246 remove_watch
, watch_toggled
,
248 !dbus_connection_set_timeout_functions(priv
->con
, add_timeout
,
250 timeout_toggled
, priv
,
252 wpa_printf(MSG_ERROR
, "dbus: Failed to set callback "
257 if (eloop_register_signal(SIGPOLL
, process_wakeup_main
, priv
))
259 dbus_connection_set_wakeup_main_function(priv
->con
, wakeup_main
,
266 static int wpas_dbus_init_common(struct wpas_dbus_priv
*priv
)
271 /* Get a reference to the system bus */
272 dbus_error_init(&error
);
273 priv
->con
= dbus_bus_get(DBUS_BUS_SYSTEM
, &error
);
275 wpa_printf(MSG_ERROR
, "dbus: Could not acquire the system "
276 "bus: %s - %s", error
.name
, error
.message
);
279 dbus_error_free(&error
);
285 static int wpas_dbus_init_common_finish(struct wpas_dbus_priv
*priv
)
287 /* Tell dbus about our mainloop integration functions */
288 integrate_with_eloop(priv
);
291 * Dispatch initial DBus messages that may have come in since the bus
292 * name was claimed above. Happens when clients are quick to notice the
295 * FIXME: is there a better solution to this problem?
297 eloop_register_timeout(0, 50, dispatch_initial_dbus_messages
,
304 static void wpas_dbus_deinit_common(struct wpas_dbus_priv
*priv
)
307 eloop_cancel_timeout(dispatch_initial_dbus_messages
,
309 dbus_connection_set_watch_functions(priv
->con
, NULL
, NULL
,
311 dbus_connection_set_timeout_functions(priv
->con
, NULL
, NULL
,
313 dbus_connection_unref(priv
->con
);
320 struct wpas_dbus_priv
* wpas_dbus_init(struct wpa_global
*global
)
322 struct wpas_dbus_priv
*priv
;
324 priv
= os_zalloc(sizeof(*priv
));
327 priv
->global
= global
;
329 if (wpas_dbus_init_common(priv
) < 0) {
330 wpas_dbus_deinit(priv
);
334 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
335 if (wpas_dbus_ctrl_iface_init(priv
) < 0) {
336 wpas_dbus_deinit(priv
);
339 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
341 #ifdef CONFIG_CTRL_IFACE_DBUS
342 if (wpa_supplicant_dbus_ctrl_iface_init(priv
) < 0) {
343 wpas_dbus_deinit(priv
);
346 #endif /* CONFIG_CTRL_IFACE_DBUS */
348 if (wpas_dbus_init_common_finish(priv
) < 0) {
349 wpas_dbus_deinit(priv
);
357 void wpas_dbus_deinit(struct wpas_dbus_priv
*priv
)
362 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
363 wpas_dbus_ctrl_iface_deinit(priv
);
364 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
366 #ifdef CONFIG_CTRL_IFACE_DBUS
367 /* TODO: is any deinit needed? */
368 #endif /* CONFIG_CTRL_IFACE_DBUS */
370 wpas_dbus_deinit_common(priv
);