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#ifndef CONFIG_NO_CONFIG_BLOBS
272		else if (!strcmp(method, "setBlobs"))
273			reply = wpas_dbus_iface_set_blobs(message, wpa_s);
274		else if (!strcmp(method, "removeBlobs"))
275			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
276#endif /* CONFIG_NO_CONFIG_BLOBS */
277#ifdef CONFIG_WPS
278		else if (!os_strcmp(method, "wpsPbc"))
279			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
280		else if (!os_strcmp(method, "wpsPin"))
281			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
282		else if (!os_strcmp(method, "wpsReg"))
283			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
284#endif /* CONFIG_WPS */
285		else if (!os_strcmp(method, "flush"))
286			reply = wpas_dbus_iface_flush(message, wpa_s);
287	}
288
289	/* If the message was handled, send back the reply */
290	if (reply) {
291		if (!dbus_message_get_no_reply(message))
292			dbus_connection_send(connection, reply, NULL);
293		dbus_message_unref(reply);
294	}
295
296out:
297	os_free(iface_obj_path);
298	os_free(network);
299	os_free(bssid);
300	return reply ? DBUS_HANDLER_RESULT_HANDLED :
301		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
302}
303
304
305/**
306 * wpas_message_handler - dispatch incoming dbus messages
307 * @connection: connection to the system message bus
308 * @message: an incoming dbus message
309 * @user_data: a pointer to a dbus control interface data structure
310 * Returns: whether or not the message was handled
311 *
312 * This function dispatches all incoming dbus messages to the correct
313 * handlers, depending on what the message's target object path is,
314 * and what the method call is.
315 */
316static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
317	DBusMessage *message, void *user_data)
318{
319	struct wpas_dbus_priv *ctrl_iface = user_data;
320	const char *method;
321	const char *path;
322	const char *msg_interface;
323	DBusMessage *reply = NULL;
324
325	method = dbus_message_get_member(message);
326	path = dbus_message_get_path(message);
327	msg_interface = dbus_message_get_interface(message);
328	if (!method || !path || !ctrl_iface || !msg_interface)
329		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
330
331	/* Validate the method interface */
332	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
333		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
334
335	if (!strcmp(path, WPAS_DBUS_PATH)) {
336		/* dispatch methods against our global dbus interface here */
337		if (!strcmp(method, "addInterface")) {
338			reply = wpas_dbus_global_add_interface(
339				message, ctrl_iface->global);
340		} else if (!strcmp(method, "removeInterface")) {
341			reply = wpas_dbus_global_remove_interface(
342				message, ctrl_iface->global);
343		} else if (!strcmp(method, "getInterface")) {
344			reply = wpas_dbus_global_get_interface(
345				message, ctrl_iface->global);
346		} else if (!strcmp(method, "setDebugParams")) {
347			reply = wpas_dbus_global_set_debugparams(
348				message, ctrl_iface->global);
349		}
350	}
351
352	/* If the message was handled, send back the reply */
353	if (reply) {
354		if (!dbus_message_get_no_reply(message))
355			dbus_connection_send(connection, reply, NULL);
356		dbus_message_unref(reply);
357	}
358
359	return reply ? DBUS_HANDLER_RESULT_HANDLED :
360		DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
361}
362
363
364/**
365 * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
366 * @wpa_s: %wpa_supplicant network interface data
367 * Returns: 0 on success, -1 on failure
368 *
369 * Notify listeners that this interface has updated scan results.
370 */
371void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
372{
373	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
374	DBusMessage *_signal;
375
376	/* Do nothing if the control interface is not turned on */
377	if (iface == NULL)
378		return;
379
380	_signal = dbus_message_new_signal(wpa_s->dbus_path,
381					  WPAS_DBUS_IFACE_INTERFACE,
382					  "ScanResultsAvailable");
383	if (_signal == NULL) {
384		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
385			   "results signal");
386		return;
387	}
388	dbus_connection_send(iface->con, _signal, NULL);
389	dbus_message_unref(_signal);
390}
391
392
393/**
394 * wpa_supplicant_dbus_notify_state_change - Send a state change signal
395 * @wpa_s: %wpa_supplicant network interface data
396 * @new_state: new state wpa_supplicant is entering
397 * @old_state: old state wpa_supplicant is leaving
398 * Returns: 0 on success, -1 on failure
399 *
400 * Notify listeners that wpa_supplicant has changed state
401 */
402void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
403					     enum wpa_states new_state,
404					     enum wpa_states old_state)
405{
406	struct wpas_dbus_priv *iface;
407	DBusMessage *_signal = NULL;
408	const char *new_state_str, *old_state_str;
409
410	if (wpa_s->dbus_path == NULL)
411		return; /* Skip signal since D-Bus setup is not yet ready */
412
413	/* Do nothing if the control interface is not turned on */
414	if (wpa_s->global == NULL)
415		return;
416	iface = wpa_s->global->dbus;
417	if (iface == NULL)
418		return;
419
420	/* Only send signal if state really changed */
421	if (new_state == old_state)
422		return;
423
424	_signal = dbus_message_new_signal(wpa_s->dbus_path,
425					  WPAS_DBUS_IFACE_INTERFACE,
426					  "StateChange");
427	if (_signal == NULL) {
428		wpa_printf(MSG_ERROR,
429		           "dbus: wpa_supplicant_dbus_notify_state_change: "
430		           "could not create dbus signal; likely out of "
431		           "memory");
432		return;
433	}
434
435	new_state_str = wpa_supplicant_state_txt(new_state);
436	old_state_str = wpa_supplicant_state_txt(old_state);
437	if (new_state_str == NULL || old_state_str == NULL) {
438		wpa_printf(MSG_ERROR,
439		           "dbus: wpa_supplicant_dbus_notify_state_change: "
440		           "Could not convert state strings");
441		goto out;
442	}
443
444	if (!dbus_message_append_args(_signal,
445	                              DBUS_TYPE_STRING, &new_state_str,
446	                              DBUS_TYPE_STRING, &old_state_str,
447	                              DBUS_TYPE_INVALID)) {
448		wpa_printf(MSG_ERROR,
449		           "dbus: wpa_supplicant_dbus_notify_state_change: "
450		           "Not enough memory to construct state change "
451		           "signal");
452		goto out;
453	}
454
455	dbus_connection_send(iface->con, _signal, NULL);
456
457out:
458	dbus_message_unref(_signal);
459}
460
461
462/**
463 * wpa_supplicant_dbus_notify_scanning - send scanning status
464 * @wpa_s: %wpa_supplicant network interface data
465 * Returns: 0 on success, -1 on failure
466 *
467 * Notify listeners of interface scanning state changes
468 */
469void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
470{
471	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
472	DBusMessage *_signal;
473	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
474
475	/* Do nothing if the control interface is not turned on */
476	if (iface == NULL)
477		return;
478
479	_signal = dbus_message_new_signal(wpa_s->dbus_path,
480					  WPAS_DBUS_IFACE_INTERFACE,
481					  "Scanning");
482	if (_signal == NULL) {
483		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
484			   "results signal");
485		return;
486	}
487
488	if (dbus_message_append_args(_signal,
489	                             DBUS_TYPE_BOOLEAN, &scanning,
490	                             DBUS_TYPE_INVALID)) {
491		dbus_connection_send(iface->con, _signal, NULL);
492	} else {
493		wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
494			   "signal");
495	}
496	dbus_message_unref(_signal);
497}
498
499
500#ifdef CONFIG_WPS
501void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
502					 const struct wps_credential *cred)
503{
504	struct wpas_dbus_priv *iface;
505	DBusMessage *_signal = NULL;
506
507	/* Do nothing if the control interface is not turned on */
508	if (wpa_s->global == NULL)
509		return;
510	iface = wpa_s->global->dbus;
511	if (iface == NULL)
512		return;
513
514	_signal = dbus_message_new_signal(wpa_s->dbus_path,
515					  WPAS_DBUS_IFACE_INTERFACE,
516					  "WpsCred");
517	if (_signal == NULL) {
518		wpa_printf(MSG_ERROR,
519		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
520		           "Could not create dbus signal; likely out of "
521		           "memory");
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: wpa_supplicant_dbus_notify_wps_cred: "
531		           "Not enough memory to construct signal");
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)
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: wpa_supplicant_dbus_notify_certification: "
571		           "Could not create dbus signal; likely out of "
572		           "memory");
573		return;
574	}
575
576	hash = cert_hash ? cert_hash : "";
577	cert_hex = cert ? wpabuf_head(cert) : "";
578	cert_hex_len = cert ? wpabuf_len(cert) : 0;
579
580	if (!dbus_message_append_args(_signal,
581				      DBUS_TYPE_INT32,&depth,
582				      DBUS_TYPE_STRING, &subject,
583	                              DBUS_TYPE_STRING, &hash,
584	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
585				      &cert_hex, cert_hex_len,
586	                              DBUS_TYPE_INVALID)) {
587		wpa_printf(MSG_ERROR,
588		           "dbus: wpa_supplicant_dbus_notify_certification: "
589		           "Not enough memory to construct signal");
590		goto out;
591	}
592
593	dbus_connection_send(iface->con, _signal, NULL);
594
595out:
596	dbus_message_unref(_signal);
597
598}
599
600
601/**
602 * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
603 * @global: Pointer to global data from wpa_supplicant_init()
604 * Returns: 0 on success, -1 on failure
605 *
606 * Initialize the dbus control interface and start receiving commands from
607 * external programs over the bus.
608 */
609int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface)
610{
611	DBusError error;
612	int ret = -1;
613	DBusObjectPathVTable wpas_vtable = {
614		NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
615	};
616
617	/* Register the message handler for the global dbus interface */
618	if (!dbus_connection_register_object_path(iface->con,
619						  WPAS_DBUS_PATH, &wpas_vtable,
620						  iface)) {
621		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
622			   "handler");
623		return -1;
624	}
625
626	/* Register our service with the message bus */
627	dbus_error_init(&error);
628	switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
629				      0, &error)) {
630	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
631		ret = 0;
632		break;
633	case DBUS_REQUEST_NAME_REPLY_EXISTS:
634	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
635	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
636		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
637			   "already registered");
638		break;
639	default:
640		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
641			   "%s %s", error.name, error.message);
642		break;
643	}
644	dbus_error_free(&error);
645
646	if (ret != 0)
647		return -1;
648
649	wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
650		   "'.");
651
652	return 0;
653}
654
655
656/**
657 * wpas_dbus_register_new_iface - Register a new interface with dbus
658 * @wpa_s: %wpa_supplicant interface description structure to register
659 * Returns: 0 on success, -1 on error
660 *
661 * Registers a new interface with dbus and assigns it a dbus object path.
662 */
663int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
664{
665	struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus;
666	DBusConnection * con;
667	u32 next;
668	DBusObjectPathVTable vtable = {
669		NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
670	};
671
672	/* Do nothing if the control interface is not turned on */
673	if (ctrl_iface == NULL)
674		return 0;
675
676	con = ctrl_iface->con;
677	next = ctrl_iface->next_objid++;
678
679	/* Create and set the interface's object path */
680	wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
681	if (wpa_s->dbus_path == NULL)
682		return -1;
683	os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX,
684		    WPAS_DBUS_PATH_INTERFACES "/%u",
685		    next);
686
687	/* Register the message handler for the interface functions */
688	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
689					       wpa_s)) {
690		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
691			   "handler for interface %s", 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)
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 (strcmp(wpa_s->dbus_path, path) == 0)
742			return wpa_s;
743	}
744	return NULL;
745}
746