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_new_handlers.h"
19 #include "dbus_dict_helpers.h"
22 static dbus_bool_t
fill_dict_with_properties(
23 DBusMessageIter
*dict_iter
,
24 const struct wpa_dbus_property_desc
*props
,
25 const char *interface
, void *user_data
, DBusError
*error
)
27 DBusMessageIter entry_iter
;
28 const struct wpa_dbus_property_desc
*dsc
;
30 for (dsc
= props
; dsc
&& dsc
->dbus_property
; dsc
++) {
31 /* Only return properties for the requested D-Bus interface */
32 if (os_strncmp(dsc
->dbus_interface
, interface
,
33 WPAS_DBUS_INTERFACE_MAX
) != 0)
36 /* Skip write-only properties */
37 if (dsc
->getter
== NULL
)
40 if (!dbus_message_iter_open_container(dict_iter
,
43 !dbus_message_iter_append_basic(&entry_iter
,
48 /* An error getting a property fails the request entirely */
49 if (!dsc
->getter(dsc
, &entry_iter
, error
, user_data
)) {
51 "dbus: %s dbus_interface=%s dbus_property=%s getter failed",
52 __func__
, dsc
->dbus_interface
,
57 if (!dbus_message_iter_close_container(dict_iter
, &entry_iter
))
64 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
70 * get_all_properties - Responds for GetAll properties calls on object
71 * @message: Message with GetAll call
72 * @interface: interface name which properties will be returned
73 * @property_dsc: list of object's properties
74 * Returns: Message with dict of variants as argument with properties values
76 * Iterates over all properties registered with object and execute getters
77 * of those, which are readable and which interface matches interface
78 * specified as argument. Returned message contains one dict argument
79 * with properties names as keys and theirs values as values.
81 static DBusMessage
* get_all_properties(DBusMessage
*message
, char *interface
,
82 struct wpa_dbus_object_desc
*obj_dsc
)
85 DBusMessageIter iter
, dict_iter
;
88 reply
= dbus_message_new_method_return(message
);
90 return wpas_dbus_error_no_memory(message
);
92 dbus_message_iter_init_append(reply
, &iter
);
93 if (!wpa_dbus_dict_open_write(&iter
, &dict_iter
)) {
94 dbus_message_unref(reply
);
95 return wpas_dbus_error_no_memory(message
);
98 dbus_error_init(&error
);
99 if (!fill_dict_with_properties(&dict_iter
, obj_dsc
->properties
,
100 interface
, obj_dsc
->user_data
, &error
)) {
101 wpa_dbus_dict_close_write(&iter
, &dict_iter
);
102 dbus_message_unref(reply
);
103 reply
= wpas_dbus_reply_new_from_error(
104 message
, &error
, DBUS_ERROR_INVALID_ARGS
,
105 "No readable properties in this interface");
106 dbus_error_free(&error
);
110 if (!wpa_dbus_dict_close_write(&iter
, &dict_iter
)) {
111 dbus_message_unref(reply
);
112 return wpas_dbus_error_no_memory(message
);
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
;
136 ret
= os_snprintf(pos
, blen
, "%s", arg
->type
);
137 if (os_snprintf_error(blen
, ret
))
143 return !os_strncmp(registered_sig
, sig
, MAX_SIG_LEN
);
147 static DBusMessage
* properties_get_all(DBusMessage
*message
, char *interface
,
148 struct wpa_dbus_object_desc
*obj_dsc
)
150 if (os_strcmp(dbus_message_get_signature(message
), "s") != 0)
151 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
154 return get_all_properties(message
, interface
, obj_dsc
);
158 static DBusMessage
* properties_get(DBusMessage
*message
,
159 const struct wpa_dbus_property_desc
*dsc
,
163 DBusMessageIter iter
;
166 if (os_strcmp(dbus_message_get_signature(message
), "ss")) {
167 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
171 if (dsc
->getter
== NULL
) {
172 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
173 "Property is write-only");
176 reply
= dbus_message_new_method_return(message
);
177 dbus_message_iter_init_append(reply
, &iter
);
179 dbus_error_init(&error
);
180 if (dsc
->getter(dsc
, &iter
, &error
, user_data
) == FALSE
) {
181 dbus_message_unref(reply
);
182 reply
= wpas_dbus_reply_new_from_error(
183 message
, &error
, DBUS_ERROR_FAILED
,
184 "Failed to read property");
185 dbus_error_free(&error
);
192 static DBusMessage
* properties_set(DBusMessage
*message
,
193 const struct wpa_dbus_property_desc
*dsc
,
197 DBusMessageIter iter
;
200 if (os_strcmp(dbus_message_get_signature(message
), "ssv")) {
201 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
205 if (dsc
->setter
== NULL
) {
206 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
207 "Property is read-only");
210 dbus_message_iter_init(message
, &iter
);
211 /* Skip the interface name and the property name */
212 dbus_message_iter_next(&iter
);
213 dbus_message_iter_next(&iter
);
215 /* Iter will now point to the property's new value */
216 dbus_error_init(&error
);
217 if (dsc
->setter(dsc
, &iter
, &error
, user_data
) == TRUE
) {
219 reply
= dbus_message_new_method_return(message
);
221 reply
= wpas_dbus_reply_new_from_error(
222 message
, &error
, DBUS_ERROR_FAILED
,
223 "Failed to set property");
224 dbus_error_free(&error
);
232 properties_get_or_set(DBusMessage
*message
, DBusMessageIter
*iter
,
234 struct wpa_dbus_object_desc
*obj_dsc
)
236 const struct wpa_dbus_property_desc
*property_dsc
;
240 method
= dbus_message_get_member(message
);
241 property_dsc
= obj_dsc
->properties
;
243 /* Second argument: property name (DBUS_TYPE_STRING) */
244 if (!dbus_message_iter_next(iter
) ||
245 dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_STRING
) {
246 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
249 dbus_message_iter_get_basic(iter
, &property
);
251 while (property_dsc
&& property_dsc
->dbus_property
) {
252 /* compare property names and
254 if (!os_strncmp(property_dsc
->dbus_property
, property
,
255 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) &&
256 !os_strncmp(property_dsc
->dbus_interface
, interface
,
257 WPAS_DBUS_INTERFACE_MAX
))
262 if (property_dsc
== NULL
|| property_dsc
->dbus_property
== NULL
) {
263 wpa_printf(MSG_DEBUG
, "no property handler for %s.%s on %s",
265 dbus_message_get_path(message
));
266 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
270 if (os_strncmp(WPA_DBUS_PROPERTIES_GET
, method
,
271 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) == 0) {
272 wpa_printf(MSG_MSGDUMP
, "%s: Get(%s)", __func__
, property
);
273 return properties_get(message
, property_dsc
,
277 wpa_printf(MSG_MSGDUMP
, "%s: Set(%s)", __func__
, property
);
278 return properties_set(message
, property_dsc
, obj_dsc
->user_data
);
282 static DBusMessage
* properties_handler(DBusMessage
*message
,
283 struct wpa_dbus_object_desc
*obj_dsc
)
285 DBusMessageIter iter
;
289 method
= dbus_message_get_member(message
);
290 dbus_message_iter_init(message
, &iter
);
292 if (!os_strncmp(WPA_DBUS_PROPERTIES_GET
, method
,
293 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) ||
294 !os_strncmp(WPA_DBUS_PROPERTIES_SET
, method
,
295 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) ||
296 !os_strncmp(WPA_DBUS_PROPERTIES_GETALL
, method
,
297 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
)) {
298 /* First argument: interface name (DBUS_TYPE_STRING) */
299 if (dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
) {
300 return dbus_message_new_error(message
,
301 DBUS_ERROR_INVALID_ARGS
,
305 dbus_message_iter_get_basic(&iter
, &interface
);
307 if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL
, method
,
308 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
)) {
310 return properties_get_all(message
, interface
, obj_dsc
);
313 return properties_get_or_set(message
, &iter
, interface
,
316 return dbus_message_new_error(message
, DBUS_ERROR_UNKNOWN_METHOD
,
321 static DBusMessage
* msg_method_handler(DBusMessage
*message
,
322 struct wpa_dbus_object_desc
*obj_dsc
)
324 const struct wpa_dbus_method_desc
*method_dsc
= obj_dsc
->methods
;
326 const char *msg_interface
;
328 method
= dbus_message_get_member(message
);
329 msg_interface
= dbus_message_get_interface(message
);
331 /* try match call to any registered method */
332 while (method_dsc
&& method_dsc
->dbus_method
) {
333 /* compare method names and interfaces */
334 if (!os_strncmp(method_dsc
->dbus_method
, method
,
335 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) &&
336 !os_strncmp(method_dsc
->dbus_interface
, msg_interface
,
337 WPAS_DBUS_INTERFACE_MAX
))
342 if (method_dsc
== NULL
|| method_dsc
->dbus_method
== NULL
) {
343 wpa_printf(MSG_DEBUG
, "no method handler for %s.%s on %s",
344 msg_interface
, method
,
345 dbus_message_get_path(message
));
346 return dbus_message_new_error(message
,
347 DBUS_ERROR_UNKNOWN_METHOD
, NULL
);
350 if (!is_signature_correct(message
, method_dsc
)) {
351 return dbus_message_new_error(message
, DBUS_ERROR_INVALID_ARGS
,
355 return method_dsc
->method_handler(message
, obj_dsc
->user_data
);
360 * message_handler - Handles incoming DBus messages
361 * @connection: DBus connection on which message was received
362 * @message: Received message
363 * @user_data: pointer to description of object to which message was sent
364 * Returns: Returns information whether message was handled or not
366 * Reads message interface and method name, then checks if they matches one
367 * of the special cases i.e. introspection call or properties get/getall/set
368 * methods and handles it. Else it iterates over registered methods list
369 * and tries to match method's name and interface to those read from message
370 * If appropriate method was found its handler function is called and
371 * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
374 static DBusHandlerResult
message_handler(DBusConnection
*connection
,
375 DBusMessage
*message
, void *user_data
)
377 struct wpa_dbus_object_desc
*obj_dsc
= user_data
;
380 const char *msg_interface
;
383 /* get method, interface and path the message is addressed to */
384 method
= dbus_message_get_member(message
);
385 path
= dbus_message_get_path(message
);
386 msg_interface
= dbus_message_get_interface(message
);
387 if (!method
|| !path
|| !msg_interface
)
388 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
390 wpa_printf(MSG_MSGDUMP
, "dbus: %s.%s (%s) [%s]",
391 msg_interface
, method
, path
,
392 dbus_message_get_signature(message
));
394 /* if message is introspection method call */
395 if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD
, method
,
396 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX
) &&
397 !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE
, msg_interface
,
398 WPAS_DBUS_INTERFACE_MAX
)) {
399 #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
400 reply
= wpa_dbus_introspect(message
, obj_dsc
);
401 #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
402 reply
= dbus_message_new_error(
403 message
, DBUS_ERROR_UNKNOWN_METHOD
,
404 "wpa_supplicant was compiled without introspection support.");
405 #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
406 } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE
, msg_interface
,
407 WPAS_DBUS_INTERFACE_MAX
)) {
408 /* if message is properties method call */
409 reply
= properties_handler(message
, obj_dsc
);
411 reply
= msg_method_handler(message
, obj_dsc
);
414 /* If handler succeed returning NULL, reply empty message */
416 reply
= dbus_message_new_method_return(message
);
418 if (!dbus_message_get_no_reply(message
))
419 dbus_connection_send(connection
, reply
, NULL
);
420 dbus_message_unref(reply
);
423 wpa_dbus_flush_all_changed_properties(connection
);
425 return DBUS_HANDLER_RESULT_HANDLED
;
430 * free_dbus_object_desc - Frees object description data structure
431 * @connection: DBus connection
432 * @obj_dsc: Object description to free
434 * Frees each of properties, methods and signals description lists and
435 * the object description structure itself.
437 void free_dbus_object_desc(struct wpa_dbus_object_desc
*obj_dsc
)
442 /* free handler's argument */
443 if (obj_dsc
->user_data_free_func
)
444 obj_dsc
->user_data_free_func(obj_dsc
->user_data
);
446 os_free(obj_dsc
->path
);
447 os_free(obj_dsc
->prop_changed_flags
);
452 static void free_dbus_object_desc_cb(DBusConnection
*connection
, void *obj_dsc
)
454 free_dbus_object_desc(obj_dsc
);
459 * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
460 * @application_data: Pointer to application specific data structure
461 * @dbus_path: DBus path to interface object
462 * @dbus_service: DBus service name to register with
463 * @messageHandler: a pointer to function which will handle dbus messages
464 * coming on interface
465 * Returns: 0 on success, -1 on failure
467 * Initialize the dbus control interface and start receiving commands from
468 * external programs over the bus.
470 int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv
*iface
,
471 char *dbus_path
, char *dbus_service
,
472 struct wpa_dbus_object_desc
*obj_desc
)
476 DBusObjectPathVTable wpa_vtable
= {
477 &free_dbus_object_desc_cb
, &message_handler
,
478 NULL
, NULL
, NULL
, NULL
481 obj_desc
->connection
= iface
->con
;
482 obj_desc
->path
= os_strdup(dbus_path
);
484 /* Register the message handler for the global dbus interface */
485 if (!dbus_connection_register_object_path(iface
->con
, dbus_path
,
486 &wpa_vtable
, obj_desc
)) {
487 wpa_printf(MSG_ERROR
, "dbus: Could not set up message handler");
491 /* Register our service with the message bus */
492 dbus_error_init(&error
);
493 switch (dbus_bus_request_name(iface
->con
, dbus_service
, 0, &error
)) {
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
,
501 "dbus: Could not request service name: already registered");
504 wpa_printf(MSG_ERROR
,
505 "dbus: Could not request service name: %s %s",
506 error
.name
, error
.message
);
509 dbus_error_free(&error
);
514 wpa_printf(MSG_DEBUG
, "Providing DBus service '%s'.", dbus_service
);
521 * wpa_dbus_register_object_per_iface - Register a new object with dbus
522 * @ctrl_iface: pointer to dbus private data
523 * @path: DBus path to object
524 * @ifname: interface name
525 * @obj_desc: description of object's methods, signals and properties
526 * Returns: 0 on success, -1 on error
528 * Registers a new interface with dbus and assigns it a dbus object path.
530 int wpa_dbus_register_object_per_iface(struct wpas_dbus_priv
*ctrl_iface
,
531 const char *path
, const char *ifname
,
532 struct wpa_dbus_object_desc
*obj_desc
)
536 DBusObjectPathVTable vtable
= {
537 &free_dbus_object_desc_cb
, &message_handler
,
538 NULL
, NULL
, NULL
, NULL
541 /* Do nothing if the control interface is not turned on */
542 if (ctrl_iface
== NULL
)
545 con
= ctrl_iface
->con
;
546 obj_desc
->connection
= con
;
547 obj_desc
->path
= os_strdup(path
);
549 dbus_error_init(&error
);
550 /* Register the message handler for the interface functions */
551 if (!dbus_connection_try_register_object_path(con
, path
, &vtable
,
553 if (os_strcmp(error
.name
, DBUS_ERROR_OBJECT_PATH_IN_USE
) == 0) {
554 wpa_printf(MSG_DEBUG
, "dbus: %s", error
.message
);
556 wpa_printf(MSG_ERROR
,
557 "dbus: Could not set up message handler for interface %s object %s (error: %s message: %s)",
558 ifname
, path
, error
.name
, error
.message
);
560 dbus_error_free(&error
);
564 dbus_error_free(&error
);
569 static void flush_object_timeout_handler(void *eloop_ctx
, void *timeout_ctx
);
573 * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
574 * @ctrl_iface: Pointer to dbus private data
575 * @path: DBus path to object which will be unregistered
576 * Returns: Zero on success and -1 on failure
578 * Unregisters DBus object given by its path
580 int wpa_dbus_unregister_object_per_iface(
581 struct wpas_dbus_priv
*ctrl_iface
, const char *path
)
583 DBusConnection
*con
= ctrl_iface
->con
;
584 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
586 dbus_connection_get_object_path_data(con
, path
, (void **) &obj_desc
);
588 wpa_printf(MSG_ERROR
,
589 "dbus: %s: Could not obtain object's private data: %s",
594 eloop_cancel_timeout(flush_object_timeout_handler
, con
, obj_desc
);
596 if (!dbus_connection_unregister_object_path(con
, path
))
603 static dbus_bool_t
put_changed_properties(
604 const struct wpa_dbus_object_desc
*obj_dsc
, const char *interface
,
605 DBusMessageIter
*dict_iter
, int clear_changed
)
607 DBusMessageIter entry_iter
;
608 const struct wpa_dbus_property_desc
*dsc
;
612 for (dsc
= obj_dsc
->properties
, i
= 0; dsc
&& dsc
->dbus_property
;
614 if (obj_dsc
->prop_changed_flags
== NULL
||
615 !obj_dsc
->prop_changed_flags
[i
])
617 if (os_strcmp(dsc
->dbus_interface
, interface
) != 0)
620 obj_dsc
->prop_changed_flags
[i
] = 0;
622 if (!dbus_message_iter_open_container(dict_iter
,
623 DBUS_TYPE_DICT_ENTRY
,
624 NULL
, &entry_iter
) ||
625 !dbus_message_iter_append_basic(&entry_iter
,
627 &dsc
->dbus_property
))
630 dbus_error_init(&error
);
631 if (!dsc
->getter(dsc
, &entry_iter
, &error
, obj_dsc
->user_data
))
633 if (dbus_error_is_set(&error
)) {
634 wpa_printf(MSG_ERROR
,
635 "dbus: %s: Cannot get new value of property %s: (%s) %s",
636 __func__
, dsc
->dbus_property
,
637 error
.name
, error
.message
);
639 wpa_printf(MSG_ERROR
,
640 "dbus: %s: Cannot get new value of property %s",
641 __func__
, dsc
->dbus_property
);
643 dbus_error_free(&error
);
647 if (!dbus_message_iter_close_container(dict_iter
, &entry_iter
))
655 static void do_send_prop_changed_signal(
656 DBusConnection
*con
, const char *path
, const char *interface
,
657 const struct wpa_dbus_object_desc
*obj_dsc
)
660 DBusMessageIter signal_iter
, dict_iter
;
662 msg
= dbus_message_new_signal(path
, DBUS_INTERFACE_PROPERTIES
,
663 "PropertiesChanged");
667 dbus_message_iter_init_append(msg
, &signal_iter
);
669 if (!dbus_message_iter_append_basic(&signal_iter
, DBUS_TYPE_STRING
,
671 /* Changed properties dict */
672 !dbus_message_iter_open_container(&signal_iter
, DBUS_TYPE_ARRAY
,
673 "{sv}", &dict_iter
) ||
674 !put_changed_properties(obj_dsc
, interface
, &dict_iter
, 0) ||
675 !dbus_message_iter_close_container(&signal_iter
, &dict_iter
) ||
676 /* Invalidated properties array (empty) */
677 !dbus_message_iter_open_container(&signal_iter
, DBUS_TYPE_ARRAY
,
679 !dbus_message_iter_close_container(&signal_iter
, &dict_iter
)) {
680 wpa_printf(MSG_DEBUG
, "dbus: %s: Failed to construct signal",
683 dbus_connection_send(con
, msg
, NULL
);
686 dbus_message_unref(msg
);
690 static void do_send_deprecated_prop_changed_signal(
691 DBusConnection
*con
, const char *path
, const char *interface
,
692 const struct wpa_dbus_object_desc
*obj_dsc
)
695 DBusMessageIter signal_iter
, dict_iter
;
697 msg
= dbus_message_new_signal(path
, interface
, "PropertiesChanged");
701 dbus_message_iter_init_append(msg
, &signal_iter
);
703 if (!dbus_message_iter_open_container(&signal_iter
, DBUS_TYPE_ARRAY
,
704 "{sv}", &dict_iter
) ||
705 !put_changed_properties(obj_dsc
, interface
, &dict_iter
, 1) ||
706 !dbus_message_iter_close_container(&signal_iter
, &dict_iter
)) {
707 wpa_printf(MSG_DEBUG
, "dbus: %s: Failed to construct signal",
710 dbus_connection_send(con
, msg
, NULL
);
713 dbus_message_unref(msg
);
717 static void send_prop_changed_signal(
718 DBusConnection
*con
, const char *path
, const char *interface
,
719 const struct wpa_dbus_object_desc
*obj_dsc
)
722 * First, send property change notification on the standardized
723 * org.freedesktop.DBus.Properties interface. This call will not
724 * clear the property change bits, so that they are preserved for
725 * the call that follows.
727 do_send_prop_changed_signal(con
, path
, interface
, obj_dsc
);
730 * Now send PropertiesChanged on our own interface for backwards
731 * compatibility. This is deprecated and will be removed in a future
734 do_send_deprecated_prop_changed_signal(con
, path
, interface
, obj_dsc
);
736 /* Property change bits have now been cleared. */
740 static void flush_object_timeout_handler(void *eloop_ctx
, void *timeout_ctx
)
742 DBusConnection
*con
= eloop_ctx
;
743 struct wpa_dbus_object_desc
*obj_desc
= timeout_ctx
;
745 wpa_printf(MSG_MSGDUMP
,
746 "dbus: %s: Timeout - sending changed properties of object %s",
747 __func__
, obj_desc
->path
);
748 wpa_dbus_flush_object_changed_properties(con
, obj_desc
->path
);
752 static void recursive_flush_changed_properties(DBusConnection
*con
,
755 char **objects
= NULL
;
756 char subobj_path
[WPAS_DBUS_OBJECT_PATH_MAX
];
759 wpa_dbus_flush_object_changed_properties(con
, path
);
761 if (!dbus_connection_list_registered(con
, path
, &objects
))
764 for (i
= 0; objects
[i
]; i
++) {
765 os_snprintf(subobj_path
, WPAS_DBUS_OBJECT_PATH_MAX
,
766 "%s/%s", path
, objects
[i
]);
767 recursive_flush_changed_properties(con
, subobj_path
);
771 dbus_free_string_array(objects
);
776 * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals
777 * @con: DBus connection
779 * Traverses through all registered objects and sends PropertiesChanged for
782 void wpa_dbus_flush_all_changed_properties(DBusConnection
*con
)
784 recursive_flush_changed_properties(con
, WPAS_DBUS_NEW_PATH
);
789 * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object
790 * @con: DBus connection
791 * @path: path to a DBus object for which PropertiesChanged will be sent.
793 * Iterates over all properties registered with object and for each interface
794 * containing properties marked as changed, sends a PropertiesChanged signal
795 * containing names and new values of properties that have changed.
797 * You need to call this function after wpa_dbus_mark_property_changed()
798 * if you want to send PropertiesChanged signal immediately (i.e., without
799 * waiting timeout to expire). PropertiesChanged signal for an object is sent
800 * automatically short time after first marking property as changed. All
801 * PropertiesChanged signals are sent automatically after responding on DBus
802 * message, so if you marked a property changed as a result of DBus call
803 * (e.g., param setter), you usually do not need to call this function.
805 void wpa_dbus_flush_object_changed_properties(DBusConnection
*con
,
808 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
809 const struct wpa_dbus_property_desc
*dsc
;
812 dbus_connection_get_object_path_data(con
, path
, (void **) &obj_desc
);
815 eloop_cancel_timeout(flush_object_timeout_handler
, con
, obj_desc
);
817 for (dsc
= obj_desc
->properties
, i
= 0; dsc
&& dsc
->dbus_property
;
819 if (obj_desc
->prop_changed_flags
== NULL
||
820 !obj_desc
->prop_changed_flags
[i
])
822 send_prop_changed_signal(con
, path
, dsc
->dbus_interface
,
828 #define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000
832 * wpa_dbus_mark_property_changed - Mark a property as changed and
833 * @iface: dbus priv struct
834 * @path: path to DBus object which property has changed
835 * @interface: interface containing changed property
836 * @property: property name which has changed
838 * Iterates over all properties registered with an object and marks the one
839 * given in parameters as changed. All parameters registered for an object
840 * within a single interface will be aggregated together and sent in one
841 * PropertiesChanged signal when function
842 * wpa_dbus_flush_object_changed_properties() is called.
844 void wpa_dbus_mark_property_changed(struct wpas_dbus_priv
*iface
,
845 const char *path
, const char *interface
,
846 const char *property
)
848 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
849 const struct wpa_dbus_property_desc
*dsc
;
855 dbus_connection_get_object_path_data(iface
->con
, path
,
856 (void **) &obj_desc
);
858 wpa_printf(MSG_ERROR
,
859 "dbus: wpa_dbus_property_changed: could not obtain object's private data: %s",
864 for (dsc
= obj_desc
->properties
; dsc
&& dsc
->dbus_property
; dsc
++, i
++)
865 if (os_strcmp(property
, dsc
->dbus_property
) == 0 &&
866 os_strcmp(interface
, dsc
->dbus_interface
) == 0) {
867 if (obj_desc
->prop_changed_flags
)
868 obj_desc
->prop_changed_flags
[i
] = 1;
872 if (!dsc
|| !dsc
->dbus_property
) {
873 wpa_printf(MSG_ERROR
,
874 "dbus: wpa_dbus_property_changed: no property %s in object %s",
879 if (!eloop_is_timeout_registered(flush_object_timeout_handler
,
880 iface
->con
, obj_desc
)) {
881 eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT
,
882 flush_object_timeout_handler
,
883 iface
->con
, obj_desc
);
889 * wpa_dbus_get_object_properties - Put object's properties into dictionary
890 * @iface: dbus priv struct
891 * @path: path to DBus object which properties will be obtained
892 * @interface: interface name which properties will be obtained
893 * @iter: DBus message iter at which to append property dictionary.
895 * Iterates over all properties registered with object and execute getters
896 * of those, which are readable and which interface matches interface
897 * specified as argument. Obtained properties values are stored in
898 * dict_iter dictionary.
900 dbus_bool_t
wpa_dbus_get_object_properties(struct wpas_dbus_priv
*iface
,
902 const char *interface
,
903 DBusMessageIter
*iter
)
905 struct wpa_dbus_object_desc
*obj_desc
= NULL
;
906 DBusMessageIter dict_iter
;
909 dbus_connection_get_object_path_data(iface
->con
, path
,
910 (void **) &obj_desc
);
912 wpa_printf(MSG_ERROR
,
913 "dbus: %s: could not obtain object's private data: %s",
918 if (!wpa_dbus_dict_open_write(iter
, &dict_iter
)) {
919 wpa_printf(MSG_ERROR
, "dbus: %s: failed to open message dict",
924 dbus_error_init(&error
);
925 if (!fill_dict_with_properties(&dict_iter
, obj_desc
->properties
,
926 interface
, obj_desc
->user_data
,
928 wpa_printf(MSG_ERROR
,
929 "dbus: %s: failed to get object properties: (%s) %s",
931 dbus_error_is_set(&error
) ? error
.name
: "none",
932 dbus_error_is_set(&error
) ? error
.message
: "none");
933 dbus_error_free(&error
);
934 wpa_dbus_dict_close_write(iter
, &dict_iter
);
938 return wpa_dbus_dict_close_write(iter
, &dict_iter
);
942 * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
943 * @path: The dbus object path
944 * @sep: Separating part (e.g., "Networks" or "PersistentGroups")
945 * @item: (out) The part following the specified separator, if any
946 * Returns: The object path of the interface this path refers to
948 * For a given object path, decomposes the object path into object id and
949 * requested part, if those parts exist. The caller is responsible for freeing
950 * the returned value. The *item pointer points to that allocated value and must
951 * not be freed separately.
953 * As an example, path = "/fi/w1/wpa_supplicant1/Interfaces/1/Networks/0" and
954 * sep = "Networks" would result in "/fi/w1/wpa_supplicant1/Interfaces/1"
955 * getting returned and *items set to point to "0".
957 char * wpas_dbus_new_decompose_object_path(const char *path
, const char *sep
,
960 const unsigned int dev_path_prefix_len
=
961 os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES
"/");
968 /* Verify that this starts with our interface prefix */
969 if (os_strncmp(path
, WPAS_DBUS_NEW_PATH_INTERFACES
"/",
970 dev_path_prefix_len
) != 0)
971 return NULL
; /* not our path */
973 /* Ensure there's something at the end of the path */
974 if ((path
+ dev_path_prefix_len
)[0] == '\0')
977 obj_path_only
= os_strdup(path
);
978 if (obj_path_only
== NULL
)
981 pos
= obj_path_only
+ dev_path_prefix_len
;
982 pos
= os_strchr(pos
, '/');
984 return obj_path_only
; /* no next item on the path */
986 /* Separate network interface prefix from the path */
989 sep_len
= os_strlen(sep
);
990 if (os_strncmp(pos
, sep
, sep_len
) != 0 || pos
[sep_len
] != '/')
991 return obj_path_only
; /* no match */
993 /* return a pointer to the requested item */
994 *item
= pos
+ sep_len
+ 1;
995 return obj_path_only
;
1000 * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a
1001 * dbus error structure
1002 * @message: The original request message for which the error is a reply
1003 * @error: The error containing a name and a descriptive error cause
1004 * @fallback_name: A generic error name if @error was not set
1005 * @fallback_string: A generic error string if @error was not set
1006 * Returns: A new D-Bus error message
1008 * Given a DBusMessage structure, creates a new D-Bus error message using
1009 * the error name and string contained in that structure.
1011 DBusMessage
* wpas_dbus_reply_new_from_error(DBusMessage
*message
,
1013 const char *fallback_name
,
1014 const char *fallback_string
)
1016 if (error
&& error
->name
&& error
->message
) {
1017 return dbus_message_new_error(message
, error
->name
,
1020 if (fallback_name
&& fallback_string
) {
1021 return dbus_message_new_error(message
, fallback_name
,