1214501Srpaulo/*
2214501Srpaulo * wpa_supplicant D-Bus control interface - common functionality
3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4214501Srpaulo * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
5214501Srpaulo * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6214501Srpaulo *
7252190Srpaulo * This software may be distributed under the terms of the BSD license.
8252190Srpaulo * See README for more details.
9214501Srpaulo */
10214501Srpaulo
11214501Srpaulo#include "utils/includes.h"
12214501Srpaulo#include <dbus/dbus.h>
13214501Srpaulo
14214501Srpaulo#include "utils/common.h"
15214501Srpaulo#include "utils/eloop.h"
16214501Srpaulo#include "dbus_common.h"
17214501Srpaulo#include "dbus_common_i.h"
18214501Srpaulo#include "dbus_new.h"
19214501Srpaulo#include "dbus_old.h"
20214501Srpaulo
21214501Srpaulo
22214501Srpaulo#ifndef SIGPOLL
23214501Srpaulo#ifdef SIGIO
24214501Srpaulo/*
25214501Srpaulo * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
26214501Srpaulo * FreeBSD.
27214501Srpaulo */
28214501Srpaulo#define SIGPOLL SIGIO
29214501Srpaulo#endif
30214501Srpaulo#endif
31214501Srpaulo
32214501Srpaulo
33214501Srpaulostatic void dispatch_data(DBusConnection *con)
34214501Srpaulo{
35214501Srpaulo	while (dbus_connection_get_dispatch_status(con) ==
36214501Srpaulo	       DBUS_DISPATCH_DATA_REMAINS)
37214501Srpaulo		dbus_connection_dispatch(con);
38214501Srpaulo}
39214501Srpaulo
40214501Srpaulo
41214501Srpaulo/**
42214501Srpaulo * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
43214501Srpaulo *     claiming bus name
44214501Srpaulo * @eloop_ctx: the DBusConnection to dispatch on
45214501Srpaulo * @timeout_ctx: unused
46214501Srpaulo *
47214501Srpaulo * If clients are quick to notice that service claimed its bus name,
48214501Srpaulo * there may have been messages that came in before initialization was
49214501Srpaulo * all finished.  Dispatch those here.
50214501Srpaulo */
51214501Srpaulostatic void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
52214501Srpaulo{
53214501Srpaulo	DBusConnection *con = eloop_ctx;
54214501Srpaulo	dispatch_data(con);
55214501Srpaulo}
56214501Srpaulo
57214501Srpaulo
58214501Srpaulostatic void process_watch(struct wpas_dbus_priv *priv,
59214501Srpaulo			  DBusWatch *watch, eloop_event_type type)
60214501Srpaulo{
61214501Srpaulo	dbus_connection_ref(priv->con);
62214501Srpaulo
63214501Srpaulo	priv->should_dispatch = 0;
64214501Srpaulo
65214501Srpaulo	if (type == EVENT_TYPE_READ)
66214501Srpaulo		dbus_watch_handle(watch, DBUS_WATCH_READABLE);
67214501Srpaulo	else if (type == EVENT_TYPE_WRITE)
68214501Srpaulo		dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
69214501Srpaulo	else if (type == EVENT_TYPE_EXCEPTION)
70214501Srpaulo		dbus_watch_handle(watch, DBUS_WATCH_ERROR);
71214501Srpaulo
72214501Srpaulo	if (priv->should_dispatch) {
73214501Srpaulo		dispatch_data(priv->con);
74214501Srpaulo		priv->should_dispatch = 0;
75214501Srpaulo	}
76214501Srpaulo
77214501Srpaulo	dbus_connection_unref(priv->con);
78214501Srpaulo}
79214501Srpaulo
80214501Srpaulo
81214501Srpaulostatic void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
82214501Srpaulo{
83214501Srpaulo	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
84214501Srpaulo}
85214501Srpaulo
86214501Srpaulo
87214501Srpaulostatic void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
88214501Srpaulo{
89214501Srpaulo	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
90214501Srpaulo}
91214501Srpaulo
92214501Srpaulo
93214501Srpaulostatic void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
94214501Srpaulo{
95214501Srpaulo	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
96214501Srpaulo}
97214501Srpaulo
98214501Srpaulo
99214501Srpaulostatic dbus_bool_t add_watch(DBusWatch *watch, void *data)
100214501Srpaulo{
101214501Srpaulo	struct wpas_dbus_priv *priv = data;
102214501Srpaulo	unsigned int flags;
103214501Srpaulo	int fd;
104214501Srpaulo
105214501Srpaulo	if (!dbus_watch_get_enabled(watch))
106214501Srpaulo		return TRUE;
107214501Srpaulo
108214501Srpaulo	flags = dbus_watch_get_flags(watch);
109214501Srpaulo	fd = dbus_watch_get_unix_fd(watch);
110214501Srpaulo
111214501Srpaulo	eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
112214501Srpaulo			    priv, watch);
113214501Srpaulo
114214501Srpaulo	if (flags & DBUS_WATCH_READABLE) {
115214501Srpaulo		eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
116214501Srpaulo				    priv, watch);
117214501Srpaulo	}
118214501Srpaulo	if (flags & DBUS_WATCH_WRITABLE) {
119214501Srpaulo		eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
120214501Srpaulo				    priv, watch);
121214501Srpaulo	}
122214501Srpaulo
123214501Srpaulo	dbus_watch_set_data(watch, priv, NULL);
124214501Srpaulo
125214501Srpaulo	return TRUE;
126214501Srpaulo}
127214501Srpaulo
128214501Srpaulo
129214501Srpaulostatic void remove_watch(DBusWatch *watch, void *data)
130214501Srpaulo{
131214501Srpaulo	unsigned int flags;
132214501Srpaulo	int fd;
133214501Srpaulo
134214501Srpaulo	flags = dbus_watch_get_flags(watch);
135214501Srpaulo	fd = dbus_watch_get_unix_fd(watch);
136214501Srpaulo
137214501Srpaulo	eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
138214501Srpaulo
139214501Srpaulo	if (flags & DBUS_WATCH_READABLE)
140214501Srpaulo		eloop_unregister_sock(fd, EVENT_TYPE_READ);
141214501Srpaulo	if (flags & DBUS_WATCH_WRITABLE)
142214501Srpaulo		eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
143214501Srpaulo
144214501Srpaulo	dbus_watch_set_data(watch, NULL, NULL);
145214501Srpaulo}
146214501Srpaulo
147214501Srpaulo
148214501Srpaulostatic void watch_toggled(DBusWatch *watch, void *data)
149214501Srpaulo{
150214501Srpaulo	if (dbus_watch_get_enabled(watch))
151214501Srpaulo		add_watch(watch, data);
152214501Srpaulo	else
153214501Srpaulo		remove_watch(watch, data);
154214501Srpaulo}
155214501Srpaulo
156214501Srpaulo
157214501Srpaulostatic void process_timeout(void *eloop_ctx, void *sock_ctx)
158214501Srpaulo{
159214501Srpaulo	DBusTimeout *timeout = sock_ctx;
160214501Srpaulo	dbus_timeout_handle(timeout);
161214501Srpaulo}
162214501Srpaulo
163214501Srpaulo
164214501Srpaulostatic dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
165214501Srpaulo{
166214501Srpaulo	struct wpas_dbus_priv *priv = data;
167214501Srpaulo	if (!dbus_timeout_get_enabled(timeout))
168214501Srpaulo		return TRUE;
169214501Srpaulo
170214501Srpaulo	eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
171214501Srpaulo			       process_timeout, priv, timeout);
172214501Srpaulo
173214501Srpaulo	dbus_timeout_set_data(timeout, priv, NULL);
174214501Srpaulo
175214501Srpaulo	return TRUE;
176214501Srpaulo}
177214501Srpaulo
178214501Srpaulo
179214501Srpaulostatic void remove_timeout(DBusTimeout *timeout, void *data)
180214501Srpaulo{
181214501Srpaulo	struct wpas_dbus_priv *priv = data;
182214501Srpaulo	eloop_cancel_timeout(process_timeout, priv, timeout);
183214501Srpaulo	dbus_timeout_set_data(timeout, NULL, NULL);
184214501Srpaulo}
185214501Srpaulo
186214501Srpaulo
187214501Srpaulostatic void timeout_toggled(DBusTimeout *timeout, void *data)
188214501Srpaulo{
189214501Srpaulo	if (dbus_timeout_get_enabled(timeout))
190214501Srpaulo		add_timeout(timeout, data);
191214501Srpaulo	else
192214501Srpaulo		remove_timeout(timeout, data);
193214501Srpaulo}
194214501Srpaulo
195214501Srpaulo
196214501Srpaulostatic void process_wakeup_main(int sig, void *signal_ctx)
197214501Srpaulo{
198214501Srpaulo	struct wpas_dbus_priv *priv = signal_ctx;
199214501Srpaulo
200214501Srpaulo	if (sig != SIGPOLL || !priv->con)
201214501Srpaulo		return;
202214501Srpaulo
203214501Srpaulo	if (dbus_connection_get_dispatch_status(priv->con) !=
204214501Srpaulo	    DBUS_DISPATCH_DATA_REMAINS)
205214501Srpaulo		return;
206214501Srpaulo
207214501Srpaulo	/* Only dispatch once - we do not want to starve other events */
208214501Srpaulo	dbus_connection_ref(priv->con);
209214501Srpaulo	dbus_connection_dispatch(priv->con);
210214501Srpaulo	dbus_connection_unref(priv->con);
211214501Srpaulo}
212214501Srpaulo
213214501Srpaulo
214214501Srpaulo/**
215214501Srpaulo * wakeup_main - Attempt to wake our mainloop up
216214501Srpaulo * @data: dbus control interface private data
217214501Srpaulo *
218214501Srpaulo * Try to wake up the main eloop so it will process
219214501Srpaulo * dbus events that may have happened.
220214501Srpaulo */
221214501Srpaulostatic void wakeup_main(void *data)
222214501Srpaulo{
223214501Srpaulo	struct wpas_dbus_priv *priv = data;
224214501Srpaulo
225214501Srpaulo	/* Use SIGPOLL to break out of the eloop select() */
226214501Srpaulo	raise(SIGPOLL);
227214501Srpaulo	priv->should_dispatch = 1;
228214501Srpaulo}
229214501Srpaulo
230214501Srpaulo
231214501Srpaulo/**
232214501Srpaulo * integrate_with_eloop - Register our mainloop integration with dbus
233214501Srpaulo * @connection: connection to the system message bus
234214501Srpaulo * @priv: a dbus control interface data structure
235214501Srpaulo * Returns: 0 on success, -1 on failure
236214501Srpaulo */
237214501Srpaulostatic int integrate_with_eloop(struct wpas_dbus_priv *priv)
238214501Srpaulo{
239214501Srpaulo	if (!dbus_connection_set_watch_functions(priv->con, add_watch,
240214501Srpaulo						 remove_watch, watch_toggled,
241214501Srpaulo						 priv, NULL) ||
242214501Srpaulo	    !dbus_connection_set_timeout_functions(priv->con, add_timeout,
243214501Srpaulo						   remove_timeout,
244214501Srpaulo						   timeout_toggled, priv,
245214501Srpaulo						   NULL)) {
246214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
247214501Srpaulo			   "functions");
248214501Srpaulo		return -1;
249214501Srpaulo	}
250214501Srpaulo
251214501Srpaulo	if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv))
252214501Srpaulo		return -1;
253214501Srpaulo	dbus_connection_set_wakeup_main_function(priv->con, wakeup_main,
254214501Srpaulo						 priv, NULL);
255214501Srpaulo
256214501Srpaulo	return 0;
257214501Srpaulo}
258214501Srpaulo
259214501Srpaulo
260214501Srpaulostatic int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
261214501Srpaulo{
262214501Srpaulo	DBusError error;
263214501Srpaulo	int ret = 0;
264214501Srpaulo
265214501Srpaulo	/* Get a reference to the system bus */
266214501Srpaulo	dbus_error_init(&error);
267214501Srpaulo	priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
268214501Srpaulo	if (!priv->con) {
269214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
270214501Srpaulo			   "bus: %s - %s", error.name, error.message);
271214501Srpaulo		ret = -1;
272214501Srpaulo	}
273214501Srpaulo	dbus_error_free(&error);
274214501Srpaulo
275214501Srpaulo	return ret;
276214501Srpaulo}
277214501Srpaulo
278214501Srpaulo
279214501Srpaulostatic int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
280214501Srpaulo{
281214501Srpaulo	/* Tell dbus about our mainloop integration functions */
282214501Srpaulo	integrate_with_eloop(priv);
283214501Srpaulo
284214501Srpaulo	/*
285214501Srpaulo	 * Dispatch initial DBus messages that may have come in since the bus
286214501Srpaulo	 * name was claimed above. Happens when clients are quick to notice the
287214501Srpaulo	 * service.
288214501Srpaulo	 *
289214501Srpaulo	 * FIXME: is there a better solution to this problem?
290214501Srpaulo	 */
291214501Srpaulo	eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
292214501Srpaulo	                       priv->con, NULL);
293214501Srpaulo
294214501Srpaulo	return 0;
295214501Srpaulo}
296214501Srpaulo
297214501Srpaulo
298214501Srpaulostatic void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
299214501Srpaulo{
300214501Srpaulo	if (priv->con) {
301214501Srpaulo		eloop_cancel_timeout(dispatch_initial_dbus_messages,
302214501Srpaulo				     priv->con, NULL);
303214501Srpaulo		dbus_connection_set_watch_functions(priv->con, NULL, NULL,
304214501Srpaulo						    NULL, NULL, NULL);
305214501Srpaulo		dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
306214501Srpaulo						      NULL, NULL, NULL);
307214501Srpaulo		dbus_connection_unref(priv->con);
308214501Srpaulo	}
309214501Srpaulo
310214501Srpaulo	os_free(priv);
311214501Srpaulo}
312214501Srpaulo
313214501Srpaulo
314214501Srpaulostruct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
315214501Srpaulo{
316214501Srpaulo	struct wpas_dbus_priv *priv;
317214501Srpaulo
318214501Srpaulo	priv = os_zalloc(sizeof(*priv));
319214501Srpaulo	if (priv == NULL)
320214501Srpaulo		return NULL;
321214501Srpaulo	priv->global = global;
322214501Srpaulo
323214501Srpaulo	if (wpas_dbus_init_common(priv) < 0) {
324214501Srpaulo		wpas_dbus_deinit(priv);
325214501Srpaulo		return NULL;
326214501Srpaulo	}
327214501Srpaulo
328214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
329214501Srpaulo	if (wpas_dbus_ctrl_iface_init(priv) < 0) {
330214501Srpaulo		wpas_dbus_deinit(priv);
331214501Srpaulo		return NULL;
332214501Srpaulo	}
333214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
334214501Srpaulo
335214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS
336214501Srpaulo	if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
337214501Srpaulo		wpas_dbus_deinit(priv);
338214501Srpaulo		return NULL;
339214501Srpaulo	}
340214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS */
341214501Srpaulo
342214501Srpaulo	if (wpas_dbus_init_common_finish(priv) < 0) {
343214501Srpaulo		wpas_dbus_deinit(priv);
344214501Srpaulo		return NULL;
345214501Srpaulo	}
346214501Srpaulo
347214501Srpaulo	return priv;
348214501Srpaulo}
349214501Srpaulo
350214501Srpaulo
351214501Srpaulovoid wpas_dbus_deinit(struct wpas_dbus_priv *priv)
352214501Srpaulo{
353214501Srpaulo	if (priv == NULL)
354214501Srpaulo		return;
355214501Srpaulo
356214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
357214501Srpaulo	wpas_dbus_ctrl_iface_deinit(priv);
358214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
359214501Srpaulo
360214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS
361214501Srpaulo	/* TODO: is any deinit needed? */
362214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS */
363214501Srpaulo
364214501Srpaulo	wpas_dbus_deinit_common(priv);
365214501Srpaulo}
366