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(message, WPAS_ERROR_INVALID_IFACE,
96				      "wpa_supplicant knows nothing about "
97				      "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	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
220	                                                 &bssid);
221	if (iface_obj_path == NULL) {
222		reply = wpas_dbus_new_invalid_iface_error(message);
223		goto out;
224	}
225
226	/* Make sure the message's object path actually refers to the
227	 * wpa_supplicant structure it's supposed to (which is wpa_s)
228	 */
229	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
230	                                          iface_obj_path) != wpa_s) {
231		reply = wpas_dbus_new_invalid_iface_error(message);
232		goto out;
233	}
234
235	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
236		/* A method for one of this interface's configured networks */
237		int nid = strtoul(network, NULL, 10);
238		if (errno != EINVAL)
239			reply = wpas_dispatch_network_method(message, wpa_s,
240							     nid);
241		else
242			reply = wpas_dbus_new_invalid_network_error(message);
243	} else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
244		/* A method for one of this interface's scanned BSSIDs */
245		reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
246	} else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
247		/* A method for an interface only. */
248		if (!strcmp(method, "scan"))
249			reply = wpas_dbus_iface_scan(message, wpa_s);
250		else if (!strcmp(method, "scanResults"))
251			reply = wpas_dbus_iface_scan_results(message, wpa_s);
252		else if (!strcmp(method, "addNetwork"))
253			reply = wpas_dbus_iface_add_network(message, wpa_s);
254		else if (!strcmp(method, "removeNetwork"))
255			reply = wpas_dbus_iface_remove_network(message, wpa_s);
256		else if (!strcmp(method, "selectNetwork"))
257			reply = wpas_dbus_iface_select_network(message, wpa_s);
258		else if (!strcmp(method, "capabilities"))
259			reply = wpas_dbus_iface_capabilities(message, wpa_s);
260		else if (!strcmp(method, "disconnect"))
261			reply = wpas_dbus_iface_disconnect(message, wpa_s);
262		else if (!strcmp(method, "setAPScan"))
263			reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
264		else if (!strcmp(method, "setSmartcardModules"))
265			reply = wpas_dbus_iface_set_smartcard_modules(message,
266								      wpa_s);
267		else if (!strcmp(method, "state"))
268			reply = wpas_dbus_iface_get_state(message, wpa_s);
269		else if (!strcmp(method, "scanning"))
270			reply = wpas_dbus_iface_get_scanning(message, wpa_s);
271		else if (!strcmp(method, "setBlobs"))
272			reply = wpas_dbus_iface_set_blobs(message, wpa_s);
273		else if (!strcmp(method, "removeBlobs"))
274			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
275#ifdef CONFIG_WPS
276		else if (!os_strcmp(method, "wpsPbc"))
277			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
278		else if (!os_strcmp(method, "wpsPin"))
279			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
280		else if (!os_strcmp(method, "wpsReg"))
281			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
282#endif /* CONFIG_WPS */
283		else if (!os_strcmp(method, "flush"))
284			reply = wpas_dbus_iface_flush(message, wpa_s);
285	}
286
287	/* If the message was handled, send back the reply */
288	if (reply) {
289		if (!dbus_message_get_no_reply(message))
290			dbus_connection_send(connection, reply, NULL);
291		dbus_message_unref(reply);
292	}
293
294out:
295	os_free(iface_obj_path);
296	os_free(network);
297	os_free(bssid);
298	return reply ? DBUS_HANDLER_RESULT_HANDLED :
299		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
300}
301
302
303/**
304 * wpas_message_handler - dispatch incoming dbus messages
305 * @connection: connection to the system message bus
306 * @message: an incoming dbus message
307 * @user_data: a pointer to a dbus control interface data structure
308 * Returns: whether or not the message was handled
309 *
310 * This function dispatches all incoming dbus messages to the correct
311 * handlers, depending on what the message's target object path is,
312 * and what the method call is.
313 */
314static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
315	DBusMessage *message, void *user_data)
316{
317	struct wpas_dbus_priv *ctrl_iface = user_data;
318	const char *method;
319	const char *path;
320	const char *msg_interface;
321	DBusMessage *reply = NULL;
322
323	method = dbus_message_get_member(message);
324	path = dbus_message_get_path(message);
325	msg_interface = dbus_message_get_interface(message);
326	if (!method || !path || !ctrl_iface || !msg_interface)
327		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
328
329	/* Validate the method interface */
330	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
331		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
332
333	if (!strcmp(path, WPAS_DBUS_PATH)) {
334		/* dispatch methods against our global dbus interface here */
335		if (!strcmp(method, "addInterface")) {
336			reply = wpas_dbus_global_add_interface(
337				message, ctrl_iface->global);
338		} else if (!strcmp(method, "removeInterface")) {
339			reply = wpas_dbus_global_remove_interface(
340				message, ctrl_iface->global);
341		} else if (!strcmp(method, "getInterface")) {
342			reply = wpas_dbus_global_get_interface(
343				message, ctrl_iface->global);
344		} else if (!strcmp(method, "setDebugParams")) {
345			reply = wpas_dbus_global_set_debugparams(
346				message, ctrl_iface->global);
347		}
348	}
349
350	/* If the message was handled, send back the reply */
351	if (reply) {
352		if (!dbus_message_get_no_reply(message))
353			dbus_connection_send(connection, reply, NULL);
354		dbus_message_unref(reply);
355	}
356
357	return reply ? DBUS_HANDLER_RESULT_HANDLED :
358		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
359}
360
361
362/**
363 * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
364 * @wpa_s: %wpa_supplicant network interface data
365 * Returns: 0 on success, -1 on failure
366 *
367 * Notify listeners that this interface has updated scan results.
368 */
369void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
370{
371	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
372	DBusMessage *_signal;
373
374	/* Do nothing if the control interface is not turned on */
375	if (iface == NULL)
376		return;
377
378	_signal = dbus_message_new_signal(wpa_s->dbus_path,
379					  WPAS_DBUS_IFACE_INTERFACE,
380					  "ScanResultsAvailable");
381	if (_signal == NULL) {
382		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
383			   "results signal");
384		return;
385	}
386	dbus_connection_send(iface->con, _signal, NULL);
387	dbus_message_unref(_signal);
388}
389
390
391/**
392 * wpa_supplicant_dbus_notify_state_change - Send a state change signal
393 * @wpa_s: %wpa_supplicant network interface data
394 * @new_state: new state wpa_supplicant is entering
395 * @old_state: old state wpa_supplicant is leaving
396 * Returns: 0 on success, -1 on failure
397 *
398 * Notify listeners that wpa_supplicant has changed state
399 */
400void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
401					     enum wpa_states new_state,
402					     enum wpa_states old_state)
403{
404	struct wpas_dbus_priv *iface;
405	DBusMessage *_signal = NULL;
406	const char *new_state_str, *old_state_str;
407
408	if (wpa_s->dbus_path == NULL)
409		return; /* Skip signal since D-Bus setup is not yet ready */
410
411	/* Do nothing if the control interface is not turned on */
412	if (wpa_s->global == NULL)
413		return;
414	iface = wpa_s->global->dbus;
415	if (iface == NULL)
416		return;
417
418	/* Only send signal if state really changed */
419	if (new_state == old_state)
420		return;
421
422	_signal = dbus_message_new_signal(wpa_s->dbus_path,
423					  WPAS_DBUS_IFACE_INTERFACE,
424					  "StateChange");
425	if (_signal == NULL) {
426		wpa_printf(MSG_ERROR,
427		           "dbus: wpa_supplicant_dbus_notify_state_change: "
428		           "could not create dbus signal; likely out of "
429		           "memory");
430		return;
431	}
432
433	new_state_str = wpa_supplicant_state_txt(new_state);
434	old_state_str = wpa_supplicant_state_txt(old_state);
435	if (new_state_str == NULL || old_state_str == NULL) {
436		wpa_printf(MSG_ERROR,
437		           "dbus: wpa_supplicant_dbus_notify_state_change: "
438		           "Could not convert state strings");
439		goto out;
440	}
441
442	if (!dbus_message_append_args(_signal,
443	                              DBUS_TYPE_STRING, &new_state_str,
444	                              DBUS_TYPE_STRING, &old_state_str,
445	                              DBUS_TYPE_INVALID)) {
446		wpa_printf(MSG_ERROR,
447		           "dbus: wpa_supplicant_dbus_notify_state_change: "
448		           "Not enough memory to construct state change "
449		           "signal");
450		goto out;
451	}
452
453	dbus_connection_send(iface->con, _signal, NULL);
454
455out:
456	dbus_message_unref(_signal);
457}
458
459
460/**
461 * wpa_supplicant_dbus_notify_scanning - send scanning status
462 * @wpa_s: %wpa_supplicant network interface data
463 * Returns: 0 on success, -1 on failure
464 *
465 * Notify listeners of interface scanning state changes
466 */
467void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
468{
469	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
470	DBusMessage *_signal;
471	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
472
473	/* Do nothing if the control interface is not turned on */
474	if (iface == NULL)
475		return;
476
477	_signal = dbus_message_new_signal(wpa_s->dbus_path,
478					  WPAS_DBUS_IFACE_INTERFACE,
479					  "Scanning");
480	if (_signal == NULL) {
481		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
482			   "results signal");
483		return;
484	}
485
486	if (dbus_message_append_args(_signal,
487	                             DBUS_TYPE_BOOLEAN, &scanning,
488	                             DBUS_TYPE_INVALID)) {
489		dbus_connection_send(iface->con, _signal, NULL);
490	} else {
491		wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
492			   "signal");
493	}
494	dbus_message_unref(_signal);
495}
496
497
498#ifdef CONFIG_WPS
499void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
500					 const struct wps_credential *cred)
501{
502	struct wpas_dbus_priv *iface;
503	DBusMessage *_signal = NULL;
504
505	/* Do nothing if the control interface is not turned on */
506	if (wpa_s->global == NULL)
507		return;
508	iface = wpa_s->global->dbus;
509	if (iface == NULL)
510		return;
511
512	_signal = dbus_message_new_signal(wpa_s->dbus_path,
513					  WPAS_DBUS_IFACE_INTERFACE,
514					  "WpsCred");
515	if (_signal == NULL) {
516		wpa_printf(MSG_ERROR,
517		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
518		           "Could not create dbus signal; likely out of "
519		           "memory");
520		return;
521	}
522
523	if (!dbus_message_append_args(_signal,
524	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
525				      &cred->cred_attr, cred->cred_attr_len,
526	                              DBUS_TYPE_INVALID)) {
527		wpa_printf(MSG_ERROR,
528		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
529		           "Not enough memory to construct signal");
530		goto out;
531	}
532
533	dbus_connection_send(iface->con, _signal, NULL);
534
535out:
536	dbus_message_unref(_signal);
537}
538#else /* CONFIG_WPS */
539void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
540					 const struct wps_credential *cred)
541{
542}
543#endif /* CONFIG_WPS */
544
545void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
546					      int depth, const char *subject,
547					      const char *cert_hash,
548					      const struct wpabuf *cert)
549{
550	struct wpas_dbus_priv *iface;
551	DBusMessage *_signal = NULL;
552	const char *hash;
553	const char *cert_hex;
554	int cert_hex_len;
555
556	/* Do nothing if the control interface is not turned on */
557	if (wpa_s->global == NULL)
558		return;
559	iface = wpa_s->global->dbus;
560	if (iface == NULL)
561		return;
562
563	_signal = dbus_message_new_signal(wpa_s->dbus_path,
564					  WPAS_DBUS_IFACE_INTERFACE,
565					  "Certification");
566	if (_signal == NULL) {
567		wpa_printf(MSG_ERROR,
568		           "dbus: wpa_supplicant_dbus_notify_certification: "
569		           "Could not create dbus signal; likely out of "
570		           "memory");
571		return;
572	}
573
574	hash = cert_hash ? cert_hash : "";
575	cert_hex = cert ? wpabuf_head(cert) : "";
576	cert_hex_len = cert ? wpabuf_len(cert) : 0;
577
578	if (!dbus_message_append_args(_signal,
579				      DBUS_TYPE_INT32,&depth,
580				      DBUS_TYPE_STRING, &subject,
581	                              DBUS_TYPE_STRING, &hash,
582	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
583				      &cert_hex, cert_hex_len,
584	                              DBUS_TYPE_INVALID)) {
585		wpa_printf(MSG_ERROR,
586		           "dbus: wpa_supplicant_dbus_notify_certification: "
587		           "Not enough memory to construct signal");
588		goto out;
589	}
590
591	dbus_connection_send(iface->con, _signal, NULL);
592
593out:
594	dbus_message_unref(_signal);
595
596}
597
598
599/**
600 * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
601 * @global: Pointer to global data from wpa_supplicant_init()
602 * Returns: 0 on success, -1 on failure
603 *
604 * Initialize the dbus control interface and start receiving commands from
605 * external programs over the bus.
606 */
607int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
608{
609	DBusError error;
610	int ret = -1;
611	DBusObjectPathVTable wpas_vtable = {
612		NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
613	};
614
615	/* Register the message handler for the global dbus interface */
616	if (!dbus_connection_register_object_path(iface->con,
617						  WPAS_DBUS_PATH, &wpas_vtable,
618						  iface)) {
619		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
620			   "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, "dbus: Could not request service name: "
635			   "already registered");
636		break;
637	default:
638		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
639			   "%s %s", error.name, error.message);
640		break;
641	}
642	dbus_error_free(&error);
643
644	if (ret != 0)
645		return -1;
646
647	wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
648		   "'.");
649
650	return 0;
651}
652
653
654/**
655 * wpas_dbus_register_new_iface - Register a new interface with dbus
656 * @wpa_s: %wpa_supplicant interface description structure to register
657 * Returns: 0 on success, -1 on error
658 *
659 * Registers a new interface with dbus and assigns it a dbus object path.
660 */
661int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
662{
663	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
664	DBusConnection * con;
665	u32 next;
666	DBusObjectPathVTable vtable = {
667		NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
668	};
669
670	/* Do nothing if the control interface is not turned on */
671	if (ctrl_iface == NULL)
672		return 0;
673
674	con = ctrl_iface->con;
675	next = ctrl_iface->next_objid++;
676
677	/* Create and set the interface's object path */
678	wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
679	if (wpa_s->dbus_path == NULL)
680		return -1;
681	os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
682		    WPAS_DBUS_PATH_INTERFACES "/%u",
683		    next);
684
685	/* Register the message handler for the interface functions */
686	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
687					       wpa_s)) {
688		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
689			   "handler for interface %s", wpa_s->ifname);
690		return -1;
691	}
692
693	return 0;
694}
695
696
697/**
698 * wpas_dbus_unregister_iface - Unregister an interface from dbus
699 * @wpa_s: wpa_supplicant interface structure
700 * Returns: 0 on success, -1 on failure
701 *
702 * Unregisters the interface with dbus
703 */
704int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
705{
706	struct wpas_dbus_priv *ctrl_iface;
707	DBusConnection *con;
708
709	/* Do nothing if the control interface is not turned on */
710	if (wpa_s == NULL || wpa_s->global == NULL)
711		return 0;
712	ctrl_iface = wpa_s->global->dbus;
713	if (ctrl_iface == NULL)
714		return 0;
715
716	con = ctrl_iface->con;
717	if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path))
718		return -1;
719
720	os_free(wpa_s->dbus_path);
721	wpa_s->dbus_path = NULL;
722
723	return 0;
724}
725
726
727/**
728 * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
729 * @global: Pointer to global data from wpa_supplicant_init()
730 * @path: Pointer to a dbus object path representing an interface
731 * Returns: Pointer to the interface or %NULL if not found
732 */
733struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
734	struct wpa_global *global, const char *path)
735{
736	struct wpa_supplicant *wpa_s;
737
738	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
739		if (strcmp(wpa_s->dbus_path, path) == 0)
740			return wpa_s;
741	}
742	return NULL;
743}
744