ctrl_iface_dbus.c revision 10356433b643a2a5266f84a11ed4ac32d8c5c845
1/*
2 * WPA Supplicant / dbus-based control interface
3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include <dbus/dbus.h>
18
19#include "common.h"
20#include "eloop.h"
21#include "wpa.h"
22#include "wpa_supplicant.h"
23#include "config.h"
24#include "eapol_sm.h"
25#include "wpa_supplicant_i.h"
26#include "ctrl_iface_dbus.h"
27#include "ctrl_iface_dbus_handlers.h"
28#include "l2_packet.h"
29#include "preauth.h"
30#include "wpa_ctrl.h"
31#include "eap.h"
32
33#define DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)
34#define DBUS_VER(major, minor) ((major) << 8 | (minor))
35
36#if DBUS_VERSION < DBUS_VER(1,1)
37#define dbus_watch_get_unix_fd dbus_watch_get_fd
38#endif
39
40
41struct ctrl_iface_dbus_priv {
42	DBusConnection *con;
43	int should_dispatch;
44	struct wpa_global *global;
45
46	u32 next_objid;
47};
48
49
50static void process_watch(struct ctrl_iface_dbus_priv *iface,
51			  DBusWatch *watch, eloop_event_type type)
52{
53	dbus_connection_ref(iface->con);
54
55	iface->should_dispatch = 0;
56
57	if (type == EVENT_TYPE_READ)
58		dbus_watch_handle(watch, DBUS_WATCH_READABLE);
59	else if (type == EVENT_TYPE_WRITE)
60		dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
61	else if (type == EVENT_TYPE_EXCEPTION)
62		dbus_watch_handle(watch, DBUS_WATCH_ERROR);
63
64	if (iface->should_dispatch) {
65		while (dbus_connection_get_dispatch_status(iface->con) ==
66		       DBUS_DISPATCH_DATA_REMAINS)
67			dbus_connection_dispatch(iface->con);
68		iface->should_dispatch = 0;
69	}
70
71	dbus_connection_unref(iface->con);
72}
73
74
75static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
76{
77	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
78}
79
80
81static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
82{
83	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
84}
85
86
87static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
88{
89	process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
90}
91
92
93static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface,
94				       DBusWatch *watch)
95{
96	unsigned int flags;
97	int fd;
98
99	if (!dbus_watch_get_enabled(watch))
100		return;
101
102	flags = dbus_watch_get_flags(watch);
103	fd = dbus_watch_get_unix_fd(watch);
104
105	eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
106			    iface, watch);
107
108	if (flags & DBUS_WATCH_READABLE) {
109		eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
110				    iface, watch);
111	}
112	if (flags & DBUS_WATCH_WRITABLE) {
113		eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
114				    iface, watch);
115	}
116
117	dbus_watch_set_data(watch, iface, NULL);
118}
119
120
121static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface,
122					  DBusWatch *watch)
123{
124	unsigned int flags;
125	int fd;
126
127	flags = dbus_watch_get_flags(watch);
128	fd = dbus_watch_get_unix_fd(watch);
129
130	eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
131
132	if (flags & DBUS_WATCH_READABLE)
133		eloop_unregister_sock(fd, EVENT_TYPE_READ);
134	if (flags & DBUS_WATCH_WRITABLE)
135		eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
136
137	dbus_watch_set_data(watch, NULL, NULL);
138}
139
140
141static dbus_bool_t add_watch(DBusWatch *watch, void *data)
142{
143	connection_setup_add_watch(data, watch);
144	return TRUE;
145}
146
147
148static void remove_watch(DBusWatch *watch, void *data)
149{
150	connection_setup_remove_watch(data, watch);
151}
152
153
154static void watch_toggled(DBusWatch *watch, void *data)
155{
156	if (dbus_watch_get_enabled(watch))
157		add_watch(watch, data);
158	else
159		remove_watch(watch, data);
160}
161
162
163static void process_timeout(void *eloop_ctx, void *sock_ctx)
164{
165	DBusTimeout *timeout = sock_ctx;
166
167	dbus_timeout_handle(timeout);
168}
169
170
171static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface,
172					 DBusTimeout *timeout)
173{
174	if (!dbus_timeout_get_enabled(timeout))
175		return;
176
177	eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
178			       process_timeout, iface, timeout);
179
180	dbus_timeout_set_data(timeout, iface, NULL);
181}
182
183
184static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface,
185					    DBusTimeout *timeout)
186{
187	eloop_cancel_timeout(process_timeout, iface, timeout);
188	dbus_timeout_set_data(timeout, NULL, NULL);
189}
190
191
192static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
193{
194	if (!dbus_timeout_get_enabled(timeout))
195		return TRUE;
196
197	connection_setup_add_timeout(data, timeout);
198
199	return TRUE;
200}
201
202
203static void remove_timeout(DBusTimeout *timeout, void *data)
204{
205	connection_setup_remove_timeout(data, timeout);
206}
207
208
209static void timeout_toggled(DBusTimeout *timeout, void *data)
210{
211	if (dbus_timeout_get_enabled(timeout))
212		add_timeout(timeout, data);
213	else
214		remove_timeout(timeout, data);
215}
216
217
218static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx)
219{
220	struct ctrl_iface_dbus_priv *iface = signal_ctx;
221
222	if (sig != SIGPOLL || !iface->con)
223		return;
224
225	if (dbus_connection_get_dispatch_status(iface->con) !=
226	    DBUS_DISPATCH_DATA_REMAINS)
227		return;
228
229	/* Only dispatch once - we do not want to starve other events */
230	dbus_connection_ref(iface->con);
231	dbus_connection_dispatch(iface->con);
232	dbus_connection_unref(iface->con);
233}
234
235
236/**
237 * wakeup_main - Attempt to wake our mainloop up
238 * @data: dbus control interface private data
239 *
240 * Try to wake up the main eloop so it will process
241 * dbus events that may have happened.
242 */
243static void wakeup_main(void *data)
244{
245	struct ctrl_iface_dbus_priv *iface = data;
246
247	/* Use SIGPOLL to break out of the eloop select() */
248	raise(SIGPOLL);
249	iface->should_dispatch = 1;
250}
251
252
253/**
254 * connection_setup_wakeup_main - Tell dbus about our wakeup_main function
255 * @iface: dbus control interface private data
256 * Returns: 0 on success, -1 on failure
257 *
258 * Register our wakeup_main handler with dbus
259 */
260static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface)
261{
262	if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface))
263		return -1;
264
265	dbus_connection_set_wakeup_main_function(iface->con, wakeup_main,
266						 iface, NULL);
267
268	return 0;
269}
270
271
272/**
273 * wpa_supplicant_dbus_next_objid - Return next available object id
274 * @iface: dbus control interface private data
275 * Returns: Object id
276 */
277u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface)
278{
279	return iface->next_objid++;
280}
281
282
283/**
284 * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
285 * @path: The dbus object path
286 * @network: (out) the configured network this object path refers to, if any
287 * @bssid: (out) the scanned bssid this object path refers to, if any
288 * Returns: The object path of the network interface this path refers to
289 *
290 * For a given object path, decomposes the object path into object id, network,
291 * and BSSID parts, if those parts exist.
292 */
293char * wpas_dbus_decompose_object_path(const char *path, char **network,
294				       char **bssid)
295{
296	const unsigned int dev_path_prefix_len =
297		strlen(WPAS_DBUS_PATH_INTERFACES "/");
298	char *obj_path_only;
299	char *next_sep;
300
301	/* Be a bit paranoid about path */
302	if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
303			     dev_path_prefix_len))
304		return NULL;
305
306	/* Ensure there's something at the end of the path */
307	if ((path + dev_path_prefix_len)[0] == '\0')
308		return NULL;
309
310	obj_path_only = strdup(path);
311	if (obj_path_only == NULL)
312		return NULL;
313
314	next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
315	if (next_sep != NULL) {
316		const char *net_part = strstr(next_sep,
317					      WPAS_DBUS_NETWORKS_PART "/");
318		const char *bssid_part = strstr(next_sep,
319						WPAS_DBUS_BSSIDS_PART "/");
320
321		if (network && net_part) {
322			/* Deal with a request for a configured network */
323			const char *net_name = net_part +
324				strlen(WPAS_DBUS_NETWORKS_PART "/");
325			*network = NULL;
326			if (strlen(net_name))
327				*network = strdup(net_name);
328		} else if (bssid && bssid_part) {
329			/* Deal with a request for a scanned BSSID */
330			const char *bssid_name = bssid_part +
331				strlen(WPAS_DBUS_BSSIDS_PART "/");
332			if (strlen(bssid_name))
333				*bssid = strdup(bssid_name);
334			else
335				*bssid = NULL;
336		}
337
338		/* Cut off interface object path before "/" */
339		*next_sep = '\0';
340	}
341
342	return obj_path_only;
343}
344
345
346/**
347 * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
348 * @message: Pointer to incoming dbus message this error refers to
349 * Returns: A dbus error message
350 *
351 * Convenience function to create and return an invalid interface error
352 */
353DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
354{
355	return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
356				      "wpa_supplicant knows nothing about "
357				      "this interface.");
358}
359
360
361/**
362 * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
363 * @message: Pointer to incoming dbus message this error refers to
364 * Returns: a dbus error message
365 *
366 * Convenience function to create and return an invalid network error
367 */
368DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
369{
370	return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
371				      "The requested network does not exist.");
372}
373
374
375/**
376 * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
377 * @message: Pointer to incoming dbus message this error refers to
378 * Returns: a dbus error message
379 *
380 * Convenience function to create and return an invalid bssid error
381 */
382static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
383{
384	return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
385				      "The BSSID requested was invalid.");
386}
387
388
389/**
390 * wpas_dispatch_network_method - dispatch messages for configured networks
391 * @message: the incoming dbus message
392 * @wpa_s: a network interface's data
393 * @network_id: id of the configured network we're interested in
394 * Returns: a reply dbus message, or a dbus error message
395 *
396 * This function dispatches all incoming dbus messages for configured networks.
397 */
398static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
399						  struct wpa_supplicant *wpa_s,
400						  int network_id)
401{
402	DBusMessage *reply = NULL;
403	const char *method = dbus_message_get_member(message);
404	struct wpa_ssid *ssid;
405
406	ssid = wpa_config_get_network(wpa_s->conf, network_id);
407	if (ssid == NULL)
408		return wpas_dbus_new_invalid_network_error(message);
409
410	if (!strcmp(method, "set"))
411		reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
412	else if (!strcmp(method, "enable"))
413		reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
414	else if (!strcmp(method, "disable"))
415		reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
416
417	return reply;
418}
419
420
421/**
422 * wpas_dispatch_bssid_method - dispatch messages for scanned networks
423 * @message: the incoming dbus message
424 * @wpa_s: a network interface's data
425 * @bssid: bssid of the scanned network we're interested in
426 * Returns: a reply dbus message, or a dbus error message
427 *
428 * This function dispatches all incoming dbus messages for scanned networks.
429 */
430static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
431						struct wpa_supplicant *wpa_s,
432						const char *bssid)
433{
434	DBusMessage *reply = NULL;
435	const char *method = dbus_message_get_member(message);
436	struct wpa_scan_result * res = NULL;
437	int i;
438
439	/* Ensure we actually have scan data */
440	if (wpa_s->scan_results == NULL &&
441	    wpa_supplicant_get_scan_results(wpa_s) < 0) {
442		reply = wpas_dbus_new_invalid_bssid_error(message);
443		goto out;
444	}
445
446	/* Find the bssid's scan data */
447	for (i = 0; i < wpa_s->num_scan_results; i++) {
448		struct wpa_scan_result * search_res = &wpa_s->scan_results[i];
449		char mac_str[18];
450
451		memset(mac_str, 0, sizeof(mac_str));
452		snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT,
453			 MAC2STR(search_res->bssid));
454		if (!strcmp(bssid, mac_str)) {
455			res = search_res;
456		}
457	}
458
459	if (!res) {
460		reply = wpas_dbus_new_invalid_bssid_error(message);
461		goto out;
462	}
463
464	/* Dispatch the method call against the scanned bssid */
465	if (!strcmp(method, "properties"))
466		reply = wpas_dbus_bssid_properties(message, wpa_s, res);
467
468out:
469	return reply;
470}
471
472
473/**
474 * wpas_iface_message_handler - Dispatch messages for interfaces or networks
475 * @connection: Connection to the system message bus
476 * @message: An incoming dbus message
477 * @user_data: A pointer to a dbus control interface data structure
478 * Returns: Whether or not the message was handled
479 *
480 * This function dispatches all incoming dbus messages for network interfaces,
481 * or objects owned by them, such as scanned BSSIDs and configured networks.
482 */
483static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
484						    DBusMessage *message,
485						    void *user_data)
486{
487	struct wpa_supplicant *wpa_s = user_data;
488	const char *method = dbus_message_get_member(message);
489	const char *path = dbus_message_get_path(message);
490	const char *msg_interface = dbus_message_get_interface(message);
491	char *iface_obj_path = NULL;
492	char *network = NULL;
493	char *bssid = NULL;
494	DBusMessage *reply = NULL;
495
496	/* Caller must specify a message interface */
497	if (!msg_interface)
498		goto out;
499
500	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
501	                                                 &bssid);
502	if (iface_obj_path == NULL) {
503		reply = wpas_dbus_new_invalid_iface_error(message);
504		goto out;
505	}
506
507	/* Make sure the message's object path actually refers to the
508	 * wpa_supplicant structure it's supposed to (which is wpa_s)
509	 */
510	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
511	                                          iface_obj_path) != wpa_s) {
512		reply = wpas_dbus_new_invalid_iface_error(message);
513		goto out;
514	}
515
516	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
517		/* A method for one of this interface's configured networks */
518		int nid = strtoul(network, NULL, 10);
519		if (errno != EINVAL)
520			reply = wpas_dispatch_network_method(message, wpa_s,
521							     nid);
522		else
523			reply = wpas_dbus_new_invalid_network_error(message);
524	} else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
525		/* A method for one of this interface's scanned BSSIDs */
526		reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
527	} else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
528		/* A method for an interface only. */
529		if (!strcmp(method, "scan"))
530			reply = wpas_dbus_iface_scan(message, wpa_s);
531		else if (!strcmp(method, "scanResults"))
532			reply = wpas_dbus_iface_scan_results(message, wpa_s);
533		else if (!strcmp(method, "addNetwork"))
534			reply = wpas_dbus_iface_add_network(message, wpa_s);
535		else if (!strcmp(method, "removeNetwork"))
536			reply = wpas_dbus_iface_remove_network(message, wpa_s);
537		else if (!strcmp(method, "selectNetwork"))
538			reply = wpas_dbus_iface_select_network(message, wpa_s);
539		else if (!strcmp(method, "capabilities"))
540			reply = wpas_dbus_iface_capabilities(message, wpa_s);
541		else if (!strcmp(method, "disconnect"))
542			reply = wpas_dbus_iface_disconnect(message, wpa_s);
543		else if (!strcmp(method, "setAPScan"))
544			reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
545		else if (!strcmp(method, "state"))
546			reply = wpas_dbus_iface_get_state(message, wpa_s);
547		else if (!strcmp(method, "setBlobs"))
548			reply = wpas_dbus_iface_set_blobs(message, wpa_s);
549		else if (!strcmp(method, "removeBlobs"))
550			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
551	}
552
553	/* If the message was handled, send back the reply */
554	if (reply) {
555		dbus_connection_send(connection, reply, NULL);
556		dbus_message_unref(reply);
557	}
558
559out:
560	free(iface_obj_path);
561	free(network);
562	free(bssid);
563	return reply ? DBUS_HANDLER_RESULT_HANDLED :
564		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
565}
566
567
568/**
569 * wpas_message_handler - dispatch incoming dbus messages
570 * @connection: connection to the system message bus
571 * @message: an incoming dbus message
572 * @user_data: a pointer to a dbus control interface data structure
573 * Returns: whether or not the message was handled
574 *
575 * This function dispatches all incoming dbus messages to the correct
576 * handlers, depending on what the message's target object path is,
577 * and what the method call is.
578 */
579static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
580	DBusMessage *message, void *user_data)
581{
582	struct ctrl_iface_dbus_priv *ctrl_iface = user_data;
583	const char *method;
584	const char *path;
585	const char *msg_interface;
586	DBusMessage *reply = NULL;
587
588	method = dbus_message_get_member(message);
589	path = dbus_message_get_path(message);
590	msg_interface = dbus_message_get_interface(message);
591	if (!method || !path || !ctrl_iface || !msg_interface)
592		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
593
594	/* Validate the method interface */
595	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
596		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
597
598	if (!strcmp(path, WPAS_DBUS_PATH)) {
599		/* dispatch methods against our global dbus interface here */
600		if (!strcmp(method, "addInterface")) {
601			reply = wpas_dbus_global_add_interface(
602				message, ctrl_iface->global);
603		} else if (!strcmp(method, "removeInterface")) {
604			reply = wpas_dbus_global_remove_interface(
605				message, ctrl_iface->global);
606		} else if (!strcmp(method, "getInterface")) {
607			reply = wpas_dbus_global_get_interface(
608				message, ctrl_iface->global);
609		}
610	}
611
612	/* If the message was handled, send back the reply */
613	if (reply) {
614		dbus_connection_send(connection, reply, NULL);
615		dbus_message_unref(reply);
616	}
617
618	return reply ? DBUS_HANDLER_RESULT_HANDLED :
619		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
620}
621
622
623/**
624 * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
625 * @wpa_s: %wpa_supplicant network interface data
626 * Returns: 0 on success, -1 on failure
627 *
628 * Notify listeners that this interface has updated scan results.
629 */
630void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
631{
632	struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface;
633	DBusMessage *signal;
634	const char *path;
635
636	/* Do nothing if the control interface is not turned on */
637	if (iface == NULL)
638		return;
639
640	path = wpa_supplicant_get_dbus_path(wpa_s);
641	if (path == NULL) {
642		perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
643		       "interface didn't have a dbus path");
644		wpa_printf(MSG_ERROR,
645		           "wpa_supplicant_dbus_notify_scan_results[dbus]: "
646		           "interface didn't have a dbus path; can't send "
647		           "scan result signal.");
648		return;
649	}
650	signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
651					 "ScanResultsAvailable");
652	if (signal == NULL) {
653		perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
654		       "couldn't create dbus signal; likely out of memory");
655		wpa_printf(MSG_ERROR, "dbus control interface: not enough "
656			   "memory to send scan results signal.");
657		return;
658	}
659	dbus_connection_send(iface->con, signal, NULL);
660	dbus_message_unref(signal);
661}
662
663
664/**
665 * wpa_supplicant_dbus_notify_state_change - Send a state change signal
666 * @wpa_s: %wpa_supplicant network interface data
667 * @new_state: new state wpa_supplicant is entering
668 * @old_state: old state wpa_supplicant is leaving
669 * Returns: 0 on success, -1 on failure
670 *
671 * Notify listeners that wpa_supplicant has changed state
672 */
673void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
674					     wpa_states new_state,
675					     wpa_states old_state)
676{
677	struct ctrl_iface_dbus_priv *iface;
678	DBusMessage *signal = NULL;
679	const char *path;
680	const char *new_state_str, *old_state_str;
681
682	/* Do nothing if the control interface is not turned on */
683	if (wpa_s->global == NULL)
684		return;
685	iface = wpa_s->global->dbus_ctrl_iface;
686	if (iface == NULL)
687		return;
688
689	/* Only send signal if state really changed */
690	if (new_state == old_state)
691		return;
692
693	path = wpa_supplicant_get_dbus_path(wpa_s);
694	if (path == NULL) {
695		perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
696		       "interface didn't have a dbus path");
697		wpa_printf(MSG_ERROR,
698		           "wpa_supplicant_dbus_notify_state_change[dbus]: "
699		           "interface didn't have a dbus path; can't send "
700		           "signal.");
701		return;
702	}
703	signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
704					 "StateChange");
705	if (signal == NULL) {
706		perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
707		       "couldn't create dbus signal; likely out of memory");
708		wpa_printf(MSG_ERROR,
709		           "wpa_supplicant_dbus_notify_state_change[dbus]: "
710		           "couldn't create dbus signal; likely out of "
711		           "memory.");
712		return;
713	}
714
715	new_state_str = wpa_supplicant_state_txt(new_state);
716	old_state_str = wpa_supplicant_state_txt(old_state);
717	if (new_state_str == NULL || old_state_str == NULL) {
718		perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
719		       "couldn't convert state strings");
720		wpa_printf(MSG_ERROR,
721		           "wpa_supplicant_dbus_notify_state_change[dbus]: "
722		           "couldn't convert state strings.");
723		goto out;
724	}
725
726	if (!dbus_message_append_args(signal,
727	                              DBUS_TYPE_STRING, &new_state_str,
728	                              DBUS_TYPE_STRING, &old_state_str,
729	                              DBUS_TYPE_INVALID)) {
730		perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
731		       "not enough memory to construct state change signal.");
732		wpa_printf(MSG_ERROR,
733		           "wpa_supplicant_dbus_notify_state_change[dbus]: "
734		           "not enough memory to construct state change "
735		           "signal.");
736		goto out;
737	}
738	dbus_connection_send(iface->con, signal, NULL);
739
740out:
741	dbus_message_unref(signal);
742}
743
744
745/**
746 * integrate_with_eloop - Register our mainloop integration with dbus
747 * @connection: connection to the system message bus
748 * @iface: a dbus control interface data structure
749 * Returns: 0 on success, -1 on failure
750 *
751 * We register our mainloop integration functions with dbus here.
752 */
753static int integrate_with_eloop(DBusConnection *connection,
754	struct ctrl_iface_dbus_priv *iface)
755{
756	if (!dbus_connection_set_watch_functions(connection, add_watch,
757						 remove_watch, watch_toggled,
758						 iface, NULL)) {
759		perror("dbus_connection_set_watch_functions[dbus]");
760		wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
761		return -1;
762	}
763
764	if (!dbus_connection_set_timeout_functions(connection, add_timeout,
765						   remove_timeout,
766						   timeout_toggled, iface,
767						   NULL)) {
768		perror("dbus_connection_set_timeout_functions[dbus]");
769		wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
770		return -1;
771	}
772
773	if (connection_setup_wakeup_main(iface) < 0) {
774		perror("connection_setup_wakeup_main[dbus]");
775		wpa_printf(MSG_ERROR, "Could not setup main wakeup function.");
776		return -1;
777	}
778
779	return 0;
780}
781
782
783/**
784 * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
785 *     claiming bus name
786 * @eloop_ctx: the DBusConnection to dispatch on
787 * @timeout_ctx: unused
788 *
789 * If clients are quick to notice that wpa_supplicant claimed its bus name,
790 * there may have been messages that came in before initialization was
791 * all finished.  Dispatch those here.
792 */
793static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
794{
795	DBusConnection *con = eloop_ctx;
796
797	while (dbus_connection_get_dispatch_status(con) ==
798	       DBUS_DISPATCH_DATA_REMAINS)
799		dbus_connection_dispatch(con);
800}
801
802
803/**
804 * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
805 * @global: Pointer to global data from wpa_supplicant_init()
806 * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure
807 *
808 * Initialize the dbus control interface and start receiving commands from
809 * external programs over the bus.
810 */
811struct ctrl_iface_dbus_priv *
812wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global)
813{
814	struct ctrl_iface_dbus_priv *iface;
815	DBusError error;
816	int ret = -1;
817	DBusObjectPathVTable wpas_vtable = {
818		NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
819	};
820
821	iface = wpa_zalloc(sizeof(struct ctrl_iface_dbus_priv));
822	if (iface == NULL)
823		return NULL;
824
825	iface->global = global;
826
827	/* Get a reference to the system bus */
828	dbus_error_init(&error);
829	iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
830	dbus_error_free(&error);
831	if (!iface->con) {
832		perror("dbus_bus_get[ctrl_iface_dbus]");
833		wpa_printf(MSG_ERROR, "Could not acquire the system bus.");
834		goto fail;
835	}
836
837	/* Tell dbus about our mainloop integration functions */
838	if (integrate_with_eloop(iface->con, iface))
839		goto fail;
840
841	/* Register the message handler for the global dbus interface */
842	if (!dbus_connection_register_object_path(iface->con,
843						  WPAS_DBUS_PATH, &wpas_vtable,
844						  iface)) {
845		perror("dbus_connection_register_object_path[dbus]");
846		wpa_printf(MSG_ERROR, "Could not set up DBus message "
847			   "handler.");
848		goto fail;
849	}
850
851	/* Register our service with the message bus */
852	dbus_error_init(&error);
853	switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
854				      0, &error)) {
855	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
856		ret = 0;
857		break;
858	case DBUS_REQUEST_NAME_REPLY_EXISTS:
859	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
860	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
861		perror("dbus_bus_request_name[dbus]");
862		wpa_printf(MSG_ERROR, "Could not request DBus service name: "
863			   "already registered.");
864		break;
865	default:
866		perror("dbus_bus_request_name[dbus]");
867		wpa_printf(MSG_ERROR, "Could not request DBus service name: "
868			   "%s %s.", error.name, error.message);
869		break;
870	}
871	dbus_error_free(&error);
872
873	if (ret != 0)
874		goto fail;
875
876	wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
877		   "'.");
878
879	/*
880	 * Dispatch initial DBus messages that may have come in since the bus
881	 * name was claimed above. Happens when clients are quick to notice the
882	 * wpa_supplicant service.
883	 *
884	 * FIXME: is there a better solution to this problem?
885	 */
886	eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
887	                       iface->con, NULL);
888
889	return iface;
890
891fail:
892	wpa_supplicant_dbus_ctrl_iface_deinit(iface);
893	return NULL;
894}
895
896
897/**
898 * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface
899 * @iface: Pointer to dbus private data from
900 * wpa_supplicant_dbus_ctrl_iface_init()
901 *
902 * Deinitialize the dbus control interface that was initialized with
903 * wpa_supplicant_dbus_ctrl_iface_init().
904 */
905void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface)
906{
907	if (iface == NULL)
908		return;
909
910	if (iface->con) {
911		eloop_cancel_timeout(dispatch_initial_dbus_messages,
912				     iface->con, NULL);
913		dbus_connection_set_watch_functions(iface->con, NULL, NULL,
914						    NULL, NULL, NULL);
915		dbus_connection_set_timeout_functions(iface->con, NULL, NULL,
916						      NULL, NULL, NULL);
917		dbus_connection_unref(iface->con);
918	}
919
920	memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv));
921	free(iface);
922}
923
924
925/**
926 * wpas_dbus_register_new_iface - Register a new interface with dbus
927 * @global: Global %wpa_supplicant data
928 * @wpa_s: %wpa_supplicant interface description structure to register
929 * Returns: 0 on success, -1 on error
930 *
931 * Registers a new interface with dbus and assigns it a dbus object path.
932 */
933int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
934{
935	struct ctrl_iface_dbus_priv *ctrl_iface =
936		wpa_s->global->dbus_ctrl_iface;
937	DBusConnection * con;
938	u32 next;
939	DBusObjectPathVTable vtable = {
940		NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
941	};
942	char *path;
943	int ret = -1;
944
945	/* Do nothing if the control interface is not turned on */
946	if (ctrl_iface == NULL)
947		return 0;
948
949	con = ctrl_iface->con;
950	next = wpa_supplicant_dbus_next_objid(ctrl_iface);
951
952	/* Create and set the interface's object path */
953	path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
954	if (path == NULL)
955		return -1;
956	snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
957		 WPAS_DBUS_PATH_INTERFACES "/%u",
958		 next);
959	if (wpa_supplicant_set_dbus_path(wpa_s, path)) {
960		wpa_printf(MSG_DEBUG,
961		           "Failed to set dbus path for interface %s",
962			   wpa_s->ifname);
963		goto out;
964	}
965
966	/* Register the message handler for the interface functions */
967	if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) {
968		perror("wpas_dbus_register_iface [dbus]");
969		wpa_printf(MSG_ERROR, "Could not set up DBus message "
970			   "handler for interface %s.", wpa_s->ifname);
971		goto out;
972	}
973	ret = 0;
974
975out:
976	free(path);
977	return ret;
978}
979
980
981/**
982 * wpas_dbus_unregister_iface - Unregister an interface from dbus
983 * @wpa_s: wpa_supplicant interface structure
984 * Returns: 0 on success, -1 on failure
985 *
986 * Unregisters the interface with dbus
987 */
988int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
989{
990	struct ctrl_iface_dbus_priv *ctrl_iface;
991	DBusConnection *con;
992	const char *path;
993
994	/* Do nothing if the control interface is not turned on */
995	if (wpa_s == NULL || wpa_s->global == NULL)
996		return 0;
997	ctrl_iface = wpa_s->global->dbus_ctrl_iface;
998	if (ctrl_iface == NULL)
999		return 0;
1000
1001	con = ctrl_iface->con;
1002	path = wpa_supplicant_get_dbus_path(wpa_s);
1003
1004	if (!dbus_connection_unregister_object_path(con, path))
1005		return -1;
1006
1007	free(wpa_s->dbus_path);
1008	wpa_s->dbus_path = NULL;
1009
1010	return 0;
1011}
1012
1013
1014/**
1015 * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
1016 * @global: Pointer to global data from wpa_supplicant_init()
1017 * @path: Pointer to a dbus object path representing an interface
1018 * Returns: Pointer to the interface or %NULL if not found
1019 */
1020struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
1021	struct wpa_global *global, const char *path)
1022{
1023	struct wpa_supplicant *wpa_s;
1024
1025	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
1026		if (strcmp(wpa_s->dbus_path, path) == 0)
1027			return wpa_s;
1028	}
1029	return NULL;
1030}
1031
1032
1033/**
1034 * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface
1035 * @wpa_s: wpa_supplicant interface structure
1036 * @path: dbus path to set on the interface
1037 * Returns: 0 on succes, -1 on error
1038 */
1039int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s,
1040				  const char *path)
1041{
1042	u32 len = strlen (path);
1043	if (len >= WPAS_DBUS_OBJECT_PATH_MAX)
1044		return -1;
1045	if (wpa_s->dbus_path)
1046		return -1;
1047	wpa_s->dbus_path = strdup(path);
1048	return 0;
1049}
1050
1051
1052/**
1053 * wpa_supplicant_get_dbus_path - Get an interface's dbus path
1054 * @wpa_s: %wpa_supplicant interface structure
1055 * Returns: Interface's dbus object path, or %NULL on error
1056 */
1057const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s)
1058{
1059	return wpa_s->dbus_path;
1060}
1061