1/*
2 * WPA Supplicant / dbus-based control interface
3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10#include <dbus/dbus.h>
11
12#include "common.h"
13#include "eloop.h"
14#include "wps/wps.h"
15#include "../config.h"
16#include "../wpa_supplicant_i.h"
17#include "../bss.h"
18#include "dbus_old.h"
19#include "dbus_old_handlers.h"
20#include "dbus_common_i.h"
21
22
23/**
24 * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
25 * @path: The dbus object path
26 * @network: (out) the configured network this object path refers to, if any
27 * @bssid: (out) the scanned bssid this object path refers to, if any
28 * Returns: The object path of the network interface this path refers to
29 *
30 * For a given object path, decomposes the object path into object id, network,
31 * and BSSID parts, if those parts exist.
32 */
33char * wpas_dbus_decompose_object_path(const char *path, char **network,
34				       char **bssid)
35{
36	const unsigned int dev_path_prefix_len =
37		strlen(WPAS_DBUS_PATH_INTERFACES "/");
38	char *obj_path_only;
39	char *next_sep;
40
41	/* Be a bit paranoid about path */
42	if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
43			     dev_path_prefix_len))
44		return NULL;
45
46	/* Ensure there's something at the end of the path */
47	if ((path + dev_path_prefix_len)[0] == '\0')
48		return NULL;
49
50	obj_path_only = os_strdup(path);
51	if (obj_path_only == NULL)
52		return NULL;
53
54	next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
55	if (next_sep != NULL) {
56		const char *net_part = strstr(next_sep,
57					      WPAS_DBUS_NETWORKS_PART "/");
58		const char *bssid_part = strstr(next_sep,
59						WPAS_DBUS_BSSIDS_PART "/");
60
61		if (network && net_part) {
62			/* Deal with a request for a configured network */
63			const char *net_name = net_part +
64				strlen(WPAS_DBUS_NETWORKS_PART "/");
65			*network = NULL;
66			if (strlen(net_name))
67				*network = os_strdup(net_name);
68		} else if (bssid && bssid_part) {
69			/* Deal with a request for a scanned BSSID */
70			const char *bssid_name = bssid_part +
71				strlen(WPAS_DBUS_BSSIDS_PART "/");
72			if (strlen(bssid_name))
73				*bssid = os_strdup(bssid_name);
74			else
75				*bssid = NULL;
76		}
77
78		/* Cut off interface object path before "/" */
79		*next_sep = '\0';
80	}
81
82	return obj_path_only;
83}
84
85
86/**
87 * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
88 * @message: Pointer to incoming dbus message this error refers to
89 * Returns: A dbus error message
90 *
91 * Convenience function to create and return an invalid interface error
92 */
93DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
94{
95	return dbus_message_new_error(
96		message, WPAS_ERROR_INVALID_IFACE,
97		"wpa_supplicant knows nothing about this interface.");
98}
99
100
101/**
102 * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
103 * @message: Pointer to incoming dbus message this error refers to
104 * Returns: a dbus error message
105 *
106 * Convenience function to create and return an invalid network error
107 */
108DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
109{
110	return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
111				      "The requested network does not exist.");
112}
113
114
115/**
116 * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
117 * @message: Pointer to incoming dbus message this error refers to
118 * Returns: a dbus error message
119 *
120 * Convenience function to create and return an invalid bssid error
121 */
122static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
123{
124	return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
125				      "The BSSID requested was invalid.");
126}
127
128
129/**
130 * wpas_dispatch_network_method - dispatch messages for configured networks
131 * @message: the incoming dbus message
132 * @wpa_s: a network interface's data
133 * @network_id: id of the configured network we're interested in
134 * Returns: a reply dbus message, or a dbus error message
135 *
136 * This function dispatches all incoming dbus messages for configured networks.
137 */
138static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
139						  struct wpa_supplicant *wpa_s,
140						  int network_id)
141{
142	DBusMessage *reply = NULL;
143	const char *method = dbus_message_get_member(message);
144	struct wpa_ssid *ssid;
145
146	ssid = wpa_config_get_network(wpa_s->conf, network_id);
147	if (ssid == NULL)
148		return wpas_dbus_new_invalid_network_error(message);
149
150	if (!strcmp(method, "set"))
151		reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
152	else if (!strcmp(method, "enable"))
153		reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
154	else if (!strcmp(method, "disable"))
155		reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
156
157	return reply;
158}
159
160
161/**
162 * wpas_dispatch_bssid_method - dispatch messages for scanned networks
163 * @message: the incoming dbus message
164 * @wpa_s: a network interface's data
165 * @bssid: bssid of the scanned network we're interested in
166 * Returns: a reply dbus message, or a dbus error message
167 *
168 * This function dispatches all incoming dbus messages for scanned networks.
169 */
170static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
171						struct wpa_supplicant *wpa_s,
172						const char *bssid_txt)
173{
174	u8 bssid[ETH_ALEN];
175	struct wpa_bss *bss;
176
177	if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0)
178		return wpas_dbus_new_invalid_bssid_error(message);
179
180	bss = wpa_bss_get_bssid(wpa_s, bssid);
181	if (bss == NULL)
182		return wpas_dbus_new_invalid_bssid_error(message);
183
184	/* Dispatch the method call against the scanned bssid */
185	if (os_strcmp(dbus_message_get_member(message), "properties") == 0)
186		return wpas_dbus_bssid_properties(message, wpa_s, bss);
187
188	return NULL;
189}
190
191
192/**
193 * wpas_iface_message_handler - Dispatch messages for interfaces or networks
194 * @connection: Connection to the system message bus
195 * @message: An incoming dbus message
196 * @user_data: A pointer to a dbus control interface data structure
197 * Returns: Whether or not the message was handled
198 *
199 * This function dispatches all incoming dbus messages for network interfaces,
200 * or objects owned by them, such as scanned BSSIDs and configured networks.
201 */
202static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
203						    DBusMessage *message,
204						    void *user_data)
205{
206	struct wpa_supplicant *wpa_s = user_data;
207	const char *method = dbus_message_get_member(message);
208	const char *path = dbus_message_get_path(message);
209	const char *msg_interface = dbus_message_get_interface(message);
210	char *iface_obj_path = NULL;
211	char *network = NULL;
212	char *bssid = NULL;
213	DBusMessage *reply = NULL;
214
215	/* Caller must specify a message interface */
216	if (!msg_interface)
217		goto out;
218
219	wpa_printf(MSG_MSGDUMP, "dbus[old/iface]: %s.%s (%s) [%s]",
220		   msg_interface, method, path,
221		   dbus_message_get_signature(message));
222
223	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
224							 &bssid);
225	if (iface_obj_path == NULL) {
226		reply = wpas_dbus_new_invalid_iface_error(message);
227		goto out;
228	}
229
230	/* Make sure the message's object path actually refers to the
231	 * wpa_supplicant structure it's supposed to (which is wpa_s)
232	 */
233	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
234						  iface_obj_path) != wpa_s) {
235		reply = wpas_dbus_new_invalid_iface_error(message);
236		goto out;
237	}
238
239	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
240		/* A method for one of this interface's configured networks */
241		int nid = strtoul(network, NULL, 10);
242
243		if (errno != EINVAL)
244			reply = wpas_dispatch_network_method(message, wpa_s,
245							     nid);
246		else
247			reply = wpas_dbus_new_invalid_network_error(message);
248	} else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
249		/* A method for one of this interface's scanned BSSIDs */
250		reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
251	} else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
252		/* A method for an interface only. */
253		if (!strcmp(method, "scan"))
254			reply = wpas_dbus_iface_scan(message, wpa_s);
255		else if (!strcmp(method, "scanResults"))
256			reply = wpas_dbus_iface_scan_results(message, wpa_s);
257		else if (!strcmp(method, "addNetwork"))
258			reply = wpas_dbus_iface_add_network(message, wpa_s);
259		else if (!strcmp(method, "removeNetwork"))
260			reply = wpas_dbus_iface_remove_network(message, wpa_s);
261		else if (!strcmp(method, "selectNetwork"))
262			reply = wpas_dbus_iface_select_network(message, wpa_s);
263		else if (!strcmp(method, "capabilities"))
264			reply = wpas_dbus_iface_capabilities(message, wpa_s);
265		else if (!strcmp(method, "disconnect"))
266			reply = wpas_dbus_iface_disconnect(message, wpa_s);
267		else if (!strcmp(method, "setAPScan"))
268			reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
269		else if (!strcmp(method, "setSmartcardModules"))
270			reply = wpas_dbus_iface_set_smartcard_modules(message,
271								      wpa_s);
272		else if (!strcmp(method, "state"))
273			reply = wpas_dbus_iface_get_state(message, wpa_s);
274		else if (!strcmp(method, "scanning"))
275			reply = wpas_dbus_iface_get_scanning(message, wpa_s);
276#ifndef CONFIG_NO_CONFIG_BLOBS
277		else if (!strcmp(method, "setBlobs"))
278			reply = wpas_dbus_iface_set_blobs(message, wpa_s);
279		else if (!strcmp(method, "removeBlobs"))
280			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
281#endif /* CONFIG_NO_CONFIG_BLOBS */
282#ifdef CONFIG_WPS
283		else if (os_strcmp(method, "wpsPbc") == 0)
284			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
285		else if (os_strcmp(method, "wpsPin") == 0)
286			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
287		else if (os_strcmp(method, "wpsReg") == 0)
288			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
289#endif /* CONFIG_WPS */
290		else if (os_strcmp(method, "flush") == 0)
291			reply = wpas_dbus_iface_flush(message, wpa_s);
292	}
293
294	/* If the message was handled, send back the reply */
295out:
296	if (reply) {
297		if (!dbus_message_get_no_reply(message))
298			dbus_connection_send(connection, reply, NULL);
299		dbus_message_unref(reply);
300	}
301
302	os_free(iface_obj_path);
303	os_free(network);
304	os_free(bssid);
305	return reply ? DBUS_HANDLER_RESULT_HANDLED :
306		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
307}
308
309
310/**
311 * wpas_message_handler - dispatch incoming dbus messages
312 * @connection: connection to the system message bus
313 * @message: an incoming dbus message
314 * @user_data: a pointer to a dbus control interface data structure
315 * Returns: whether or not the message was handled
316 *
317 * This function dispatches all incoming dbus messages to the correct
318 * handlers, depending on what the message's target object path is,
319 * and what the method call is.
320 */
321static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
322	DBusMessage *message, void *user_data)
323{
324	struct wpas_dbus_priv *ctrl_iface = user_data;
325	const char *method;
326	const char *path;
327	const char *msg_interface;
328	DBusMessage *reply = NULL;
329
330	method = dbus_message_get_member(message);
331	path = dbus_message_get_path(message);
332	msg_interface = dbus_message_get_interface(message);
333	if (!method || !path || !ctrl_iface || !msg_interface)
334		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
335
336	wpa_printf(MSG_MSGDUMP, "dbus[old]: %s.%s (%s) [%s]",
337		   msg_interface, method, path,
338		   dbus_message_get_signature(message));
339
340	/* Validate the method interface */
341	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
342		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
343
344	if (!strcmp(path, WPAS_DBUS_PATH)) {
345		/* dispatch methods against our global dbus interface here */
346		if (!strcmp(method, "addInterface")) {
347			reply = wpas_dbus_global_add_interface(
348				message, ctrl_iface->global);
349		} else if (!strcmp(method, "removeInterface")) {
350			reply = wpas_dbus_global_remove_interface(
351				message, ctrl_iface->global);
352		} else if (!strcmp(method, "getInterface")) {
353			reply = wpas_dbus_global_get_interface(
354				message, ctrl_iface->global);
355		} else if (!strcmp(method, "setDebugParams")) {
356			reply = wpas_dbus_global_set_debugparams(
357				message, ctrl_iface->global);
358		}
359	}
360
361	/* If the message was handled, send back the reply */
362	if (reply) {
363		if (!dbus_message_get_no_reply(message))
364			dbus_connection_send(connection, reply, NULL);
365		dbus_message_unref(reply);
366	}
367
368	return reply ? DBUS_HANDLER_RESULT_HANDLED :
369		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
370}
371
372
373/**
374 * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
375 * @wpa_s: %wpa_supplicant network interface data
376 * Returns: 0 on success, -1 on failure
377 *
378 * Notify listeners that this interface has updated scan results.
379 */
380void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
381{
382	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
383	DBusMessage *_signal;
384
385	/* Do nothing if the control interface is not turned on */
386	if (iface == NULL || !wpa_s->dbus_path)
387		return;
388
389	_signal = dbus_message_new_signal(wpa_s->dbus_path,
390					  WPAS_DBUS_IFACE_INTERFACE,
391					  "ScanResultsAvailable");
392	if (_signal == NULL) {
393		wpa_printf(MSG_ERROR,
394			   "dbus: Not enough memory to send scan results signal");
395		return;
396	}
397	dbus_connection_send(iface->con, _signal, NULL);
398	dbus_message_unref(_signal);
399}
400
401
402/**
403 * wpa_supplicant_dbus_notify_state_change - Send a state change signal
404 * @wpa_s: %wpa_supplicant network interface data
405 * @new_state: new state wpa_supplicant is entering
406 * @old_state: old state wpa_supplicant is leaving
407 * Returns: 0 on success, -1 on failure
408 *
409 * Notify listeners that wpa_supplicant has changed state
410 */
411void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
412					     enum wpa_states new_state,
413					     enum wpa_states old_state)
414{
415	struct wpas_dbus_priv *iface;
416	DBusMessage *_signal = NULL;
417	const char *new_state_str, *old_state_str;
418
419	if (wpa_s->dbus_path == NULL)
420		return; /* Skip signal since D-Bus setup is not yet ready */
421
422	/* Do nothing if the control interface is not turned on */
423	if (wpa_s->global == NULL)
424		return;
425	iface = wpa_s->global->dbus;
426	if (iface == NULL)
427		return;
428
429	/* Only send signal if state really changed */
430	if (new_state == old_state)
431		return;
432
433	_signal = dbus_message_new_signal(wpa_s->dbus_path,
434					  WPAS_DBUS_IFACE_INTERFACE,
435					  "StateChange");
436	if (_signal == NULL) {
437		wpa_printf(MSG_ERROR,
438			   "dbus: %s: could not create dbus signal; likely out of memory",
439			   __func__);
440		return;
441	}
442
443	new_state_str = wpa_supplicant_state_txt(new_state);
444	old_state_str = wpa_supplicant_state_txt(old_state);
445
446	if (!dbus_message_append_args(_signal,
447				      DBUS_TYPE_STRING, &new_state_str,
448				      DBUS_TYPE_STRING, &old_state_str,
449				      DBUS_TYPE_INVALID)) {
450		wpa_printf(MSG_ERROR,
451			   "dbus: %s: Not enough memory to construct state change signal",
452			   __func__);
453		goto out;
454	}
455
456	dbus_connection_send(iface->con, _signal, NULL);
457
458out:
459	dbus_message_unref(_signal);
460}
461
462
463/**
464 * wpa_supplicant_dbus_notify_scanning - send scanning status
465 * @wpa_s: %wpa_supplicant network interface data
466 * Returns: 0 on success, -1 on failure
467 *
468 * Notify listeners of interface scanning state changes
469 */
470void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
471{
472	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
473	DBusMessage *_signal;
474	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
475
476	/* Do nothing if the control interface is not turned on */
477	if (iface == NULL || !wpa_s->dbus_path)
478		return;
479
480	_signal = dbus_message_new_signal(wpa_s->dbus_path,
481					  WPAS_DBUS_IFACE_INTERFACE,
482					  "Scanning");
483	if (_signal == NULL) {
484		wpa_printf(MSG_ERROR,
485			   "dbus: Not enough memory to send scan results signal");
486		return;
487	}
488
489	if (dbus_message_append_args(_signal,
490				     DBUS_TYPE_BOOLEAN, &scanning,
491				     DBUS_TYPE_INVALID)) {
492		dbus_connection_send(iface->con, _signal, NULL);
493	} else {
494		wpa_printf(MSG_ERROR,
495			   "dbus: Not enough memory to construct signal");
496	}
497	dbus_message_unref(_signal);
498}
499
500
501#ifdef CONFIG_WPS
502void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
503					 const struct wps_credential *cred)
504{
505	struct wpas_dbus_priv *iface;
506	DBusMessage *_signal = NULL;
507
508	/* Do nothing if the control interface is not turned on */
509	if (wpa_s->global == NULL)
510		return;
511	iface = wpa_s->global->dbus;
512	if (iface == NULL || !wpa_s->dbus_path)
513		return;
514
515	_signal = dbus_message_new_signal(wpa_s->dbus_path,
516					  WPAS_DBUS_IFACE_INTERFACE,
517					  "WpsCred");
518	if (_signal == NULL) {
519		wpa_printf(MSG_ERROR,
520			   "dbus: %s: Could not create dbus signal; likely out of memory",
521			   __func__);
522		return;
523	}
524
525	if (!dbus_message_append_args(_signal,
526				      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
527				      &cred->cred_attr, cred->cred_attr_len,
528				      DBUS_TYPE_INVALID)) {
529		wpa_printf(MSG_ERROR,
530			   "dbus: %s: Not enough memory to construct signal",
531			   __func__);
532		goto out;
533	}
534
535	dbus_connection_send(iface->con, _signal, NULL);
536
537out:
538	dbus_message_unref(_signal);
539}
540#else /* CONFIG_WPS */
541void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
542					 const struct wps_credential *cred)
543{
544}
545#endif /* CONFIG_WPS */
546
547void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
548					      int depth, const char *subject,
549					      const char *cert_hash,
550					      const struct wpabuf *cert)
551{
552	struct wpas_dbus_priv *iface;
553	DBusMessage *_signal = NULL;
554	const char *hash;
555	const char *cert_hex;
556	int cert_hex_len;
557
558	/* Do nothing if the control interface is not turned on */
559	if (wpa_s->global == NULL)
560		return;
561	iface = wpa_s->global->dbus;
562	if (iface == NULL || !wpa_s->dbus_path)
563		return;
564
565	_signal = dbus_message_new_signal(wpa_s->dbus_path,
566					  WPAS_DBUS_IFACE_INTERFACE,
567					  "Certification");
568	if (_signal == NULL) {
569		wpa_printf(MSG_ERROR,
570			   "dbus: %s: Could not create dbus signal; likely out of memory",
571			   __func__);
572		return;
573	}
574
575	hash = cert_hash ? cert_hash : "";
576	cert_hex = cert ? wpabuf_head(cert) : "";
577	cert_hex_len = cert ? wpabuf_len(cert) : 0;
578
579	if (!dbus_message_append_args(_signal,
580				      DBUS_TYPE_INT32, &depth,
581				      DBUS_TYPE_STRING, &subject,
582				      DBUS_TYPE_STRING, &hash,
583				      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
584				      &cert_hex, cert_hex_len,
585				      DBUS_TYPE_INVALID)) {
586		wpa_printf(MSG_ERROR,
587			   "dbus: %s: Not enough memory to construct signal",
588			   __func__);
589		goto out;
590	}
591
592	dbus_connection_send(iface->con, _signal, NULL);
593
594out:
595	dbus_message_unref(_signal);
596
597}
598
599
600/**
601 * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
602 * @global: Pointer to global data from wpa_supplicant_init()
603 * Returns: 0 on success, -1 on failure
604 *
605 * Initialize the dbus control interface and start receiving commands from
606 * external programs over the bus.
607 */
608int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
609{
610	DBusError error;
611	int ret = -1;
612	DBusObjectPathVTable wpas_vtable = {
613		NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
614	};
615
616	/* Register the message handler for the global dbus interface */
617	if (!dbus_connection_register_object_path(iface->con,
618						  WPAS_DBUS_PATH, &wpas_vtable,
619						  iface)) {
620		wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
621		return -1;
622	}
623
624	/* Register our service with the message bus */
625	dbus_error_init(&error);
626	switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
627				      0, &error)) {
628	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
629		ret = 0;
630		break;
631	case DBUS_REQUEST_NAME_REPLY_EXISTS:
632	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
633	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
634		wpa_printf(MSG_ERROR,
635			   "dbus: Could not request service name: already registered");
636		break;
637	default:
638		wpa_printf(MSG_ERROR,
639			   "dbus: Could not request service name: %s %s",
640			   error.name, error.message);
641		break;
642	}
643	dbus_error_free(&error);
644
645	if (ret != 0)
646		return -1;
647
648	wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
649		   "'.");
650
651	return 0;
652}
653
654
655/**
656 * wpas_dbus_register_new_iface - Register a new interface with dbus
657 * @wpa_s: %wpa_supplicant interface description structure to register
658 * Returns: 0 on success, -1 on error
659 *
660 * Registers a new interface with dbus and assigns it a dbus object path.
661 */
662int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
663{
664	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
665	DBusConnection * con;
666	u32 next;
667	DBusObjectPathVTable vtable = {
668		NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
669	};
670
671	/* Do nothing if the control interface is not turned on */
672	if (ctrl_iface == NULL)
673		return 0;
674
675	con = ctrl_iface->con;
676	next = ctrl_iface->next_objid++;
677
678	/* Create and set the interface's object path */
679	wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
680	if (wpa_s->dbus_path == NULL)
681		return -1;
682	os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
683		    WPAS_DBUS_PATH_INTERFACES "/%u",
684		    next);
685
686	/* Register the message handler for the interface functions */
687	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
688					       wpa_s)) {
689		wpa_printf(MSG_ERROR,
690			   "dbus: Could not set up message handler for interface %s",
691			   wpa_s->ifname);
692		return -1;
693	}
694
695	return 0;
696}
697
698
699/**
700 * wpas_dbus_unregister_iface - Unregister an interface from dbus
701 * @wpa_s: wpa_supplicant interface structure
702 * Returns: 0 on success, -1 on failure
703 *
704 * Unregisters the interface with dbus
705 */
706int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
707{
708	struct wpas_dbus_priv *ctrl_iface;
709	DBusConnection *con;
710
711	/* Do nothing if the control interface is not turned on */
712	if (wpa_s == NULL || wpa_s->global == NULL)
713		return 0;
714	ctrl_iface = wpa_s->global->dbus;
715	if (ctrl_iface == NULL || wpa_s->dbus_path == NULL)
716		return 0;
717
718	con = ctrl_iface->con;
719	if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path))
720		return -1;
721
722	os_free(wpa_s->dbus_path);
723	wpa_s->dbus_path = NULL;
724
725	return 0;
726}
727
728
729/**
730 * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
731 * @global: Pointer to global data from wpa_supplicant_init()
732 * @path: Pointer to a dbus object path representing an interface
733 * Returns: Pointer to the interface or %NULL if not found
734 */
735struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
736	struct wpa_global *global, const char *path)
737{
738	struct wpa_supplicant *wpa_s;
739
740	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
741		if (wpa_s->dbus_path && strcmp(wpa_s->dbus_path, path) == 0)
742			return wpa_s;
743	}
744	return NULL;
745}
746