1214501Srpaulo/*
2214501Srpaulo * WPA Supplicant / dbus-based control interface
3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4214501Srpaulo * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
5214501Srpaulo *
6252190Srpaulo * This software may be distributed under the terms of the BSD license.
7252190Srpaulo * See README for more details.
8214501Srpaulo */
9214501Srpaulo
10214501Srpaulo#include "utils/includes.h"
11214501Srpaulo
12214501Srpaulo#include "utils/common.h"
13214501Srpaulo#include "utils/eloop.h"
14214501Srpaulo#include "dbus_common.h"
15214501Srpaulo#include "dbus_common_i.h"
16214501Srpaulo#include "dbus_new.h"
17214501Srpaulo#include "dbus_new_helpers.h"
18252190Srpaulo#include "dbus_dict_helpers.h"
19214501Srpaulo
20214501Srpaulo
21252190Srpaulostatic dbus_bool_t fill_dict_with_properties(
22252190Srpaulo	DBusMessageIter *dict_iter,
23252190Srpaulo	const struct wpa_dbus_property_desc *props,
24252190Srpaulo	const char *interface, void *user_data, DBusError *error)
25214501Srpaulo{
26252190Srpaulo	DBusMessageIter entry_iter;
27214501Srpaulo	const struct wpa_dbus_property_desc *dsc;
28214501Srpaulo
29214501Srpaulo	for (dsc = props; dsc && dsc->dbus_property; dsc++) {
30252190Srpaulo		/* Only return properties for the requested D-Bus interface */
31252190Srpaulo		if (os_strncmp(dsc->dbus_interface, interface,
32252190Srpaulo			       WPAS_DBUS_INTERFACE_MAX) != 0)
33252190Srpaulo			continue;
34214501Srpaulo
35252190Srpaulo		/* Skip write-only properties */
36252190Srpaulo		if (dsc->getter == NULL)
37252190Srpaulo			continue;
38214501Srpaulo
39252190Srpaulo		if (!dbus_message_iter_open_container(dict_iter,
40252190Srpaulo						      DBUS_TYPE_DICT_ENTRY,
41252190Srpaulo						      NULL, &entry_iter)) {
42252190Srpaulo			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
43252190Srpaulo			                     "no memory");
44252190Srpaulo			return FALSE;
45252190Srpaulo		}
46252190Srpaulo		if (!dbus_message_iter_append_basic(&entry_iter,
47252190Srpaulo						    DBUS_TYPE_STRING,
48252190Srpaulo						    &dsc->dbus_property)) {
49252190Srpaulo			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
50252190Srpaulo			                     "no memory");
51252190Srpaulo			return FALSE;
52252190Srpaulo		}
53214501Srpaulo
54252190Srpaulo		/* An error getting a property fails the request entirely */
55252190Srpaulo		if (!dsc->getter(&entry_iter, error, user_data))
56252190Srpaulo			return FALSE;
57214501Srpaulo
58252190Srpaulo		dbus_message_iter_close_container(dict_iter, &entry_iter);
59214501Srpaulo	}
60214501Srpaulo
61252190Srpaulo	return TRUE;
62214501Srpaulo}
63214501Srpaulo
64214501Srpaulo
65214501Srpaulo/**
66214501Srpaulo * get_all_properties - Responds for GetAll properties calls on object
67214501Srpaulo * @message: Message with GetAll call
68214501Srpaulo * @interface: interface name which properties will be returned
69214501Srpaulo * @property_dsc: list of object's properties
70214501Srpaulo * Returns: Message with dict of variants as argument with properties values
71214501Srpaulo *
72214501Srpaulo * Iterates over all properties registered with object and execute getters
73214501Srpaulo * of those, which are readable and which interface matches interface
74214501Srpaulo * specified as argument. Returned message contains one dict argument
75214501Srpaulo * with properties names as keys and theirs values as values.
76214501Srpaulo */
77252190Srpaulostatic DBusMessage * get_all_properties(DBusMessage *message, char *interface,
78252190Srpaulo				        struct wpa_dbus_object_desc *obj_dsc)
79214501Srpaulo{
80252190Srpaulo	DBusMessage *reply;
81214501Srpaulo	DBusMessageIter iter, dict_iter;
82252190Srpaulo	DBusError error;
83214501Srpaulo
84252190Srpaulo	reply = dbus_message_new_method_return(message);
85252190Srpaulo	if (reply == NULL) {
86252190Srpaulo		wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
87252190Srpaulo			   __func__);
88252190Srpaulo		return NULL;
89252190Srpaulo	}
90252190Srpaulo
91214501Srpaulo	dbus_message_iter_init_append(reply, &iter);
92252190Srpaulo	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
93252190Srpaulo		wpa_printf(MSG_ERROR, "%s: out of memory creating reply",
94252190Srpaulo			   __func__);
95252190Srpaulo		dbus_message_unref(reply);
96252190Srpaulo		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
97252190Srpaulo					       "out of memory");
98252190Srpaulo		return reply;
99252190Srpaulo	}
100214501Srpaulo
101252190Srpaulo	dbus_error_init(&error);
102252190Srpaulo	if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
103252190Srpaulo				       interface, obj_dsc->user_data, &error))
104252190Srpaulo	{
105214501Srpaulo		dbus_message_unref(reply);
106252190Srpaulo		reply = wpas_dbus_reply_new_from_error(message, &error,
107252190Srpaulo						       DBUS_ERROR_INVALID_ARGS,
108252190Srpaulo						       "No readable properties"
109252190Srpaulo						       " in this interface");
110252190Srpaulo		dbus_error_free(&error);
111252190Srpaulo		return reply;
112214501Srpaulo	}
113214501Srpaulo
114252190Srpaulo	wpa_dbus_dict_close_write(&iter, &dict_iter);
115214501Srpaulo	return reply;
116214501Srpaulo}
117214501Srpaulo
118214501Srpaulo
119214501Srpaulostatic int is_signature_correct(DBusMessage *message,
120214501Srpaulo				const struct wpa_dbus_method_desc *method_dsc)
121214501Srpaulo{
122214501Srpaulo	/* According to DBus documentation max length of signature is 255 */
123214501Srpaulo#define MAX_SIG_LEN 256
124214501Srpaulo	char registered_sig[MAX_SIG_LEN], *pos;
125214501Srpaulo	const char *sig = dbus_message_get_signature(message);
126214501Srpaulo	int ret;
127214501Srpaulo	const struct wpa_dbus_argument *arg;
128214501Srpaulo
129214501Srpaulo	pos = registered_sig;
130214501Srpaulo	*pos = '\0';
131214501Srpaulo
132214501Srpaulo	for (arg = method_dsc->args; arg && arg->name; arg++) {
133214501Srpaulo		if (arg->dir == ARG_IN) {
134214501Srpaulo			size_t blen = registered_sig + MAX_SIG_LEN - pos;
135214501Srpaulo			ret = os_snprintf(pos, blen, "%s", arg->type);
136214501Srpaulo			if (ret < 0 || (size_t) ret >= blen)
137214501Srpaulo				return 0;
138214501Srpaulo			pos += ret;
139214501Srpaulo		}
140214501Srpaulo	}
141214501Srpaulo
142214501Srpaulo	return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
143214501Srpaulo}
144214501Srpaulo
145214501Srpaulo
146214501Srpaulostatic DBusMessage * properties_get_all(DBusMessage *message, char *interface,
147214501Srpaulo					struct wpa_dbus_object_desc *obj_dsc)
148214501Srpaulo{
149214501Srpaulo	if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
150214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
151214501Srpaulo					      NULL);
152214501Srpaulo
153214501Srpaulo	return get_all_properties(message, interface, obj_dsc);
154214501Srpaulo}
155214501Srpaulo
156214501Srpaulo
157214501Srpaulostatic DBusMessage * properties_get(DBusMessage *message,
158214501Srpaulo				    const struct wpa_dbus_property_desc *dsc,
159214501Srpaulo				    void *user_data)
160214501Srpaulo{
161252190Srpaulo	DBusMessage *reply;
162252190Srpaulo	DBusMessageIter iter;
163252190Srpaulo	DBusError error;
164252190Srpaulo
165252190Srpaulo	if (os_strcmp(dbus_message_get_signature(message), "ss")) {
166214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
167214501Srpaulo					      NULL);
168252190Srpaulo	}
169214501Srpaulo
170252190Srpaulo	if (dsc->getter == NULL) {
171252190Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
172252190Srpaulo					      "Property is write-only");
173252190Srpaulo	}
174214501Srpaulo
175252190Srpaulo	reply = dbus_message_new_method_return(message);
176252190Srpaulo	dbus_message_iter_init_append(reply, &iter);
177252190Srpaulo
178252190Srpaulo	dbus_error_init(&error);
179252190Srpaulo	if (dsc->getter(&iter, &error, user_data) == FALSE) {
180252190Srpaulo		dbus_message_unref(reply);
181252190Srpaulo		reply = wpas_dbus_reply_new_from_error(
182252190Srpaulo			message, &error, DBUS_ERROR_FAILED,
183252190Srpaulo			"Failed to read property");
184252190Srpaulo		dbus_error_free(&error);
185252190Srpaulo	}
186252190Srpaulo
187252190Srpaulo	return reply;
188214501Srpaulo}
189214501Srpaulo
190214501Srpaulo
191214501Srpaulostatic DBusMessage * properties_set(DBusMessage *message,
192214501Srpaulo				    const struct wpa_dbus_property_desc *dsc,
193214501Srpaulo				    void *user_data)
194214501Srpaulo{
195252190Srpaulo	DBusMessage *reply;
196252190Srpaulo	DBusMessageIter iter;
197252190Srpaulo	DBusError error;
198252190Srpaulo
199252190Srpaulo	if (os_strcmp(dbus_message_get_signature(message), "ssv")) {
200214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
201214501Srpaulo					      NULL);
202252190Srpaulo	}
203214501Srpaulo
204252190Srpaulo	if (dsc->setter == NULL) {
205252190Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
206252190Srpaulo					      "Property is read-only");
207252190Srpaulo	}
208214501Srpaulo
209252190Srpaulo	dbus_message_iter_init(message, &iter);
210252190Srpaulo	/* Skip the interface name and the property name */
211252190Srpaulo	dbus_message_iter_next(&iter);
212252190Srpaulo	dbus_message_iter_next(&iter);
213252190Srpaulo
214252190Srpaulo	/* Iter will now point to the property's new value */
215252190Srpaulo	dbus_error_init(&error);
216252190Srpaulo	if (dsc->setter(&iter, &error, user_data) == TRUE) {
217252190Srpaulo		/* Success */
218252190Srpaulo		reply = dbus_message_new_method_return(message);
219252190Srpaulo	} else {
220252190Srpaulo		reply = wpas_dbus_reply_new_from_error(
221252190Srpaulo			message, &error, DBUS_ERROR_FAILED,
222252190Srpaulo			"Failed to set property");
223252190Srpaulo		dbus_error_free(&error);
224252190Srpaulo	}
225252190Srpaulo
226252190Srpaulo	return reply;
227214501Srpaulo}
228214501Srpaulo
229214501Srpaulo
230214501Srpaulostatic DBusMessage *
231214501Srpauloproperties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
232214501Srpaulo		      char *interface,
233214501Srpaulo		      struct wpa_dbus_object_desc *obj_dsc)
234214501Srpaulo{
235214501Srpaulo	const struct wpa_dbus_property_desc *property_dsc;
236214501Srpaulo	char *property;
237214501Srpaulo	const char *method;
238214501Srpaulo
239214501Srpaulo	method = dbus_message_get_member(message);
240214501Srpaulo	property_dsc = obj_dsc->properties;
241214501Srpaulo
242214501Srpaulo	/* Second argument: property name (DBUS_TYPE_STRING) */
243214501Srpaulo	if (!dbus_message_iter_next(iter) ||
244214501Srpaulo	    dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
245214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
246214501Srpaulo					      NULL);
247214501Srpaulo	}
248214501Srpaulo	dbus_message_iter_get_basic(iter, &property);
249214501Srpaulo
250214501Srpaulo	while (property_dsc && property_dsc->dbus_property) {
251214501Srpaulo		/* compare property names and
252214501Srpaulo		 * interfaces */
253214501Srpaulo		if (!os_strncmp(property_dsc->dbus_property, property,
254214501Srpaulo				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
255214501Srpaulo		    !os_strncmp(property_dsc->dbus_interface, interface,
256214501Srpaulo				WPAS_DBUS_INTERFACE_MAX))
257214501Srpaulo			break;
258214501Srpaulo
259214501Srpaulo		property_dsc++;
260214501Srpaulo	}
261214501Srpaulo	if (property_dsc == NULL || property_dsc->dbus_property == NULL) {
262214501Srpaulo		wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
263214501Srpaulo			   interface, property,
264214501Srpaulo			   dbus_message_get_path(message));
265214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
266214501Srpaulo					      "No such property");
267214501Srpaulo	}
268214501Srpaulo
269214501Srpaulo	if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
270214501Srpaulo		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
271214501Srpaulo		return properties_get(message, property_dsc,
272214501Srpaulo				      obj_dsc->user_data);
273214501Srpaulo
274214501Srpaulo	return properties_set(message, property_dsc, obj_dsc->user_data);
275214501Srpaulo}
276214501Srpaulo
277214501Srpaulo
278214501Srpaulostatic DBusMessage * properties_handler(DBusMessage *message,
279214501Srpaulo					struct wpa_dbus_object_desc *obj_dsc)
280214501Srpaulo{
281214501Srpaulo	DBusMessageIter iter;
282214501Srpaulo	char *interface;
283214501Srpaulo	const char *method;
284214501Srpaulo
285214501Srpaulo	method = dbus_message_get_member(message);
286214501Srpaulo	dbus_message_iter_init(message, &iter);
287214501Srpaulo
288214501Srpaulo	if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
289214501Srpaulo			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
290214501Srpaulo	    !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
291214501Srpaulo			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
292214501Srpaulo	    !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
293214501Srpaulo			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
294214501Srpaulo		/* First argument: interface name (DBUS_TYPE_STRING) */
295214501Srpaulo		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
296214501Srpaulo		{
297214501Srpaulo			return dbus_message_new_error(message,
298214501Srpaulo						      DBUS_ERROR_INVALID_ARGS,
299214501Srpaulo						      NULL);
300214501Srpaulo		}
301214501Srpaulo
302214501Srpaulo		dbus_message_iter_get_basic(&iter, &interface);
303214501Srpaulo
304214501Srpaulo		if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
305214501Srpaulo				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
306214501Srpaulo			/* GetAll */
307214501Srpaulo			return properties_get_all(message, interface, obj_dsc);
308214501Srpaulo		}
309214501Srpaulo		/* Get or Set */
310214501Srpaulo		return properties_get_or_set(message, &iter, interface,
311214501Srpaulo					     obj_dsc);
312214501Srpaulo	}
313214501Srpaulo	return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
314214501Srpaulo				      NULL);
315214501Srpaulo}
316214501Srpaulo
317214501Srpaulo
318214501Srpaulostatic DBusMessage * msg_method_handler(DBusMessage *message,
319214501Srpaulo					struct wpa_dbus_object_desc *obj_dsc)
320214501Srpaulo{
321214501Srpaulo	const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
322214501Srpaulo	const char *method;
323214501Srpaulo	const char *msg_interface;
324214501Srpaulo
325214501Srpaulo	method = dbus_message_get_member(message);
326214501Srpaulo	msg_interface = dbus_message_get_interface(message);
327214501Srpaulo
328214501Srpaulo	/* try match call to any registered method */
329214501Srpaulo	while (method_dsc && method_dsc->dbus_method) {
330214501Srpaulo		/* compare method names and interfaces */
331214501Srpaulo		if (!os_strncmp(method_dsc->dbus_method, method,
332214501Srpaulo				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
333214501Srpaulo		    !os_strncmp(method_dsc->dbus_interface, msg_interface,
334214501Srpaulo				WPAS_DBUS_INTERFACE_MAX))
335214501Srpaulo			break;
336214501Srpaulo
337214501Srpaulo		method_dsc++;
338214501Srpaulo	}
339214501Srpaulo	if (method_dsc == NULL || method_dsc->dbus_method == NULL) {
340214501Srpaulo		wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
341214501Srpaulo			   msg_interface, method,
342214501Srpaulo			   dbus_message_get_path(message));
343214501Srpaulo		return dbus_message_new_error(message,
344214501Srpaulo					      DBUS_ERROR_UNKNOWN_METHOD, NULL);
345214501Srpaulo	}
346214501Srpaulo
347214501Srpaulo	if (!is_signature_correct(message, method_dsc)) {
348214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
349214501Srpaulo					      NULL);
350214501Srpaulo	}
351214501Srpaulo
352214501Srpaulo	return method_dsc->method_handler(message,
353214501Srpaulo					  obj_dsc->user_data);
354214501Srpaulo}
355214501Srpaulo
356214501Srpaulo
357214501Srpaulo/**
358214501Srpaulo * message_handler - Handles incoming DBus messages
359214501Srpaulo * @connection: DBus connection on which message was received
360214501Srpaulo * @message: Received message
361214501Srpaulo * @user_data: pointer to description of object to which message was sent
362214501Srpaulo * Returns: Returns information whether message was handled or not
363214501Srpaulo *
364214501Srpaulo * Reads message interface and method name, then checks if they matches one
365214501Srpaulo * of the special cases i.e. introspection call or properties get/getall/set
366214501Srpaulo * methods and handles it. Else it iterates over registered methods list
367214501Srpaulo * and tries to match method's name and interface to those read from message
368214501Srpaulo * If appropriate method was found its handler function is called and
369214501Srpaulo * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
370214501Srpaulo * will be sent.
371214501Srpaulo */
372214501Srpaulostatic DBusHandlerResult message_handler(DBusConnection *connection,
373214501Srpaulo					 DBusMessage *message, void *user_data)
374214501Srpaulo{
375214501Srpaulo	struct wpa_dbus_object_desc *obj_dsc = user_data;
376214501Srpaulo	const char *method;
377214501Srpaulo	const char *path;
378214501Srpaulo	const char *msg_interface;
379214501Srpaulo	DBusMessage *reply;
380214501Srpaulo
381214501Srpaulo	/* get method, interface and path the message is addressed to */
382214501Srpaulo	method = dbus_message_get_member(message);
383214501Srpaulo	path = dbus_message_get_path(message);
384214501Srpaulo	msg_interface = dbus_message_get_interface(message);
385214501Srpaulo	if (!method || !path || !msg_interface)
386214501Srpaulo		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
387214501Srpaulo
388214501Srpaulo	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
389214501Srpaulo		   msg_interface, method, path);
390214501Srpaulo
391214501Srpaulo	/* if message is introspection method call */
392214501Srpaulo	if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
393214501Srpaulo			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
394214501Srpaulo	    !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
395214501Srpaulo			WPAS_DBUS_INTERFACE_MAX)) {
396214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
397214501Srpaulo		reply = wpa_dbus_introspect(message, obj_dsc);
398214501Srpaulo#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
399214501Srpaulo		reply = dbus_message_new_error(
400214501Srpaulo			message, DBUS_ERROR_UNKNOWN_METHOD,
401214501Srpaulo			"wpa_supplicant was compiled without "
402214501Srpaulo			"introspection support.");
403214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
404214501Srpaulo	} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
405214501Srpaulo			     WPAS_DBUS_INTERFACE_MAX)) {
406214501Srpaulo		/* if message is properties method call */
407214501Srpaulo		reply = properties_handler(message, obj_dsc);
408214501Srpaulo	} else {
409214501Srpaulo		reply = msg_method_handler(message, obj_dsc);
410214501Srpaulo	}
411214501Srpaulo
412214501Srpaulo	/* If handler succeed returning NULL, reply empty message */
413214501Srpaulo	if (!reply)
414214501Srpaulo		reply = dbus_message_new_method_return(message);
415214501Srpaulo	if (reply) {
416214501Srpaulo		if (!dbus_message_get_no_reply(message))
417214501Srpaulo			dbus_connection_send(connection, reply, NULL);
418214501Srpaulo		dbus_message_unref(reply);
419214501Srpaulo	}
420214501Srpaulo
421214501Srpaulo	wpa_dbus_flush_all_changed_properties(connection);
422214501Srpaulo
423214501Srpaulo	return DBUS_HANDLER_RESULT_HANDLED;
424214501Srpaulo}
425214501Srpaulo
426214501Srpaulo
427214501Srpaulo/**
428214501Srpaulo * free_dbus_object_desc - Frees object description data structure
429214501Srpaulo * @connection: DBus connection
430214501Srpaulo * @obj_dsc: Object description to free
431214501Srpaulo *
432214501Srpaulo * Frees each of properties, methods and signals description lists and
433214501Srpaulo * the object description structure itself.
434214501Srpaulo */
435214501Srpaulovoid free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
436214501Srpaulo{
437214501Srpaulo	if (!obj_dsc)
438214501Srpaulo		return;
439214501Srpaulo
440214501Srpaulo	/* free handler's argument */
441214501Srpaulo	if (obj_dsc->user_data_free_func)
442214501Srpaulo		obj_dsc->user_data_free_func(obj_dsc->user_data);
443214501Srpaulo
444214501Srpaulo	os_free(obj_dsc->path);
445214501Srpaulo	os_free(obj_dsc->prop_changed_flags);
446214501Srpaulo	os_free(obj_dsc);
447214501Srpaulo}
448214501Srpaulo
449214501Srpaulo
450214501Srpaulostatic void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
451214501Srpaulo{
452214501Srpaulo	free_dbus_object_desc(obj_dsc);
453214501Srpaulo}
454214501Srpaulo
455214501Srpaulo/**
456214501Srpaulo * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
457214501Srpaulo * @application_data: Pointer to application specific data structure
458214501Srpaulo * @dbus_path: DBus path to interface object
459214501Srpaulo * @dbus_service: DBus service name to register with
460214501Srpaulo * @messageHandler: a pointer to function which will handle dbus messages
461214501Srpaulo * coming on interface
462214501Srpaulo * Returns: 0 on success, -1 on failure
463214501Srpaulo *
464214501Srpaulo * Initialize the dbus control interface and start receiving commands from
465214501Srpaulo * external programs over the bus.
466214501Srpaulo */
467214501Srpauloint wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
468214501Srpaulo			     char *dbus_path, char *dbus_service,
469214501Srpaulo			     struct wpa_dbus_object_desc *obj_desc)
470214501Srpaulo{
471214501Srpaulo	DBusError error;
472214501Srpaulo	int ret = -1;
473214501Srpaulo	DBusObjectPathVTable wpa_vtable = {
474214501Srpaulo		&free_dbus_object_desc_cb, &message_handler,
475214501Srpaulo		NULL, NULL, NULL, NULL
476214501Srpaulo	};
477214501Srpaulo
478214501Srpaulo	obj_desc->connection = iface->con;
479214501Srpaulo	obj_desc->path = os_strdup(dbus_path);
480214501Srpaulo
481214501Srpaulo	/* Register the message handler for the global dbus interface */
482214501Srpaulo	if (!dbus_connection_register_object_path(iface->con,
483214501Srpaulo						  dbus_path, &wpa_vtable,
484214501Srpaulo						  obj_desc)) {
485214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
486214501Srpaulo			   "handler");
487214501Srpaulo		return -1;
488214501Srpaulo	}
489214501Srpaulo
490214501Srpaulo	/* Register our service with the message bus */
491214501Srpaulo	dbus_error_init(&error);
492214501Srpaulo	switch (dbus_bus_request_name(iface->con, dbus_service,
493214501Srpaulo				      0, &error)) {
494214501Srpaulo	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
495214501Srpaulo		ret = 0;
496214501Srpaulo		break;
497214501Srpaulo	case DBUS_REQUEST_NAME_REPLY_EXISTS:
498214501Srpaulo	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
499214501Srpaulo	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
500214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
501214501Srpaulo			   "already registered");
502214501Srpaulo		break;
503214501Srpaulo	default:
504214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
505214501Srpaulo			   "%s %s", error.name, error.message);
506214501Srpaulo		break;
507214501Srpaulo	}
508214501Srpaulo	dbus_error_free(&error);
509214501Srpaulo
510214501Srpaulo	if (ret != 0)
511214501Srpaulo		return -1;
512214501Srpaulo
513214501Srpaulo	wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
514214501Srpaulo
515214501Srpaulo	return 0;
516214501Srpaulo}
517214501Srpaulo
518214501Srpaulo
519214501Srpaulo/**
520214501Srpaulo * wpa_dbus_register_object_per_iface - Register a new object with dbus
521214501Srpaulo * @ctrl_iface: pointer to dbus private data
522214501Srpaulo * @path: DBus path to object
523214501Srpaulo * @ifname: interface name
524214501Srpaulo * @obj_desc: description of object's methods, signals and properties
525214501Srpaulo * Returns: 0 on success, -1 on error
526214501Srpaulo *
527214501Srpaulo * Registers a new interface with dbus and assigns it a dbus object path.
528214501Srpaulo */
529214501Srpauloint wpa_dbus_register_object_per_iface(
530214501Srpaulo	struct wpas_dbus_priv *ctrl_iface,
531214501Srpaulo	const char *path, const char *ifname,
532214501Srpaulo	struct wpa_dbus_object_desc *obj_desc)
533214501Srpaulo{
534214501Srpaulo	DBusConnection *con;
535252190Srpaulo	DBusError error;
536214501Srpaulo
537214501Srpaulo	DBusObjectPathVTable vtable = {
538214501Srpaulo		&free_dbus_object_desc_cb, &message_handler,
539214501Srpaulo		NULL, NULL, NULL, NULL
540214501Srpaulo	};
541214501Srpaulo
542214501Srpaulo	/* Do nothing if the control interface is not turned on */
543214501Srpaulo	if (ctrl_iface == NULL)
544214501Srpaulo		return 0;
545214501Srpaulo
546214501Srpaulo	con = ctrl_iface->con;
547214501Srpaulo	obj_desc->connection = con;
548214501Srpaulo	obj_desc->path = os_strdup(path);
549214501Srpaulo
550252190Srpaulo	dbus_error_init(&error);
551214501Srpaulo	/* Register the message handler for the interface functions */
552252190Srpaulo	if (!dbus_connection_try_register_object_path(con, path, &vtable,
553252190Srpaulo						      obj_desc, &error)) {
554252190Srpaulo		if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) {
555252190Srpaulo			wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
556252190Srpaulo		} else {
557252190Srpaulo			wpa_printf(MSG_ERROR, "dbus: Could not set up message "
558252190Srpaulo				   "handler for interface %s object %s",
559252190Srpaulo				   ifname, path);
560252190Srpaulo			wpa_printf(MSG_ERROR, "dbus error: %s", error.name);
561252190Srpaulo			wpa_printf(MSG_ERROR, "dbus: %s", error.message);
562252190Srpaulo		}
563252190Srpaulo		dbus_error_free(&error);
564214501Srpaulo		return -1;
565214501Srpaulo	}
566214501Srpaulo
567252190Srpaulo	dbus_error_free(&error);
568214501Srpaulo	return 0;
569214501Srpaulo}
570214501Srpaulo
571214501Srpaulo
572214501Srpaulostatic void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx);
573214501Srpaulo
574214501Srpaulo
575214501Srpaulo/**
576214501Srpaulo * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
577214501Srpaulo * @ctrl_iface: Pointer to dbus private data
578214501Srpaulo * @path: DBus path to object which will be unregistered
579214501Srpaulo * Returns: Zero on success and -1 on failure
580214501Srpaulo *
581214501Srpaulo * Unregisters DBus object given by its path
582214501Srpaulo */
583214501Srpauloint wpa_dbus_unregister_object_per_iface(
584214501Srpaulo	struct wpas_dbus_priv *ctrl_iface, const char *path)
585214501Srpaulo{
586214501Srpaulo	DBusConnection *con = ctrl_iface->con;
587214501Srpaulo	struct wpa_dbus_object_desc *obj_desc = NULL;
588214501Srpaulo
589214501Srpaulo	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
590214501Srpaulo	if (!obj_desc) {
591214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
592214501Srpaulo			   "private data: %s", __func__, path);
593214501Srpaulo	} else {
594214501Srpaulo		eloop_cancel_timeout(flush_object_timeout_handler, con,
595214501Srpaulo				     obj_desc);
596214501Srpaulo	}
597214501Srpaulo
598214501Srpaulo	if (!dbus_connection_unregister_object_path(con, path))
599214501Srpaulo		return -1;
600214501Srpaulo
601214501Srpaulo	return 0;
602214501Srpaulo}
603214501Srpaulo
604214501Srpaulo
605252190Srpaulostatic dbus_bool_t put_changed_properties(
606252190Srpaulo	const struct wpa_dbus_object_desc *obj_dsc, const char *interface,
607252190Srpaulo	DBusMessageIter *dict_iter, int clear_changed)
608214501Srpaulo{
609252190Srpaulo	DBusMessageIter entry_iter;
610214501Srpaulo	const struct wpa_dbus_property_desc *dsc;
611214501Srpaulo	int i;
612252190Srpaulo	DBusError error;
613214501Srpaulo
614214501Srpaulo	for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property;
615214501Srpaulo	     dsc++, i++) {
616214501Srpaulo		if (obj_dsc->prop_changed_flags == NULL ||
617214501Srpaulo		    !obj_dsc->prop_changed_flags[i])
618214501Srpaulo			continue;
619214501Srpaulo		if (os_strcmp(dsc->dbus_interface, interface) != 0)
620214501Srpaulo			continue;
621252190Srpaulo		if (clear_changed)
622252190Srpaulo			obj_dsc->prop_changed_flags[i] = 0;
623214501Srpaulo
624252190Srpaulo		if (!dbus_message_iter_open_container(dict_iter,
625252190Srpaulo						      DBUS_TYPE_DICT_ENTRY,
626252190Srpaulo						      NULL, &entry_iter))
627252190Srpaulo			return FALSE;
628214501Srpaulo
629252190Srpaulo		if (!dbus_message_iter_append_basic(&entry_iter,
630214501Srpaulo						    DBUS_TYPE_STRING,
631214501Srpaulo						    &dsc->dbus_property))
632252190Srpaulo			return FALSE;
633214501Srpaulo
634252190Srpaulo		dbus_error_init(&error);
635252190Srpaulo		if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
636252190Srpaulo			if (dbus_error_is_set (&error)) {
637252190Srpaulo				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
638252190Srpaulo					   "new value of property %s: (%s) %s",
639252190Srpaulo				           __func__, dsc->dbus_property,
640252190Srpaulo				           error.name, error.message);
641252190Srpaulo			} else {
642252190Srpaulo				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
643252190Srpaulo					   "new value of property %s",
644252190Srpaulo					   __func__, dsc->dbus_property);
645252190Srpaulo			}
646252190Srpaulo			dbus_error_free(&error);
647252190Srpaulo			return FALSE;
648252190Srpaulo		}
649214501Srpaulo
650214501Srpaulo		if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
651252190Srpaulo			return FALSE;
652214501Srpaulo	}
653214501Srpaulo
654252190Srpaulo	return TRUE;
655252190Srpaulo}
656252190Srpaulo
657252190Srpaulo
658252190Srpaulostatic void do_send_prop_changed_signal(
659252190Srpaulo	DBusConnection *con, const char *path, const char *interface,
660252190Srpaulo	const struct wpa_dbus_object_desc *obj_dsc)
661252190Srpaulo{
662252190Srpaulo	DBusMessage *msg;
663252190Srpaulo	DBusMessageIter signal_iter, dict_iter;
664252190Srpaulo
665252190Srpaulo	msg = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES,
666252190Srpaulo				      "PropertiesChanged");
667252190Srpaulo	if (msg == NULL)
668252190Srpaulo		return;
669252190Srpaulo
670252190Srpaulo	dbus_message_iter_init_append(msg, &signal_iter);
671252190Srpaulo
672252190Srpaulo	if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
673252190Srpaulo					    &interface))
674252190Srpaulo		goto err;
675252190Srpaulo
676252190Srpaulo	/* Changed properties dict */
677252190Srpaulo	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
678252190Srpaulo					      "{sv}", &dict_iter))
679252190Srpaulo		goto err;
680252190Srpaulo
681252190Srpaulo	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0))
682252190Srpaulo		goto err;
683252190Srpaulo
684252190Srpaulo	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
685252190Srpaulo		goto err;
686252190Srpaulo
687252190Srpaulo	/* Invalidated properties array (empty) */
688252190Srpaulo	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
689252190Srpaulo					      "s", &dict_iter))
690252190Srpaulo		goto err;
691252190Srpaulo
692252190Srpaulo	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
693252190Srpaulo		goto err;
694252190Srpaulo
695252190Srpaulo	dbus_connection_send(con, msg, NULL);
696252190Srpaulo
697252190Srpauloout:
698252190Srpaulo	dbus_message_unref(msg);
699214501Srpaulo	return;
700214501Srpaulo
701214501Srpauloerr:
702252190Srpaulo	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
703252190Srpaulo		   __func__);
704252190Srpaulo	goto out;
705214501Srpaulo}
706214501Srpaulo
707214501Srpaulo
708252190Srpaulostatic void do_send_deprecated_prop_changed_signal(
709214501Srpaulo	DBusConnection *con, const char *path, const char *interface,
710214501Srpaulo	const struct wpa_dbus_object_desc *obj_dsc)
711214501Srpaulo{
712214501Srpaulo	DBusMessage *msg;
713214501Srpaulo	DBusMessageIter signal_iter, dict_iter;
714214501Srpaulo
715214501Srpaulo	msg = dbus_message_new_signal(path, interface, "PropertiesChanged");
716214501Srpaulo	if (msg == NULL)
717214501Srpaulo		return;
718214501Srpaulo
719214501Srpaulo	dbus_message_iter_init_append(msg, &signal_iter);
720214501Srpaulo
721214501Srpaulo	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
722214501Srpaulo					      "{sv}", &dict_iter))
723214501Srpaulo		goto err;
724214501Srpaulo
725252190Srpaulo	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
726252190Srpaulo		goto err;
727214501Srpaulo
728214501Srpaulo	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
729214501Srpaulo		goto err;
730214501Srpaulo
731214501Srpaulo	dbus_connection_send(con, msg, NULL);
732214501Srpaulo
733214501Srpauloout:
734214501Srpaulo	dbus_message_unref(msg);
735214501Srpaulo	return;
736214501Srpaulo
737214501Srpauloerr:
738214501Srpaulo	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
739214501Srpaulo		   __func__);
740214501Srpaulo	goto out;
741214501Srpaulo}
742214501Srpaulo
743214501Srpaulo
744252190Srpaulostatic void send_prop_changed_signal(
745252190Srpaulo	DBusConnection *con, const char *path, const char *interface,
746252190Srpaulo	const struct wpa_dbus_object_desc *obj_dsc)
747252190Srpaulo{
748252190Srpaulo	/*
749252190Srpaulo	 * First, send property change notification on the standardized
750252190Srpaulo	 * org.freedesktop.DBus.Properties interface. This call will not
751252190Srpaulo	 * clear the property change bits, so that they are preserved for
752252190Srpaulo	 * the call that follows.
753252190Srpaulo	 */
754252190Srpaulo	do_send_prop_changed_signal(con, path, interface, obj_dsc);
755252190Srpaulo
756252190Srpaulo	/*
757252190Srpaulo	 * Now send PropertiesChanged on our own interface for backwards
758252190Srpaulo	 * compatibility. This is deprecated and will be removed in a future
759252190Srpaulo	 * release.
760252190Srpaulo	 */
761252190Srpaulo	do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc);
762252190Srpaulo
763252190Srpaulo	/* Property change bits have now been cleared. */
764252190Srpaulo}
765252190Srpaulo
766252190Srpaulo
767214501Srpaulostatic void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx)
768214501Srpaulo{
769214501Srpaulo	DBusConnection *con = eloop_ctx;
770214501Srpaulo	struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
771214501Srpaulo
772214501Srpaulo	wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties "
773214501Srpaulo		   "of object %s", __func__, obj_desc->path);
774214501Srpaulo	wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
775214501Srpaulo}
776214501Srpaulo
777214501Srpaulo
778214501Srpaulostatic void recursive_flush_changed_properties(DBusConnection *con,
779214501Srpaulo					       const char *path)
780214501Srpaulo{
781214501Srpaulo	char **objects = NULL;
782214501Srpaulo	char subobj_path[WPAS_DBUS_OBJECT_PATH_MAX];
783214501Srpaulo	int i;
784214501Srpaulo
785214501Srpaulo	wpa_dbus_flush_object_changed_properties(con, path);
786214501Srpaulo
787214501Srpaulo	if (!dbus_connection_list_registered(con, path, &objects))
788214501Srpaulo		goto out;
789214501Srpaulo
790214501Srpaulo	for (i = 0; objects[i]; i++) {
791214501Srpaulo		os_snprintf(subobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
792214501Srpaulo			    "%s/%s", path, objects[i]);
793214501Srpaulo		recursive_flush_changed_properties(con, subobj_path);
794214501Srpaulo	}
795214501Srpaulo
796214501Srpauloout:
797214501Srpaulo	dbus_free_string_array(objects);
798214501Srpaulo}
799214501Srpaulo
800214501Srpaulo
801214501Srpaulo/**
802214501Srpaulo * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals
803214501Srpaulo * @con: DBus connection
804214501Srpaulo *
805214501Srpaulo * Traverses through all registered objects and sends PropertiesChanged for
806214501Srpaulo * each properties.
807214501Srpaulo */
808214501Srpaulovoid wpa_dbus_flush_all_changed_properties(DBusConnection *con)
809214501Srpaulo{
810214501Srpaulo	recursive_flush_changed_properties(con, WPAS_DBUS_NEW_PATH);
811214501Srpaulo}
812214501Srpaulo
813214501Srpaulo
814214501Srpaulo/**
815214501Srpaulo * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object
816214501Srpaulo * @con: DBus connection
817214501Srpaulo * @path: path to a DBus object for which PropertiesChanged will be sent.
818214501Srpaulo *
819214501Srpaulo * Iterates over all properties registered with object and for each interface
820214501Srpaulo * containing properties marked as changed, sends a PropertiesChanged signal
821214501Srpaulo * containing names and new values of properties that have changed.
822214501Srpaulo *
823214501Srpaulo * You need to call this function after wpa_dbus_mark_property_changed()
824214501Srpaulo * if you want to send PropertiesChanged signal immediately (i.e., without
825214501Srpaulo * waiting timeout to expire). PropertiesChanged signal for an object is sent
826214501Srpaulo * automatically short time after first marking property as changed. All
827214501Srpaulo * PropertiesChanged signals are sent automatically after responding on DBus
828214501Srpaulo * message, so if you marked a property changed as a result of DBus call
829214501Srpaulo * (e.g., param setter), you usually do not need to call this function.
830214501Srpaulo */
831214501Srpaulovoid wpa_dbus_flush_object_changed_properties(DBusConnection *con,
832214501Srpaulo					      const char *path)
833214501Srpaulo{
834214501Srpaulo	struct wpa_dbus_object_desc *obj_desc = NULL;
835214501Srpaulo	const struct wpa_dbus_property_desc *dsc;
836214501Srpaulo	int i;
837214501Srpaulo
838214501Srpaulo	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
839214501Srpaulo	if (!obj_desc)
840214501Srpaulo		return;
841214501Srpaulo	eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
842214501Srpaulo
843214501Srpaulo	dsc = obj_desc->properties;
844214501Srpaulo	for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property;
845214501Srpaulo	     dsc++, i++) {
846214501Srpaulo		if (obj_desc->prop_changed_flags == NULL ||
847214501Srpaulo		    !obj_desc->prop_changed_flags[i])
848214501Srpaulo			continue;
849214501Srpaulo		send_prop_changed_signal(con, path, dsc->dbus_interface,
850214501Srpaulo					 obj_desc);
851214501Srpaulo	}
852214501Srpaulo}
853214501Srpaulo
854214501Srpaulo
855214501Srpaulo#define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000
856214501Srpaulo
857214501Srpaulo
858214501Srpaulo/**
859214501Srpaulo * wpa_dbus_mark_property_changed - Mark a property as changed and
860214501Srpaulo * @iface: dbus priv struct
861214501Srpaulo * @path: path to DBus object which property has changed
862214501Srpaulo * @interface: interface containing changed property
863214501Srpaulo * @property: property name which has changed
864214501Srpaulo *
865214501Srpaulo * Iterates over all properties registered with an object and marks the one
866214501Srpaulo * given in parameters as changed. All parameters registered for an object
867214501Srpaulo * within a single interface will be aggregated together and sent in one
868214501Srpaulo * PropertiesChanged signal when function
869214501Srpaulo * wpa_dbus_flush_object_changed_properties() is called.
870214501Srpaulo */
871214501Srpaulovoid wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
872214501Srpaulo				    const char *path, const char *interface,
873214501Srpaulo				    const char *property)
874214501Srpaulo{
875214501Srpaulo	struct wpa_dbus_object_desc *obj_desc = NULL;
876214501Srpaulo	const struct wpa_dbus_property_desc *dsc;
877214501Srpaulo	int i = 0;
878214501Srpaulo
879214501Srpaulo	if (iface == NULL)
880214501Srpaulo		return;
881214501Srpaulo
882214501Srpaulo	dbus_connection_get_object_path_data(iface->con, path,
883214501Srpaulo					     (void **) &obj_desc);
884214501Srpaulo	if (!obj_desc) {
885214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
886214501Srpaulo			   "could not obtain object's private data: %s", path);
887214501Srpaulo		return;
888214501Srpaulo	}
889214501Srpaulo
890214501Srpaulo	for (dsc = obj_desc->properties; dsc && dsc->dbus_property; dsc++, i++)
891214501Srpaulo		if (os_strcmp(property, dsc->dbus_property) == 0 &&
892214501Srpaulo		    os_strcmp(interface, dsc->dbus_interface) == 0) {
893214501Srpaulo			if (obj_desc->prop_changed_flags)
894214501Srpaulo				obj_desc->prop_changed_flags[i] = 1;
895214501Srpaulo			break;
896214501Srpaulo		}
897214501Srpaulo
898214501Srpaulo	if (!dsc || !dsc->dbus_property) {
899214501Srpaulo		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
900214501Srpaulo			   "no property %s in object %s", property, path);
901214501Srpaulo		return;
902214501Srpaulo	}
903214501Srpaulo
904214501Srpaulo	if (!eloop_is_timeout_registered(flush_object_timeout_handler,
905214501Srpaulo					 iface->con, obj_desc->path)) {
906214501Srpaulo		eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
907214501Srpaulo				       flush_object_timeout_handler,
908214501Srpaulo				       iface->con, obj_desc);
909214501Srpaulo	}
910214501Srpaulo}
911214501Srpaulo
912214501Srpaulo
913214501Srpaulo/**
914214501Srpaulo * wpa_dbus_get_object_properties - Put object's properties into dictionary
915214501Srpaulo * @iface: dbus priv struct
916214501Srpaulo * @path: path to DBus object which properties will be obtained
917214501Srpaulo * @interface: interface name which properties will be obtained
918252190Srpaulo * @iter: DBus message iter at which to append property dictionary.
919214501Srpaulo *
920214501Srpaulo * Iterates over all properties registered with object and execute getters
921214501Srpaulo * of those, which are readable and which interface matches interface
922214501Srpaulo * specified as argument. Obtained properties values are stored in
923214501Srpaulo * dict_iter dictionary.
924214501Srpaulo */
925252190Srpaulodbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
926252190Srpaulo					   const char *path,
927252190Srpaulo					   const char *interface,
928252190Srpaulo					   DBusMessageIter *iter)
929214501Srpaulo{
930214501Srpaulo	struct wpa_dbus_object_desc *obj_desc = NULL;
931252190Srpaulo	DBusMessageIter dict_iter;
932252190Srpaulo	DBusError error;
933214501Srpaulo
934214501Srpaulo	dbus_connection_get_object_path_data(iface->con, path,
935214501Srpaulo					     (void **) &obj_desc);
936214501Srpaulo	if (!obj_desc) {
937252190Srpaulo		wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
938252190Srpaulo		           "private data: %s", __func__, path);
939252190Srpaulo		return FALSE;
940214501Srpaulo	}
941214501Srpaulo
942252190Srpaulo	if (!wpa_dbus_dict_open_write(iter, &dict_iter)) {
943252190Srpaulo		wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict",
944252190Srpaulo			   __func__);
945252190Srpaulo		return FALSE;
946252190Srpaulo	}
947252190Srpaulo
948252190Srpaulo	dbus_error_init(&error);
949252190Srpaulo	if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
950252190Srpaulo				       interface, obj_desc->user_data,
951252190Srpaulo				       &error)) {
952252190Srpaulo		wpa_printf(MSG_ERROR, "dbus: %s: failed to get object"
953252190Srpaulo		           " properties: (%s) %s", __func__,
954252190Srpaulo		           dbus_error_is_set(&error) ? error.name : "none",
955252190Srpaulo		           dbus_error_is_set(&error) ? error.message : "none");
956252190Srpaulo		dbus_error_free(&error);
957252190Srpaulo		return FALSE;
958252190Srpaulo	}
959252190Srpaulo
960252190Srpaulo	return wpa_dbus_dict_close_write(iter, &dict_iter);
961214501Srpaulo}
962252190Srpaulo
963252190Srpaulo/**
964252190Srpaulo * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
965252190Srpaulo * @path: The dbus object path
966252190Srpaulo * @p2p_persistent_group: indicates whether to parse the path as a P2P
967252190Srpaulo *                        persistent group object
968252190Srpaulo * @network: (out) the configured network this object path refers to, if any
969252190Srpaulo * @bssid: (out) the scanned bssid this object path refers to, if any
970252190Srpaulo * Returns: The object path of the network interface this path refers to
971252190Srpaulo *
972252190Srpaulo * For a given object path, decomposes the object path into object id, network,
973252190Srpaulo * and BSSID parts, if those parts exist.
974252190Srpaulo */
975252190Srpaulochar *wpas_dbus_new_decompose_object_path(const char *path,
976252190Srpaulo					   int p2p_persistent_group,
977252190Srpaulo					   char **network,
978252190Srpaulo					   char **bssid)
979252190Srpaulo{
980252190Srpaulo	const unsigned int dev_path_prefix_len =
981252190Srpaulo		os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
982252190Srpaulo	char *obj_path_only;
983252190Srpaulo	char *next_sep;
984252190Srpaulo
985252190Srpaulo	/* Be a bit paranoid about path */
986252190Srpaulo	if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
987252190Srpaulo				dev_path_prefix_len))
988252190Srpaulo		return NULL;
989252190Srpaulo
990252190Srpaulo	/* Ensure there's something at the end of the path */
991252190Srpaulo	if ((path + dev_path_prefix_len)[0] == '\0')
992252190Srpaulo		return NULL;
993252190Srpaulo
994252190Srpaulo	obj_path_only = os_strdup(path);
995252190Srpaulo	if (obj_path_only == NULL)
996252190Srpaulo		return NULL;
997252190Srpaulo
998252190Srpaulo	next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
999252190Srpaulo	if (next_sep != NULL) {
1000252190Srpaulo		const char *net_part = os_strstr(
1001252190Srpaulo			next_sep, p2p_persistent_group ?
1002252190Srpaulo			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
1003252190Srpaulo			WPAS_DBUS_NEW_NETWORKS_PART "/");
1004252190Srpaulo		const char *bssid_part = os_strstr(
1005252190Srpaulo			next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
1006252190Srpaulo
1007252190Srpaulo		if (network && net_part) {
1008252190Srpaulo			/* Deal with a request for a configured network */
1009252190Srpaulo			const char *net_name = net_part +
1010252190Srpaulo				os_strlen(p2p_persistent_group ?
1011252190Srpaulo					  WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
1012252190Srpaulo					  "/" :
1013252190Srpaulo					  WPAS_DBUS_NEW_NETWORKS_PART "/");
1014252190Srpaulo			*network = NULL;
1015252190Srpaulo			if (os_strlen(net_name))
1016252190Srpaulo				*network = os_strdup(net_name);
1017252190Srpaulo		} else if (bssid && bssid_part) {
1018252190Srpaulo			/* Deal with a request for a scanned BSSID */
1019252190Srpaulo			const char *bssid_name = bssid_part +
1020252190Srpaulo				os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
1021252190Srpaulo			if (os_strlen(bssid_name))
1022252190Srpaulo				*bssid = os_strdup(bssid_name);
1023252190Srpaulo			else
1024252190Srpaulo				*bssid = NULL;
1025252190Srpaulo		}
1026252190Srpaulo
1027252190Srpaulo		/* Cut off interface object path before "/" */
1028252190Srpaulo		*next_sep = '\0';
1029252190Srpaulo	}
1030252190Srpaulo
1031252190Srpaulo	return obj_path_only;
1032252190Srpaulo}
1033252190Srpaulo
1034252190Srpaulo
1035252190Srpaulo/**
1036252190Srpaulo * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a
1037252190Srpaulo *   dbus error structure
1038252190Srpaulo * @message: The original request message for which the error is a reply
1039252190Srpaulo * @error: The error containing a name and a descriptive error cause
1040252190Srpaulo * @fallback_name: A generic error name if @error was not set
1041252190Srpaulo * @fallback_string: A generic error string if @error was not set
1042252190Srpaulo * Returns: A new D-Bus error message
1043252190Srpaulo *
1044252190Srpaulo * Given a DBusMessage structure, creates a new D-Bus error message using
1045252190Srpaulo * the error name and string contained in that structure.
1046252190Srpaulo */
1047252190SrpauloDBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message,
1048252190Srpaulo					     DBusError *error,
1049252190Srpaulo					     const char *fallback_name,
1050252190Srpaulo					     const char *fallback_string)
1051252190Srpaulo{
1052252190Srpaulo	if (error && error->name && error->message) {
1053252190Srpaulo		return dbus_message_new_error(message, error->name,
1054252190Srpaulo					      error->message);
1055252190Srpaulo	}
1056252190Srpaulo	if (fallback_name && fallback_string) {
1057252190Srpaulo		return dbus_message_new_error(message, fallback_name,
1058252190Srpaulo					      fallback_string);
1059252190Srpaulo	}
1060252190Srpaulo	return NULL;
1061252190Srpaulo}
1062