2 * WPA Supplicant / dbus-based control interface
3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4 * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
10 #include "utils/includes.h"
12 #include "utils/common.h"
13 #include "utils/eloop.h"
14 #include "dbus_common.h"
15 #include "dbus_common_i.h"
17 #include "dbus_new_helpers.h"
18 #include "dbus_dict_helpers.h"
21 static dbus_bool_t
fill_dict_with_properties(
22 DBusMessageIter
*dict_iter
,
23 const struct wpa_dbus_property_desc
*props
,
24 const char *interface
, void *user_data
, DBusError
*error
)
26 DBusMessageIter entry_iter
;
27 const struct wpa_dbus_property_desc
*dsc
;
29 for (dsc
= props
; dsc
&& dsc
->dbus_property
; dsc
++) {
30 /* Only return properties for the requested D-Bus interface */
31 if (os_strncmp(dsc
->dbus_interface
, interface
,
32 WPAS_DBUS_INTERFACE_MAX
) != 0)
35 /* Skip write-only properties */
36 if (dsc
->getter
== NULL
)
39 if (!dbus_message_iter_open_container(dict_iter
,
42 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
,
46 if (!dbus_message_iter_append_basic(&entry_iter
,
48 &dsc
->dbus_property
)) {
49 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
,
54 /* An error getting a property fails the request entirely */
55 if (!dsc
->getter(&entry_iter
, error
, user_data
))
58 dbus_message_iter_close_container(dict_iter
, &entry_iter
);
66 * get_all_properties - Responds for GetAll properties calls on object
67 * @message: Message with GetAll call
68 * @interface: interface name which properties will be returned
69 * @property_dsc: list of object's properties
70 * Returns: Message with dict of variants as argument with properties values
72 * Iterates over all properties registered with object and execute getters
73 * of those, which are readable and which interface matches interface
74 * specified as argument. Returned message contains one dict argument
75 * with properties names as keys and theirs values as values.
77 static DBusMessage
* get_all_properties(DBusMessage
*message
, char *interface
,
78 struct wpa_dbus_object_desc
*obj_dsc
)
81 DBusMessageIter iter
, dict_iter
;
84 reply
= dbus_message_new_method_return(message
);
86 wpa_printf(MSG_ERROR
, "%s: out of memory creating dbus reply",
91 dbus_message_iter_init_append(reply
, &iter
);
92 if (!wpa_dbus_dict_open_write(&iter
, &dict_iter
)) {
93 wpa_printf(MSG_ERROR
, "%s: out of memory creating reply",
95 dbus_message_unref(reply
);
96 reply
= dbus_message_new_error(message
, DBUS_ERROR_NO_MEMORY
,
101 dbus_error_init(&error
);
102 if (!fill_dict_with_properties(&dict_iter
, obj_dsc
->properties
,
103 interface
, obj_dsc
->user_data
, &error
))
105 dbus_message_unref(reply
);
106 reply
= wpas_dbus_reply_new_from_error(message
, &error
,
107 DBUS_ERROR_INVALID_ARGS
,
108 "No readable properties"
109 " in this interface");
110 dbus_error_free(&error
);
114 wpa_dbus_dict_close_write(&iter
, &dict_iter
);
119 static int is_signature_correct(DBusMessage
*message
,
120 const struct wpa_dbus_method_desc
*method_dsc
)
122 /* According to DBus documentation max length of signature is 255 */
123 #define MAX_SIG_LEN 256
124 char registered_sig
[MAX_SIG_LEN
], *pos
;
125 const char *sig
= dbus_message_get_signature(message
);
127 const struct wpa_dbus_argument
*arg
;
129 pos
= registered_sig
;
132 for (arg
= method_dsc
->args
; arg
&& arg
->name
; arg
++) {
133 if (arg
->dir
== ARG_IN
) {
134 size_t blen
= registered_sig
+ MAX_SIG_LEN
- pos
;
135 ret
= os_snprintf(pos
, blen
, "%s", arg
->type
);
136 if (ret
< 0 || (size_t) ret
>= blen
)
142 return !os_strncmp(registered_sig
, sig
, MAX_SIG_LEN
);
146 static DBusMessage
* properties_get_all(DBusMessage
*message
, char *interface
,
147 struct wpa_dbus_object_desc
*obj_dsc
)
149 if (os_strcmp(dbus_message_get_signature(message
), "s") != 0)
150 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
153 return get_all_properties(message
, interface
, obj_dsc
);
157 static DBusMessage
* properties_get(DBusMessage
*message
,
158 const struct wpa_dbus_property_desc
*dsc
,
162 DBusMessageIter iter
;
165 if (os_strcmp(dbus_message_get_signature(message
), "ss")) {
166 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
170 if (dsc
->getter
== NULL
) {
171 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
172 "Property is write-only");
175 reply
= dbus_message_new_method_return(message
);
176 dbus_message_iter_init_append(reply
, &iter
);
178 dbus_error_init(&error
);
179 if (dsc
->getter(&iter
, &error
, user_data
) == FALSE
) {
180 dbus_message_unref(reply
);
181 reply
= wpas_dbus_reply_new_from_error(
182 message
, &error
, DBUS_ERROR_FAILED
,
183 "Failed to read property");
184 dbus_error_free(&error
);
191 static DBusMessage
* properties_set(DBusMessage
*message
,
192 const struct wpa_dbus_property_desc
*dsc
,
196 DBusMessageIter iter
;
199 if (os_strcmp(dbus_message_get_signature(message
), "ssv")) {
200 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
204 if (dsc
->setter
== NULL
) {
205 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
206 "Property is read-only");
209 dbus_message_iter_init(message
, &iter
);
210 /* Skip the interface name and the property name */
211 dbus_message_iter_next(&iter
);
212 dbus_message_iter_next(&iter
);
214 /* Iter will now point to the property's new value */
215 dbus_error_init(&error
);
216 if (dsc
->setter(&iter
, &error
, user_data
) == TRUE
) {
218 reply
= dbus_message_new_method_return(message
);
220 reply
= wpas_dbus_reply_new_from_error(
221 message
, &error
, DBUS_ERROR_FAILED
,
222 "Failed to set property");
223 dbus_error_free(&error
);
231 properties_get_or_set(DBusMessage
*message
, DBusMessageIter
*iter
,
233 struct wpa_dbus_object_desc
*obj_dsc
)
235 const struct wpa_dbus_property_desc
*property_dsc
;
239 method
= dbus_message_get_member(message
);
240 property_dsc
= obj_dsc
->properties
;
242 /* Second argument: property name (DBUS_TYPE_STRING) */
243 if (!dbus_message_iter_next(iter
) ||
244 dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_STRING
) {
245 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
248 dbus_message_iter_get_basic(iter
, &property
);
250 while (property_dsc
&& property_dsc
->dbus_property
) {
251 /* compare property names and
253 if (!os_strncmp(property_dsc
->dbus_property
, property
,
254 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) &&
255 !os_strncmp(property_dsc
->dbus_interface
, interface
,
256 WPAS_DBUS_INTERFACE_MAX
))
261 if (property_dsc
== NULL
|| property_dsc
->dbus_property
== NULL
) {
262 wpa_printf(MSG_DEBUG
, "no property handler for %s.%s on %s",
264 dbus_message_get_path(message
));
265 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
269 if (os_strncmp(WPA_DBUS_PROPERTIES_GET
, method
,
270 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) == 0)
271 return properties_get(message
, property_dsc
,
274 return properties_set(message
, property_dsc
, obj_dsc
->user_data
);
278 static DBusMessage
* properties_handler(DBusMessage
*message
,
279 struct wpa_dbus_object_desc
*obj_dsc
)
281 DBusMessageIter iter
;
285 method
= dbus_message_get_member(message
);
286 dbus_message_iter_init(message
, &iter
);
288 if (!os_strncmp(WPA_DBUS_PROPERTIES_GET
, method
,
289 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) ||
290 !os_strncmp(WPA_DBUS_PROPERTIES_SET
, method
,
291 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) ||
292 !os_strncmp(WPA_DBUS_PROPERTIES_GETALL
, method
,
293 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
)) {
294 /* First argument: interface name (DBUS_TYPE_STRING) */
295 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
297 return dbus_message_new_error(message
,
298 DBUS_ERROR_INVALID_ARGS
,
302 dbus_message_iter_get_basic(&iter
, &interface
);
304 if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL
, method
,
305 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
)) {
307 return properties_get_all(message
, interface
, obj_dsc
);
310 return properties_get_or_set(message
, &iter
, interface
,
313 return dbus_message_new_error(message
, DBUS_ERROR_UNKNOWN_METHOD
,
318 static DBusMessage
* msg_method_handler(DBusMessage
*message
,
319 struct wpa_dbus_object_desc
*obj_dsc
)
321 const struct wpa_dbus_method_desc
*method_dsc
= obj_dsc
->methods
;
323 const char *msg_interface
;
325 method
= dbus_message_get_member(message
);
326 msg_interface
= dbus_message_get_interface(message
);
328 /* try match call to any registered method */
329 while (method_dsc
&& method_dsc
->dbus_method
) {
330 /* compare method names and interfaces */
331 if (!os_strncmp(method_dsc
->dbus_method
, method
,
332 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) &&
333 !os_strncmp(method_dsc
->dbus_interface
, msg_interface
,
334 WPAS_DBUS_INTERFACE_MAX
))
339 if (method_dsc
== NULL
|| method_dsc
->dbus_method
== NULL
) {
340 wpa_printf(MSG_DEBUG
, "no method handler for %s.%s on %s",
341 msg_interface
, method
,
342 dbus_message_get_path(message
));
343 return dbus_message_new_error(message
,
344 DBUS_ERROR_UNKNOWN_METHOD
, NULL
);
347 if (!is_signature_correct(message
, method_dsc
)) {
348 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
352 return method_dsc
->method_handler(message
,
358 * message_handler - Handles incoming DBus messages
359 * @connection: DBus connection on which message was received
360 * @message: Received message
361 * @user_data: pointer to description of object to which message was sent
362 * Returns: Returns information whether message was handled or not
364 * Reads message interface and method name, then checks if they matches one
365 * of the special cases i.e. introspection call or properties get/getall/set
366 * methods and handles it. Else it iterates over registered methods list
367 * and tries to match method's name and interface to those read from message
368 * If appropriate method was found its handler function is called and
369 * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
372 static DBusHandlerResult
message_handler(DBusConnection
*connection
,
373 DBusMessage
*message
, void *user_data
)
375 struct wpa_dbus_object_desc
*obj_dsc
= user_data
;
378 const char *msg_interface
;
381 /* get method, interface and path the message is addressed to */
382 method
= dbus_message_get_member(message
);
383 path
= dbus_message_get_path(message
);
384 msg_interface
= dbus_message_get_interface(message
);
385 if (!method
|| !path
|| !msg_interface
)
386 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
388 wpa_printf(MSG_MSGDUMP
, "dbus: %s.%s (%s)",
389 msg_interface
, method
, path
);
391 /* if message is introspection method call */
392 if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD
, method
,
393 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) &&
394 !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE
, msg_interface
,
395 WPAS_DBUS_INTERFACE_MAX
)) {
396 #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
397 reply
= wpa_dbus_introspect(message
, obj_dsc
);
398 #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
399 reply
= dbus_message_new_error(
400 message
, DBUS_ERROR_UNKNOWN_METHOD
,
401 "wpa_supplicant was compiled without "
402 "introspection support.");
403 #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
404 } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE
, msg_interface
,
405 WPAS_DBUS_INTERFACE_MAX
)) {
406 /* if message is properties method call */
407 reply
= properties_handler(message
, obj_dsc
);
409 reply
= msg_method_handler(message
, obj_dsc
);
412 /* If handler succeed returning NULL, reply empty message */
414 reply
= dbus_message_new_method_return(message
);
416 if (!dbus_message_get_no_reply(message
))
417 dbus_connection_send(connection
, reply
, NULL
);
418 dbus_message_unref(reply
);
421 wpa_dbus_flush_all_changed_properties(connection
);
423 return DBUS_HANDLER_RESULT_HANDLED
;
428 * free_dbus_object_desc - Frees object description data structure
429 * @connection: DBus connection
430 * @obj_dsc: Object description to free
432 * Frees each of properties, methods and signals description lists and
433 * the object description structure itself.
435 void free_dbus_object_desc(struct wpa_dbus_object_desc
*obj_dsc
)
440 /* free handler's argument */
441 if (obj_dsc
->user_data_free_func
)
442 obj_dsc
->user_data_free_func(obj_dsc
->user_data
);
444 os_free(obj_dsc
->path
);
445 os_free(obj_dsc
->prop_changed_flags
);
450 static void free_dbus_object_desc_cb(DBusConnection
*connection
, void *obj_dsc
)
452 free_dbus_object_desc(obj_dsc
);
456 * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
457 * @application_data: Pointer to application specific data structure
458 * @dbus_path: DBus path to interface object
459 * @dbus_service: DBus service name to register with
460 * @messageHandler: a pointer to function which will handle dbus messages
461 * coming on interface
462 * Returns: 0 on success, -1 on failure
464 * Initialize the dbus control interface and start receiving commands from
465 * external programs over the bus.
467 int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv
*iface
,
468 char *dbus_path
, char *dbus_service
,
469 struct wpa_dbus_object_desc
*obj_desc
)
473 DBusObjectPathVTable wpa_vtable
= {
474 &free_dbus_object_desc_cb
, &message_handler
,
475 NULL
, NULL
, NULL
, NULL
478 obj_desc
->connection
= iface
->con
;
479 obj_desc
->path
= os_strdup(dbus_path
);
481 /* Register the message handler for the global dbus interface */
482 if (!dbus_connection_register_object_path(iface
->con
,
483 dbus_path
, &wpa_vtable
,
485 wpa_printf(MSG_ERROR
, "dbus: Could not set up message "
490 /* Register our service with the message bus */
491 dbus_error_init(&error
);
492 switch (dbus_bus_request_name(iface
->con
, dbus_service
,
494 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
:
497 case DBUS_REQUEST_NAME_REPLY_EXISTS
:
498 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE
:
499 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER
:
500 wpa_printf(MSG_ERROR
, "dbus: Could not request service name: "
501 "already registered");
504 wpa_printf(MSG_ERROR
, "dbus: Could not request service name: "
505 "%s %s", error
.name
, error
.message
);
508 dbus_error_free(&error
);
513 wpa_printf(MSG_DEBUG
, "Providing DBus service '%s'.", dbus_service
);
520 * wpa_dbus_register_object_per_iface - Register a new object with dbus
521 * @ctrl_iface: pointer to dbus private data
522 * @path: DBus path to object
523 * @ifname: interface name
524 * @obj_desc: description of object's methods, signals and properties
525 * Returns: 0 on success, -1 on error
527 * Registers a new interface with dbus and assigns it a dbus object path.
529 int wpa_dbus_register_object_per_iface(
530 struct wpas_dbus_priv
*ctrl_iface
,
531 const char *path
, const char *ifname
,
532 struct wpa_dbus_object_desc
*obj_desc
)
537 DBusObjectPathVTable vtable
= {
538 &free_dbus_object_desc_cb
, &message_handler
,
539 NULL
, NULL
, NULL
, NULL
542 /* Do nothing if the control interface is not turned on */
543 if (ctrl_iface
== NULL
)
546 con
= ctrl_iface
->con
;
547 obj_desc
->connection
= con
;
548 obj_desc
->path
= os_strdup(path
);
550 dbus_error_init(&error
);
551 /* Register the message handler for the interface functions */
552 if (!dbus_connection_try_register_object_path(con
, path
, &vtable
,
554 if (!os_strcmp(error
.name
, DBUS_ERROR_OBJECT_PATH_IN_USE
)) {
555 wpa_printf(MSG_DEBUG
, "dbus: %s", error
.message
);
557 wpa_printf(MSG_ERROR
, "dbus: Could not set up message "
558 "handler for interface %s object %s",
560 wpa_printf(MSG_ERROR
, "dbus error: %s", error
.name
);
561 wpa_printf(MSG_ERROR
, "dbus: %s", error
.message
);
563 dbus_error_free(&error
);
567 dbus_error_free(&error
);
572 static void flush_object_timeout_handler(void *eloop_ctx
, void *timeout_ctx
);
576 * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
577 * @ctrl_iface: Pointer to dbus private data
578 * @path: DBus path to object which will be unregistered
579 * Returns: Zero on success and -1 on failure
581 * Unregisters DBus object given by its path
583 int wpa_dbus_unregister_object_per_iface(
584 struct wpas_dbus_priv
*ctrl_iface
, const char *path
)
586 DBusConnection
*con
= ctrl_iface
->con
;
587 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
589 dbus_connection_get_object_path_data(con
, path
, (void **) &obj_desc
);
591 wpa_printf(MSG_ERROR
, "dbus: %s: Could not obtain object's "
592 "private data: %s", __func__
, path
);
594 eloop_cancel_timeout(flush_object_timeout_handler
, con
,
598 if (!dbus_connection_unregister_object_path(con
, path
))
605 static dbus_bool_t
put_changed_properties(
606 const struct wpa_dbus_object_desc
*obj_dsc
, const char *interface
,
607 DBusMessageIter
*dict_iter
, int clear_changed
)
609 DBusMessageIter entry_iter
;
610 const struct wpa_dbus_property_desc
*dsc
;
614 for (dsc
= obj_dsc
->properties
, i
= 0; dsc
&& dsc
->dbus_property
;
616 if (obj_dsc
->prop_changed_flags
== NULL
||
617 !obj_dsc
->prop_changed_flags
[i
])
619 if (os_strcmp(dsc
->dbus_interface
, interface
) != 0)
622 obj_dsc
->prop_changed_flags
[i
] = 0;
624 if (!dbus_message_iter_open_container(dict_iter
,
625 DBUS_TYPE_DICT_ENTRY
,
629 if (!dbus_message_iter_append_basic(&entry_iter
,
631 &dsc
->dbus_property
))
634 dbus_error_init(&error
);
635 if (!dsc
->getter(&entry_iter
, &error
, obj_dsc
->user_data
)) {
636 if (dbus_error_is_set (&error
)) {
637 wpa_printf(MSG_ERROR
, "dbus: %s: Cannot get "
638 "new value of property %s: (%s) %s",
639 __func__
, dsc
->dbus_property
,
640 error
.name
, error
.message
);
642 wpa_printf(MSG_ERROR
, "dbus: %s: Cannot get "
643 "new value of property %s",
644 __func__
, dsc
->dbus_property
);
646 dbus_error_free(&error
);
650 if (!dbus_message_iter_close_container(dict_iter
, &entry_iter
))
658 static void do_send_prop_changed_signal(
659 DBusConnection
*con
, const char *path
, const char *interface
,
660 const struct wpa_dbus_object_desc
*obj_dsc
)
663 DBusMessageIter signal_iter
, dict_iter
;
665 msg
= dbus_message_new_signal(path
, DBUS_INTERFACE_PROPERTIES
,
666 "PropertiesChanged");
670 dbus_message_iter_init_append(msg
, &signal_iter
);
672 if (!dbus_message_iter_append_basic(&signal_iter
, DBUS_TYPE_STRING
,
676 /* Changed properties dict */
677 if (!dbus_message_iter_open_container(&signal_iter
, DBUS_TYPE_ARRAY
,
681 if (!put_changed_properties(obj_dsc
, interface
, &dict_iter
, 0))
684 if (!dbus_message_iter_close_container(&signal_iter
, &dict_iter
))
687 /* Invalidated properties array (empty) */
688 if (!dbus_message_iter_open_container(&signal_iter
, DBUS_TYPE_ARRAY
,
692 if (!dbus_message_iter_close_container(&signal_iter
, &dict_iter
))
695 dbus_connection_send(con
, msg
, NULL
);
698 dbus_message_unref(msg
);
702 wpa_printf(MSG_DEBUG
, "dbus: %s: Failed to construct signal",
708 static void do_send_deprecated_prop_changed_signal(
709 DBusConnection
*con
, const char *path
, const char *interface
,
710 const struct wpa_dbus_object_desc
*obj_dsc
)
713 DBusMessageIter signal_iter
, dict_iter
;
715 msg
= dbus_message_new_signal(path
, interface
, "PropertiesChanged");
719 dbus_message_iter_init_append(msg
, &signal_iter
);
721 if (!dbus_message_iter_open_container(&signal_iter
, DBUS_TYPE_ARRAY
,
725 if (!put_changed_properties(obj_dsc
, interface
, &dict_iter
, 1))
728 if (!dbus_message_iter_close_container(&signal_iter
, &dict_iter
))
731 dbus_connection_send(con
, msg
, NULL
);
734 dbus_message_unref(msg
);
738 wpa_printf(MSG_DEBUG
, "dbus: %s: Failed to construct signal",
744 static void send_prop_changed_signal(
745 DBusConnection
*con
, const char *path
, const char *interface
,
746 const struct wpa_dbus_object_desc
*obj_dsc
)
749 * First, send property change notification on the standardized
750 * org.freedesktop.DBus.Properties interface. This call will not
751 * clear the property change bits, so that they are preserved for
752 * the call that follows.
754 do_send_prop_changed_signal(con
, path
, interface
, obj_dsc
);
757 * Now send PropertiesChanged on our own interface for backwards
758 * compatibility. This is deprecated and will be removed in a future
761 do_send_deprecated_prop_changed_signal(con
, path
, interface
, obj_dsc
);
763 /* Property change bits have now been cleared. */
767 static void flush_object_timeout_handler(void *eloop_ctx
, void *timeout_ctx
)
769 DBusConnection
*con
= eloop_ctx
;
770 struct wpa_dbus_object_desc
*obj_desc
= timeout_ctx
;
772 wpa_printf(MSG_DEBUG
, "dbus: %s: Timeout - sending changed properties "
773 "of object %s", __func__
, obj_desc
->path
);
774 wpa_dbus_flush_object_changed_properties(con
, obj_desc
->path
);
778 static void recursive_flush_changed_properties(DBusConnection
*con
,
781 char **objects
= NULL
;
782 char subobj_path
[WPAS_DBUS_OBJECT_PATH_MAX
];
785 wpa_dbus_flush_object_changed_properties(con
, path
);
787 if (!dbus_connection_list_registered(con
, path
, &objects
))
790 for (i
= 0; objects
[i
]; i
++) {
791 os_snprintf(subobj_path
, WPAS_DBUS_OBJECT_PATH_MAX
,
792 "%s/%s", path
, objects
[i
]);
793 recursive_flush_changed_properties(con
, subobj_path
);
797 dbus_free_string_array(objects
);
802 * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals
803 * @con: DBus connection
805 * Traverses through all registered objects and sends PropertiesChanged for
808 void wpa_dbus_flush_all_changed_properties(DBusConnection
*con
)
810 recursive_flush_changed_properties(con
, WPAS_DBUS_NEW_PATH
);
815 * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object
816 * @con: DBus connection
817 * @path: path to a DBus object for which PropertiesChanged will be sent.
819 * Iterates over all properties registered with object and for each interface
820 * containing properties marked as changed, sends a PropertiesChanged signal
821 * containing names and new values of properties that have changed.
823 * You need to call this function after wpa_dbus_mark_property_changed()
824 * if you want to send PropertiesChanged signal immediately (i.e., without
825 * waiting timeout to expire). PropertiesChanged signal for an object is sent
826 * automatically short time after first marking property as changed. All
827 * PropertiesChanged signals are sent automatically after responding on DBus
828 * message, so if you marked a property changed as a result of DBus call
829 * (e.g., param setter), you usually do not need to call this function.
831 void wpa_dbus_flush_object_changed_properties(DBusConnection
*con
,
834 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
835 const struct wpa_dbus_property_desc
*dsc
;
838 dbus_connection_get_object_path_data(con
, path
, (void **) &obj_desc
);
841 eloop_cancel_timeout(flush_object_timeout_handler
, con
, obj_desc
);
843 dsc
= obj_desc
->properties
;
844 for (dsc
= obj_desc
->properties
, i
= 0; dsc
&& dsc
->dbus_property
;
846 if (obj_desc
->prop_changed_flags
== NULL
||
847 !obj_desc
->prop_changed_flags
[i
])
849 send_prop_changed_signal(con
, path
, dsc
->dbus_interface
,
855 #define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000
859 * wpa_dbus_mark_property_changed - Mark a property as changed and
860 * @iface: dbus priv struct
861 * @path: path to DBus object which property has changed
862 * @interface: interface containing changed property
863 * @property: property name which has changed
865 * Iterates over all properties registered with an object and marks the one
866 * given in parameters as changed. All parameters registered for an object
867 * within a single interface will be aggregated together and sent in one
868 * PropertiesChanged signal when function
869 * wpa_dbus_flush_object_changed_properties() is called.
871 void wpa_dbus_mark_property_changed(struct wpas_dbus_priv
*iface
,
872 const char *path
, const char *interface
,
873 const char *property
)
875 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
876 const struct wpa_dbus_property_desc
*dsc
;
882 dbus_connection_get_object_path_data(iface
->con
, path
,
883 (void **) &obj_desc
);
885 wpa_printf(MSG_ERROR
, "dbus: wpa_dbus_property_changed: "
886 "could not obtain object's private data: %s", path
);
890 for (dsc
= obj_desc
->properties
; dsc
&& dsc
->dbus_property
; dsc
++, i
++)
891 if (os_strcmp(property
, dsc
->dbus_property
) == 0 &&
892 os_strcmp(interface
, dsc
->dbus_interface
) == 0) {
893 if (obj_desc
->prop_changed_flags
)
894 obj_desc
->prop_changed_flags
[i
] = 1;
898 if (!dsc
|| !dsc
->dbus_property
) {
899 wpa_printf(MSG_ERROR
, "dbus: wpa_dbus_property_changed: "
900 "no property %s in object %s", property
, path
);
904 if (!eloop_is_timeout_registered(flush_object_timeout_handler
,
905 iface
->con
, obj_desc
->path
)) {
906 eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT
,
907 flush_object_timeout_handler
,
908 iface
->con
, obj_desc
);
914 * wpa_dbus_get_object_properties - Put object's properties into dictionary
915 * @iface: dbus priv struct
916 * @path: path to DBus object which properties will be obtained
917 * @interface: interface name which properties will be obtained
918 * @iter: DBus message iter at which to append property dictionary.
920 * Iterates over all properties registered with object and execute getters
921 * of those, which are readable and which interface matches interface
922 * specified as argument. Obtained properties values are stored in
923 * dict_iter dictionary.
925 dbus_bool_t
wpa_dbus_get_object_properties(struct wpas_dbus_priv
*iface
,
927 const char *interface
,
928 DBusMessageIter
*iter
)
930 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
931 DBusMessageIter dict_iter
;
934 dbus_connection_get_object_path_data(iface
->con
, path
,
935 (void **) &obj_desc
);
937 wpa_printf(MSG_ERROR
, "dbus: %s: could not obtain object's "
938 "private data: %s", __func__
, path
);
942 if (!wpa_dbus_dict_open_write(iter
, &dict_iter
)) {
943 wpa_printf(MSG_ERROR
, "dbus: %s: failed to open message dict",
948 dbus_error_init(&error
);
949 if (!fill_dict_with_properties(&dict_iter
, obj_desc
->properties
,
950 interface
, obj_desc
->user_data
,
952 wpa_printf(MSG_ERROR
, "dbus: %s: failed to get object"
953 " properties: (%s) %s", __func__
,
954 dbus_error_is_set(&error
) ? error
.name
: "none",
955 dbus_error_is_set(&error
) ? error
.message
: "none");
956 dbus_error_free(&error
);
960 return wpa_dbus_dict_close_write(iter
, &dict_iter
);
964 * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
965 * @path: The dbus object path
966 * @p2p_persistent_group: indicates whether to parse the path as a P2P
967 * persistent group object
968 * @network: (out) the configured network this object path refers to, if any
969 * @bssid: (out) the scanned bssid this object path refers to, if any
970 * Returns: The object path of the network interface this path refers to
972 * For a given object path, decomposes the object path into object id, network,
973 * and BSSID parts, if those parts exist.
975 char *wpas_dbus_new_decompose_object_path(const char *path
,
976 int p2p_persistent_group
,
980 const unsigned int dev_path_prefix_len
=
981 os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES
"/");
985 /* Be a bit paranoid about path */
986 if (!path
|| os_strncmp(path
, WPAS_DBUS_NEW_PATH_INTERFACES
"/",
987 dev_path_prefix_len
))
990 /* Ensure there's something at the end of the path */
991 if ((path
+ dev_path_prefix_len
)[0] == '\0')
994 obj_path_only
= os_strdup(path
);
995 if (obj_path_only
== NULL
)
998 next_sep
= os_strchr(obj_path_only
+ dev_path_prefix_len
, '/');
999 if (next_sep
!= NULL
) {
1000 const char *net_part
= os_strstr(
1001 next_sep
, p2p_persistent_group
?
1002 WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
"/" :
1003 WPAS_DBUS_NEW_NETWORKS_PART
"/");
1004 const char *bssid_part
= os_strstr(
1005 next_sep
, WPAS_DBUS_NEW_BSSIDS_PART
"/");
1007 if (network
&& net_part
) {
1008 /* Deal with a request for a configured network */
1009 const char *net_name
= net_part
+
1010 os_strlen(p2p_persistent_group
?
1011 WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
1013 WPAS_DBUS_NEW_NETWORKS_PART
"/");
1015 if (os_strlen(net_name
))
1016 *network
= os_strdup(net_name
);
1017 } else if (bssid
&& bssid_part
) {
1018 /* Deal with a request for a scanned BSSID */
1019 const char *bssid_name
= bssid_part
+
1020 os_strlen(WPAS_DBUS_NEW_BSSIDS_PART
"/");
1021 if (os_strlen(bssid_name
))
1022 *bssid
= os_strdup(bssid_name
);
1027 /* Cut off interface object path before "/" */
1031 return obj_path_only
;
1036 * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a
1037 * dbus error structure
1038 * @message: The original request message for which the error is a reply
1039 * @error: The error containing a name and a descriptive error cause
1040 * @fallback_name: A generic error name if @error was not set
1041 * @fallback_string: A generic error string if @error was not set
1042 * Returns: A new D-Bus error message
1044 * Given a DBusMessage structure, creates a new D-Bus error message using
1045 * the error name and string contained in that structure.
1047 DBusMessage
* wpas_dbus_reply_new_from_error(DBusMessage
*message
,
1049 const char *fallback_name
,
1050 const char *fallback_string
)
1052 if (error
&& error
->name
&& error
->message
) {
1053 return dbus_message_new_error(message
, error
->name
,
1056 if (fallback_name
&& fallback_string
) {
1057 return dbus_message_new_error(message
, fallback_name
,