dbus: Replace StateChanged with PropertiesChanged signal
[libeap.git] / wpa_supplicant / dbus / dbus_new_helpers.c
1 /*
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>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
16 #include "includes.h"
17
18 #include "common.h"
19 #include "dbus_common.h"
20 #include "dbus_common_i.h"
21 #include "dbus_new_helpers.h"
22
23
24 /**
25  * recursive_iter_copy - Reads arguments from one iterator and
26  * writes to another recursively
27  * @from: iterator to read from
28  * @to: iterator to write to
29  *
30  * Copies one iterator's elements to another. If any element in
31  * iterator is of container type, its content is copied recursively
32  */
33 static void recursive_iter_copy(DBusMessageIter *from, DBusMessageIter *to)
34 {
35
36         char *subtype = NULL;
37         int type;
38
39         /* iterate over iterator to copy */
40         while ((type = dbus_message_iter_get_arg_type(from)) !=
41                DBUS_TYPE_INVALID) {
42
43                 /* simply copy basic type entries */
44                 if (dbus_type_is_basic(type)) {
45                         if (dbus_type_is_fixed(type)) {
46                                 /*
47                                  * According to DBus documentation all
48                                  * fixed-length types are guaranteed to fit
49                                  * 8 bytes
50                                  */
51                                 dbus_uint64_t v;
52                                 dbus_message_iter_get_basic(from, &v);
53                                 dbus_message_iter_append_basic(to, type, &v);
54                         } else {
55                                 char *v;
56                                 dbus_message_iter_get_basic(from, &v);
57                                 dbus_message_iter_append_basic(to, type, &v);
58                         }
59                 } else {
60                         /* recursively copy container type entries */
61                         DBusMessageIter write_subiter, read_subiter;
62
63                         dbus_message_iter_recurse(from, &read_subiter);
64
65                         if (type == DBUS_TYPE_VARIANT ||
66                             type == DBUS_TYPE_ARRAY) {
67                                 subtype = dbus_message_iter_get_signature(
68                                         &read_subiter);
69                         }
70
71                         dbus_message_iter_open_container(to, type, subtype,
72                                                          &write_subiter);
73
74                         recursive_iter_copy(&read_subiter, &write_subiter);
75
76                         dbus_message_iter_close_container(to, &write_subiter);
77                         if (subtype)
78                                 dbus_free(subtype);
79                 }
80
81                 dbus_message_iter_next(from);
82         }
83 }
84
85
86 static unsigned int fill_dict_with_properties(
87         DBusMessageIter *dict_iter, const struct wpa_dbus_property_desc *props,
88         const char *interface, const void *user_data)
89 {
90         DBusMessage *reply;
91         DBusMessageIter entry_iter, ret_iter;
92         unsigned int counter = 0;
93         const struct wpa_dbus_property_desc *dsc;
94
95         for (dsc = props; dsc && dsc->dbus_property; dsc++) {
96                 if (!os_strncmp(dsc->dbus_interface, interface,
97                                 WPAS_DBUS_INTERFACE_MAX) &&
98                     dsc->access != W && dsc->getter) {
99                         reply = dsc->getter(NULL, user_data);
100                         if (!reply)
101                                 continue;
102
103                         if (dbus_message_get_type(reply) ==
104                             DBUS_MESSAGE_TYPE_ERROR) {
105                                 dbus_message_unref(reply);
106                                 continue;
107                         }
108
109                         dbus_message_iter_init(reply, &ret_iter);
110
111                         dbus_message_iter_open_container(dict_iter,
112                                                          DBUS_TYPE_DICT_ENTRY,
113                                                          NULL, &entry_iter);
114                         dbus_message_iter_append_basic(
115                                 &entry_iter, DBUS_TYPE_STRING,
116                                 &dsc->dbus_property);
117
118                         recursive_iter_copy(&ret_iter, &entry_iter);
119
120                         dbus_message_iter_close_container(dict_iter,
121                                                           &entry_iter);
122                         dbus_message_unref(reply);
123                         counter++;
124                 }
125         }
126
127         return counter;
128 }
129
130
131 /**
132  * get_all_properties - Responds for GetAll properties calls on object
133  * @message: Message with GetAll call
134  * @interface: interface name which properties will be returned
135  * @property_dsc: list of object's properties
136  * Returns: Message with dict of variants as argument with properties values
137  *
138  * Iterates over all properties registered with object and execute getters
139  * of those, which are readable and which interface matches interface
140  * specified as argument. Returned message contains one dict argument
141  * with properties names as keys and theirs values as values.
142  */
143 static DBusMessage * get_all_properties(
144         DBusMessage *message, char *interface,
145         struct wpa_dbus_object_desc *obj_dsc)
146 {
147         /* Create and initialize the return message */
148         DBusMessage *reply = dbus_message_new_method_return(message);
149         DBusMessageIter iter, dict_iter;
150         int props_num;
151
152         dbus_message_iter_init_append(reply, &iter);
153
154         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
155                                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
156                                          DBUS_TYPE_STRING_AS_STRING
157                                          DBUS_TYPE_VARIANT_AS_STRING
158                                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
159                                          &dict_iter);
160
161         props_num = fill_dict_with_properties(&dict_iter, obj_dsc->properties,
162                                               interface, obj_dsc->user_data);
163
164         dbus_message_iter_close_container(&iter, &dict_iter);
165
166         if (props_num == 0) {
167                 dbus_message_unref(reply);
168                 reply = dbus_message_new_error(message,
169                                                DBUS_ERROR_INVALID_ARGS,
170                                                "No readable properties in "
171                                                "this interface");
172         }
173
174         return reply;
175 }
176
177
178 static int is_signature_correct(DBusMessage *message,
179                                 const struct wpa_dbus_method_desc *method_dsc)
180 {
181         /* According to DBus documentation max length of signature is 255 */
182 #define MAX_SIG_LEN 256
183         char registered_sig[MAX_SIG_LEN], *pos;
184         const char *sig = dbus_message_get_signature(message);
185         int ret;
186         const struct wpa_dbus_argument *arg;
187
188         pos = registered_sig;
189         *pos = '\0';
190
191         for (arg = method_dsc->args; arg && arg->name; arg++) {
192                 if (arg->dir == ARG_IN) {
193                         size_t blen = registered_sig + MAX_SIG_LEN - pos;
194                         ret = os_snprintf(pos, blen, "%s", arg->type);
195                         if (ret < 0 || (size_t) ret >= blen)
196                                 return 0;
197                         pos += ret;
198                 }
199         }
200
201         return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
202 }
203
204
205 static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
206                                         struct wpa_dbus_object_desc *obj_dsc)
207 {
208         if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
209                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
210                                               NULL);
211
212         return get_all_properties(message, interface, obj_dsc);
213 }
214
215
216 static DBusMessage * properties_get(DBusMessage *message,
217                                     const struct wpa_dbus_property_desc *dsc,
218                                     void *user_data)
219 {
220         if (os_strcmp(dbus_message_get_signature(message), "ss"))
221                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
222                                               NULL);
223
224         if (dsc->access != W && dsc->getter)
225                 return dsc->getter(message, user_data);
226
227         return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
228                                       "Property is write-only");
229 }
230
231
232 static DBusMessage * properties_set(DBusMessage *message,
233                                     const struct wpa_dbus_property_desc *dsc,
234                                     void *user_data)
235 {
236         if (os_strcmp(dbus_message_get_signature(message), "ssv"))
237                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
238                                               NULL);
239
240         if (dsc->access != R && dsc->setter)
241                 return dsc->setter(message, user_data);
242
243         return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
244                                       "Property is read-only");
245 }
246
247
248 static DBusMessage *
249 properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
250                       char *interface,
251                       struct wpa_dbus_object_desc *obj_dsc)
252 {
253         const struct wpa_dbus_property_desc *property_dsc;
254         char *property;
255         const char *method;
256
257         method = dbus_message_get_member(message);
258         property_dsc = obj_dsc->properties;
259
260         /* Second argument: property name (DBUS_TYPE_STRING) */
261         if (!dbus_message_iter_next(iter) ||
262             dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
263                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
264                                               NULL);
265         }
266         dbus_message_iter_get_basic(iter, &property);
267
268         while (property_dsc && property_dsc->dbus_property) {
269                 /* compare property names and
270                  * interfaces */
271                 if (!os_strncmp(property_dsc->dbus_property, property,
272                                 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
273                     !os_strncmp(property_dsc->dbus_interface, interface,
274                                 WPAS_DBUS_INTERFACE_MAX))
275                         break;
276
277                 property_dsc++;
278         }
279         if (property_dsc == NULL || property_dsc->dbus_property == NULL) {
280                 wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
281                            interface, property,
282                            dbus_message_get_path(message));
283                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
284                                               "No such property");
285         }
286
287         if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
288                        WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
289                 return properties_get(message, property_dsc,
290                                       obj_dsc->user_data);
291
292         return properties_set(message, property_dsc, obj_dsc->user_data);
293 }
294
295
296 static DBusMessage * properties_handler(DBusMessage *message,
297                                         struct wpa_dbus_object_desc *obj_dsc)
298 {
299         DBusMessageIter iter;
300         char *interface;
301         const char *method;
302
303         method = dbus_message_get_member(message);
304         dbus_message_iter_init(message, &iter);
305
306         if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
307                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
308             !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
309                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
310             !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
311                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
312                 /* First argument: interface name (DBUS_TYPE_STRING) */
313                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
314                 {
315                         return dbus_message_new_error(message,
316                                                       DBUS_ERROR_INVALID_ARGS,
317                                                       NULL);
318                 }
319
320                 dbus_message_iter_get_basic(&iter, &interface);
321
322                 if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
323                                 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
324                         /* GetAll */
325                         return properties_get_all(message, interface, obj_dsc);
326                 }
327                 /* Get or Set */
328                 return properties_get_or_set(message, &iter, interface,
329                                              obj_dsc);
330         }
331         return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
332                                       NULL);
333 }
334
335
336 static DBusMessage * msg_method_handler(DBusMessage *message,
337                                         struct wpa_dbus_object_desc *obj_dsc)
338 {
339         const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
340         const char *method;
341         const char *msg_interface;
342
343         method = dbus_message_get_member(message);
344         msg_interface = dbus_message_get_interface(message);
345
346         /* try match call to any registered method */
347         while (method_dsc && method_dsc->dbus_method) {
348                 /* compare method names and interfaces */
349                 if (!os_strncmp(method_dsc->dbus_method, method,
350                                 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
351                     !os_strncmp(method_dsc->dbus_interface, msg_interface,
352                                 WPAS_DBUS_INTERFACE_MAX))
353                         break;
354
355                 method_dsc++;
356         }
357         if (method_dsc == NULL || method_dsc->dbus_method == NULL) {
358                 wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
359                            msg_interface, method,
360                            dbus_message_get_path(message));
361                 return dbus_message_new_error(message,
362                                               DBUS_ERROR_UNKNOWN_METHOD, NULL);
363         }
364
365         if (!is_signature_correct(message, method_dsc)) {
366                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
367                                               NULL);
368         }
369
370         return method_dsc->method_handler(message,
371                                           obj_dsc->user_data);
372 }
373
374
375 /**
376  * message_handler - Handles incoming DBus messages
377  * @connection: DBus connection on which message was received
378  * @message: Received message
379  * @user_data: pointer to description of object to which message was sent
380  * Returns: Returns information whether message was handled or not
381  *
382  * Reads message interface and method name, then checks if they matches one
383  * of the special cases i.e. introspection call or properties get/getall/set
384  * methods and handles it. Else it iterates over registered methods list
385  * and tries to match method's name and interface to those read from message
386  * If appropriate method was found its handler function is called and
387  * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
388  * will be sent.
389  */
390 static DBusHandlerResult message_handler(DBusConnection *connection,
391                                          DBusMessage *message, void *user_data)
392 {
393         struct wpa_dbus_object_desc *obj_dsc = user_data;
394         const char *method;
395         const char *path;
396         const char *msg_interface;
397         DBusMessage *reply;
398
399         /* get method, interface and path the message is addressed to */
400         method = dbus_message_get_member(message);
401         path = dbus_message_get_path(message);
402         msg_interface = dbus_message_get_interface(message);
403         if (!method || !path || !msg_interface)
404                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
405
406         wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
407                    msg_interface, method, path);
408
409         /* if message is introspection method call */
410         if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
411                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
412             !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
413                         WPAS_DBUS_INTERFACE_MAX)) {
414 #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
415                 reply = wpa_dbus_introspect(message, obj_dsc);
416 #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
417                 reply = dbus_message_new_error(
418                         message, DBUS_ERROR_UNKNOWN_METHOD,
419                         "wpa_supplicant was compiled without "
420                         "introspection support.");
421 #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
422         } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
423                              WPAS_DBUS_INTERFACE_MAX)) {
424                 /* if message is properties method call */
425                 reply = properties_handler(message, obj_dsc);
426         } else {
427                 reply = msg_method_handler(message, obj_dsc);
428         }
429
430         /* If handler succeed returning NULL, reply empty message */
431         if (!reply)
432                 reply = dbus_message_new_method_return(message);
433         if (reply) {
434                 if (!dbus_message_get_no_reply(message))
435                         dbus_connection_send(connection, reply, NULL);
436                 dbus_message_unref(reply);
437         }
438         return DBUS_HANDLER_RESULT_HANDLED;
439 }
440
441
442 /**
443  * free_dbus_object_desc - Frees object description data structure
444  * @connection: DBus connection
445  * @obj_dsc: Object description to free
446  *
447  * Frees each of properties, methods and signals description lists and
448  * the object description structure itself.
449  */
450 void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
451 {
452         if (!obj_dsc)
453                 return;
454
455         /* free handler's argument */
456         if (obj_dsc->user_data_free_func)
457                 obj_dsc->user_data_free_func(obj_dsc->user_data);
458
459         os_free(obj_dsc);
460 }
461
462
463 static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
464 {
465         free_dbus_object_desc(obj_dsc);
466 }
467
468 /**
469  * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
470  * @application_data: Pointer to application specific data structure
471  * @dbus_path: DBus path to interface object
472  * @dbus_service: DBus service name to register with
473  * @messageHandler: a pointer to function which will handle dbus messages
474  * coming on interface
475  * Returns: 0 on success, -1 on failure
476  *
477  * Initialize the dbus control interface and start receiving commands from
478  * external programs over the bus.
479  */
480 int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
481                              char *dbus_path, char *dbus_service,
482                              struct wpa_dbus_object_desc *obj_desc)
483 {
484         DBusError error;
485         int ret = -1;
486         DBusObjectPathVTable wpa_vtable = {
487                 &free_dbus_object_desc_cb, &message_handler,
488                 NULL, NULL, NULL, NULL
489         };
490
491         obj_desc->connection = iface->con;
492
493         /* Register the message handler for the global dbus interface */
494         if (!dbus_connection_register_object_path(iface->con,
495                                                   dbus_path, &wpa_vtable,
496                                                   obj_desc)) {
497                 wpa_printf(MSG_ERROR, "dbus: Could not set up message "
498                            "handler");
499                 return -1;
500         }
501
502         /* Register our service with the message bus */
503         dbus_error_init(&error);
504         switch (dbus_bus_request_name(iface->con, dbus_service,
505                                       0, &error)) {
506         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
507                 ret = 0;
508                 break;
509         case DBUS_REQUEST_NAME_REPLY_EXISTS:
510         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
511         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
512                 wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
513                            "already registered");
514                 break;
515         default:
516                 wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
517                            "%s %s", error.name, error.message);
518                 break;
519         }
520         dbus_error_free(&error);
521
522         if (ret != 0)
523                 return -1;
524
525         wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
526
527         return 0;
528 }
529
530
531 /**
532  * wpa_dbus_register_object_per_iface - Register a new object with dbus
533  * @ctrl_iface: pointer to dbus private data
534  * @path: DBus path to object
535  * @ifname: interface name
536  * @obj_desc: description of object's methods, signals and properties
537  * Returns: 0 on success, -1 on error
538  *
539  * Registers a new interface with dbus and assigns it a dbus object path.
540  */
541 int wpa_dbus_register_object_per_iface(
542         struct wpas_dbus_priv *ctrl_iface,
543         const char *path, const char *ifname,
544         struct wpa_dbus_object_desc *obj_desc)
545 {
546         DBusConnection *con;
547
548         DBusObjectPathVTable vtable = {
549                 &free_dbus_object_desc_cb, &message_handler,
550                 NULL, NULL, NULL, NULL
551         };
552
553         /* Do nothing if the control interface is not turned on */
554         if (ctrl_iface == NULL)
555                 return 0;
556
557         con = ctrl_iface->con;
558         obj_desc->connection = con;
559
560         /* Register the message handler for the interface functions */
561         if (!dbus_connection_register_object_path(con, path, &vtable,
562                                                   obj_desc)) {
563                 wpa_printf(MSG_ERROR, "dbus: Could not set up message "
564                            "handler for interface %s object %s", ifname, path);
565                 return -1;
566         }
567
568         return 0;
569 }
570
571
572 /**
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
577  *
578  * Unregisters DBus object given by its path
579  */
580 int wpa_dbus_unregister_object_per_iface(
581         struct wpas_dbus_priv *ctrl_iface, const char *path)
582 {
583         DBusConnection *con = ctrl_iface->con;
584         if (!dbus_connection_unregister_object_path(con, path))
585                 return -1;
586
587         return 0;
588 }
589
590
591 /**
592  * wpas_dbus_signal_network_added - Send a property changed signal
593  * @iface: dbus priv struct
594  * @property_getter: propperty getter used to fetch new property value
595  * @getter_arg: argument passed to property getter
596  * @path: path to object which property has changed
597  * @interface_name: signal and property interface
598  * @property_name: name of property which has changed
599  *
600  * Notify listeners about changing value of some property. Signal
601  * contains property name and its value fetched using given property
602  * getter.
603  */
604 void wpa_dbus_signal_property_changed(struct wpas_dbus_priv *iface,
605                                       WPADBusPropertyAccessor property_getter,
606                                       void *getter_arg,
607                                       const char *path,
608                                       const char *interface_name,
609                                       const char *property_name)
610 {
611
612         DBusConnection *connection;
613         DBusMessage *msg, *getter_reply;
614         DBusMessageIter prop_iter, signal_iter, dict_iter, entry_iter;
615
616         if (!iface)
617                 return;
618         connection = iface->con;
619
620         if (!property_getter || !path || !interface_name || !property_name) {
621                 wpa_printf(MSG_ERROR, "dbus: %s: A parameter not specified",
622                            __func__);
623                 return;
624         }
625
626         getter_reply = property_getter(NULL, getter_arg);
627         if (!getter_reply ||
628             dbus_message_get_type(getter_reply) == DBUS_MESSAGE_TYPE_ERROR) {
629                 wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value of "
630                            "property %s", __func__, property_name);
631                 return;
632         }
633
634         msg = dbus_message_new_signal(path, interface_name,
635                                       "PropertiesChanged");
636         if (msg == NULL) {
637                 dbus_message_unref(getter_reply);
638                 return;
639         }
640
641         dbus_message_iter_init(getter_reply, &prop_iter);
642         dbus_message_iter_init_append(msg, &signal_iter);
643
644         if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
645                                               "{sv}", &dict_iter) ||
646             !dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY,
647                                               NULL, &entry_iter) ||
648             !dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING,
649                                             &property_name))
650                 goto err;
651
652         recursive_iter_copy(&prop_iter, &entry_iter);
653
654         if (!dbus_message_iter_close_container(&dict_iter, &entry_iter) ||
655             !dbus_message_iter_close_container(&signal_iter, &dict_iter))
656                 goto err;
657
658         dbus_connection_send(connection, msg, NULL);
659
660 out:
661         dbus_message_unref(getter_reply);
662         dbus_message_unref(msg);
663         return;
664
665 err:
666         wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
667                    __func__);
668         goto out;
669 }
670
671
672 /**
673  * wpa_dbus_get_object_properties - Put object's properties into dictionary
674  * @iface: dbus priv struct
675  * @path: path to DBus object which properties will be obtained
676  * @interface: interface name which properties will be obtained
677  * @dict_iter: correct, open DBus dictionary iterator.
678  *
679  * Iterates over all properties registered with object and execute getters
680  * of those, which are readable and which interface matches interface
681  * specified as argument. Obtained properties values are stored in
682  * dict_iter dictionary.
683  */
684 void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
685                                     const char *path, const char *interface,
686                                     DBusMessageIter *dict_iter)
687 {
688         struct wpa_dbus_object_desc *obj_desc = NULL;
689
690         dbus_connection_get_object_path_data(iface->con, path,
691                                              (void **) &obj_desc);
692         if (!obj_desc) {
693                 wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
694                            "could not obtain object's private data: %s", path);
695                 return;
696         }
697
698         fill_dict_with_properties(dict_iter, obj_desc->properties,
699                                   interface, obj_desc->user_data);
700 }