5de32010790243bb248d931c49d662331afcaa4e
[mech_eap.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, 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         struct wpa_dbus_property_desc *property_dsc;
94
95         for (property_dsc = props; property_dsc;
96              property_dsc = property_dsc->next) {
97                 if (!os_strncmp(property_dsc->dbus_interface, interface,
98                                 WPAS_DBUS_INTERFACE_MAX) &&
99                     property_dsc->access != W && property_dsc->getter) {
100                         reply = property_dsc->getter(NULL, user_data);
101                         if (!reply)
102                                 continue;
103
104                         if (dbus_message_get_type(reply) ==
105                             DBUS_MESSAGE_TYPE_ERROR) {
106                                 dbus_message_unref(reply);
107                                 continue;
108                         }
109
110                         dbus_message_iter_init(reply, &ret_iter);
111
112                         dbus_message_iter_open_container(dict_iter,
113                                                          DBUS_TYPE_DICT_ENTRY,
114                                                          NULL, &entry_iter);
115                         dbus_message_iter_append_basic(
116                                 &entry_iter, DBUS_TYPE_STRING,
117                                 &(property_dsc->dbus_property));
118
119                         recursive_iter_copy(&ret_iter, &entry_iter);
120
121                         dbus_message_iter_close_container(dict_iter,
122                                                           &entry_iter);
123                         dbus_message_unref(reply);
124                         counter++;
125                 }
126         }
127
128         return counter;
129 }
130
131
132 /**
133  * get_all_properties - Responds for GetAll properties calls on object
134  * @message: Message with GetAll call
135  * @interface: interface name which properties will be returned
136  * @property_dsc: list of object's properties
137  * Returns: Message with dict of variants as argument with properties values
138  *
139  * Iterates over all properties registered with object and execute getters
140  * of those, which are readable and which interface matches interface
141  * specified as argument. Returned message contains one dict argument
142  * with properties names as keys and theirs values as values.
143  */
144 static DBusMessage * get_all_properties(
145         DBusMessage *message, char *interface,
146         struct wpa_dbus_object_desc *obj_dsc)
147 {
148         /* Create and initialize the return message */
149         DBusMessage *reply = dbus_message_new_method_return(message);
150         DBusMessageIter iter, dict_iter;
151         int props_num;
152
153         dbus_message_iter_init_append(reply, &iter);
154
155         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
156                                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
157                                          DBUS_TYPE_STRING_AS_STRING
158                                          DBUS_TYPE_VARIANT_AS_STRING
159                                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
160                                          &dict_iter);
161
162         props_num = fill_dict_with_properties(&dict_iter,obj_dsc->properties,
163                                               interface, obj_dsc->user_data);
164
165         dbus_message_iter_close_container(&iter, &dict_iter);
166
167         if (props_num == 0) {
168                 dbus_message_unref(reply);
169                 reply = dbus_message_new_error(message,
170                                                DBUS_ERROR_INVALID_ARGS,
171                                                "No readable properties in "
172                                                "this interface");
173         }
174
175         return reply;
176 }
177
178
179 static int is_signature_correct(DBusMessage *message,
180                                 struct wpa_dbus_method_desc *method_dsc)
181 {
182         /* According to DBus documentation max length of signature is 255 */
183 #define MAX_SIG_LEN 256
184         char registered_sig[MAX_SIG_LEN], *pos;
185         const char *sig = dbus_message_get_signature(message);
186         int i, ret;
187
188         pos = registered_sig;
189         *pos = '\0';
190
191         for (i = 0; i < method_dsc->args_num; i++) {
192                 struct wpa_dbus_argument arg = method_dsc->args[i];
193                 if (arg.dir == ARG_IN) {
194                         size_t blen = registered_sig + MAX_SIG_LEN - pos;
195                         ret = os_snprintf(pos, blen, "%s", arg.type);
196                         if (ret < 0 || (size_t) ret >= blen)
197                                 return 0;
198                         pos += ret;
199                 }
200         }
201
202         return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
203 }
204
205
206 static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
207                                         struct wpa_dbus_object_desc *obj_dsc)
208 {
209         if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
210                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
211                                               NULL);
212
213         return get_all_properties(message, interface, obj_dsc);
214 }
215
216
217 static DBusMessage * properties_get(DBusMessage *message,
218                                     struct wpa_dbus_property_desc *dsc,
219                                     void *user_data)
220 {
221         if (os_strcmp(dbus_message_get_signature(message), "ss"))
222                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
223                                               NULL);
224
225         if (dsc->access != W && dsc->getter)
226                 return dsc->getter(message, user_data);
227
228         return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
229                                       "Property is write-only");
230 }
231
232
233 static DBusMessage * properties_set(DBusMessage *message,
234                                     struct wpa_dbus_property_desc *dsc,
235                                     void *user_data)
236 {
237         if (os_strcmp(dbus_message_get_signature(message), "ssv"))
238                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
239                                               NULL);
240
241         if (dsc->access != R && dsc->setter)
242                 return dsc->setter(message, user_data);
243
244         return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
245                                       "Property is read-only");
246 }
247
248
249 static DBusMessage *
250 properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
251                       char *interface,
252                       struct wpa_dbus_object_desc *obj_dsc)
253 {
254         struct wpa_dbus_property_desc *property_dsc;
255         char *property;
256         const char *method;
257
258         method = dbus_message_get_member(message);
259         property_dsc = obj_dsc->properties;
260
261         /* Second argument: property name (DBUS_TYPE_STRING) */
262         if (!dbus_message_iter_next(iter) ||
263             dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
264                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
265                                               NULL);
266         }
267         dbus_message_iter_get_basic(iter, &property);
268
269         while (property_dsc) {
270                 /* compare property names and
271                  * interfaces */
272                 if (!os_strncmp(property_dsc->dbus_property, property,
273                                 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
274                     !os_strncmp(property_dsc->dbus_interface, interface,
275                                 WPAS_DBUS_INTERFACE_MAX))
276                         break;
277
278                 property_dsc = property_dsc->next;
279         }
280         if (property_dsc == NULL) {
281                 wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
282                            interface, property,
283                            dbus_message_get_path(message));
284                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
285                                               "No such property");
286         }
287
288         if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
289                        WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
290                 return properties_get(message, property_dsc,
291                                       obj_dsc->user_data);
292
293         return properties_set(message, property_dsc, obj_dsc->user_data);
294 }
295
296
297 static DBusMessage * properties_handler(DBusMessage *message,
298                                         struct wpa_dbus_object_desc *obj_dsc)
299 {
300         DBusMessageIter iter;
301         char *interface;
302         const char *method;
303
304         method = dbus_message_get_member(message);
305         dbus_message_iter_init(message, &iter);
306
307         if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
308                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
309             !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
310                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
311             !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
312                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
313                 /* First argument: interface name (DBUS_TYPE_STRING) */
314                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
315                 {
316                         return dbus_message_new_error(message,
317                                                       DBUS_ERROR_INVALID_ARGS,
318                                                       NULL);
319                 }
320
321                 dbus_message_iter_get_basic(&iter, &interface);
322
323                 if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
324                                 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
325                         /* GetAll */
326                         return properties_get_all(message, interface, obj_dsc);
327                 }
328                 /* Get or Set */
329                 return properties_get_or_set(message, &iter, interface,
330                                              obj_dsc);
331         }
332         return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
333                                       NULL);
334 }
335
336
337 static DBusMessage * msg_method_handler(DBusMessage *message,
338                                         struct wpa_dbus_object_desc *obj_dsc)
339 {
340         struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
341         const char *method;
342         const char *msg_interface;
343
344         method = dbus_message_get_member(message);
345         msg_interface = dbus_message_get_interface(message);
346
347         /* try match call to any registered method */
348         while (method_dsc) {
349                 /* compare method names and interfaces */
350                 if (!os_strncmp(method_dsc->dbus_method, method,
351                                 WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
352                     !os_strncmp(method_dsc->dbus_interface, msg_interface,
353                                 WPAS_DBUS_INTERFACE_MAX))
354                         break;
355
356                 method_dsc = method_dsc->next;
357         }
358         if (method_dsc == NULL) {
359                 wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
360                            msg_interface, method,
361                            dbus_message_get_path(message));
362                 return dbus_message_new_error(message,
363                                               DBUS_ERROR_UNKNOWN_METHOD, NULL);
364         }
365
366         if (!is_signature_correct(message, method_dsc)) {
367                 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
368                                               NULL);
369         }
370
371         return method_dsc->method_handler(message,
372                                           obj_dsc->user_data);
373 }
374
375
376 /**
377  * message_handler - Handles incoming DBus messages
378  * @connection: DBus connection on which message was received
379  * @message: Received message
380  * @user_data: pointer to description of object to which message was sent
381  * Returns: Returns information whether message was handled or not
382  *
383  * Reads message interface and method name, then checks if they matches one
384  * of the special cases i.e. introspection call or properties get/getall/set
385  * methods and handles it. Else it iterates over registered methods list
386  * and tries to match method's name and interface to those read from message
387  * If appropriate method was found its handler function is called and
388  * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
389  * will be sent.
390  */
391 static DBusHandlerResult message_handler(DBusConnection *connection,
392                                          DBusMessage *message, void *user_data)
393 {
394         struct wpa_dbus_object_desc *obj_dsc = user_data;
395         const char *method;
396         const char *path;
397         const char *msg_interface;
398         DBusMessage *reply;
399
400         /* get method, interface and path the message is addressed to */
401         method = dbus_message_get_member(message);
402         path = dbus_message_get_path(message);
403         msg_interface = dbus_message_get_interface(message);
404         if (!method || !path || !msg_interface)
405                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
406
407         wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
408                    msg_interface, method, path);
409
410         /* if message is introspection method call */
411         if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
412                         WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
413             !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
414                         WPAS_DBUS_INTERFACE_MAX)) {
415 #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
416                 reply = wpa_dbus_introspect(message, obj_dsc);
417 #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
418                 reply = dbus_message_new_error(
419                         message, DBUS_ERROR_UNKNOWN_METHOD,
420                         "wpa_supplicant was compiled without "
421                         "introspection support.");
422 #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
423         } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
424                              WPAS_DBUS_INTERFACE_MAX)) {
425                 /* if message is properties method call */
426                 reply = properties_handler(message, obj_dsc);
427         } else {
428                 reply = msg_method_handler(message, obj_dsc);
429         }
430
431         /* If handler succeed returning NULL, reply empty message */
432         if (!reply)
433                 reply = dbus_message_new_method_return(message);
434         if (reply) {
435                 if (!dbus_message_get_no_reply(message))
436                         dbus_connection_send(connection, reply, NULL);
437                 dbus_message_unref(reply);
438         }
439         return DBUS_HANDLER_RESULT_HANDLED;
440 }
441
442
443 /**
444  * free_dbus_object_desc - Frees object description data structure
445  * @connection: DBus connection
446  * @obj_dsc: Object description to free
447  *
448  * Frees each of properties, methods and signals description lists and
449  * the object description structure itself.
450  */
451 void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
452 {
453         struct wpa_dbus_method_desc *method_dsc, *tmp_met_dsc;
454         struct wpa_dbus_signal_desc *signal_dsc, *tmp_sig_dsc;
455         struct wpa_dbus_property_desc *property_dsc, *tmp_prop_dsc;
456         int i;
457
458         if (!obj_dsc)
459                 return;
460
461         /* free methods */
462         method_dsc = obj_dsc->methods;
463
464         while (method_dsc) {
465                 tmp_met_dsc = method_dsc;
466                 method_dsc = method_dsc->next;
467
468                 os_free(tmp_met_dsc->dbus_interface);
469                 os_free(tmp_met_dsc->dbus_method);
470
471                 for (i = 0; i < tmp_met_dsc->args_num; i++) {
472                         os_free(tmp_met_dsc->args[i].name);
473                         os_free(tmp_met_dsc->args[i].type);
474                 }
475
476                 os_free(tmp_met_dsc);
477         }
478
479         /* free signals */
480         signal_dsc = obj_dsc->signals;
481
482         while (signal_dsc) {
483                 tmp_sig_dsc = signal_dsc;
484                 signal_dsc = signal_dsc->next;
485
486                 os_free(tmp_sig_dsc->dbus_interface);
487                 os_free(tmp_sig_dsc->dbus_signal);
488
489                 for (i = 0; i < tmp_sig_dsc->args_num; i++) {
490                         os_free(tmp_sig_dsc->args[i].name);
491                         os_free(tmp_sig_dsc->args[i].type);
492                 }
493
494                 os_free(tmp_sig_dsc);
495         }
496
497         /* free properties */
498         property_dsc = obj_dsc->properties;
499
500         while (property_dsc) {
501                 tmp_prop_dsc = property_dsc;
502                 property_dsc = property_dsc->next;
503
504                 os_free(tmp_prop_dsc->dbus_interface);
505                 os_free(tmp_prop_dsc->dbus_property);
506                 os_free(tmp_prop_dsc->type);
507
508                 os_free(tmp_prop_dsc);
509         }
510
511         /* free handler's argument */
512         if (obj_dsc->user_data_free_func)
513                 obj_dsc->user_data_free_func(obj_dsc->user_data);
514
515         os_free(obj_dsc);
516 }
517
518
519 static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
520 {
521         free_dbus_object_desc(obj_dsc);
522 }
523
524 /**
525  * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
526  * @application_data: Pointer to application specific data structure
527  * @dbus_path: DBus path to interface object
528  * @dbus_service: DBus service name to register with
529  * @messageHandler: a pointer to function which will handle dbus messages
530  * coming on interface
531  * Returns: 0 on success, -1 on failure
532  *
533  * Initialize the dbus control interface and start receiving commands from
534  * external programs over the bus.
535  */
536 int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
537                              char *dbus_path, char *dbus_service,
538                              struct wpa_dbus_object_desc *obj_desc)
539 {
540         DBusError error;
541         int ret = -1;
542         DBusObjectPathVTable wpa_vtable = {
543                 &free_dbus_object_desc_cb, &message_handler,
544                 NULL, NULL, NULL, NULL
545         };
546
547         obj_desc->connection = iface->con;
548
549         /* Register the message handler for the global dbus interface */
550         if (!dbus_connection_register_object_path(iface->con,
551                                                   dbus_path, &wpa_vtable,
552                                                   obj_desc)) {
553                 perror("dbus_connection_register_object_path[dbus]");
554                 wpa_printf(MSG_ERROR, "Could not set up DBus message "
555                            "handler.");
556                 return -1;
557         }
558
559         /* Register our service with the message bus */
560         dbus_error_init(&error);
561         switch (dbus_bus_request_name(iface->con, dbus_service,
562                                       0, &error)) {
563         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
564                 ret = 0;
565                 break;
566         case DBUS_REQUEST_NAME_REPLY_EXISTS:
567         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
568         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
569                 perror("dbus_bus_request_name[dbus]");
570                 wpa_printf(MSG_ERROR, "Could not request DBus service name: "
571                            "already registered.");
572                 break;
573         default:
574                 perror("dbus_bus_request_name[dbus]");
575                 wpa_printf(MSG_ERROR, "Could not request DBus service name: "
576                            "%s %s.", error.name, error.message);
577                 break;
578         }
579         dbus_error_free(&error);
580
581         if (ret != 0)
582                 return -1;
583
584         wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
585
586         return 0;
587 }
588
589
590 /**
591  * wpa_dbus_register_object_per_iface - Register a new object with dbus
592  * @ctrl_iface: pointer to dbus private data
593  * @path: DBus path to object
594  * @ifname: interface name
595  * @obj_desc: description of object's methods, signals and properties
596  * Returns: 0 on success, -1 on error
597  *
598  * Registers a new interface with dbus and assigns it a dbus object path.
599  */
600 int wpa_dbus_register_object_per_iface(
601         struct wpas_dbus_priv *ctrl_iface,
602         const char *path, const char *ifname,
603         struct wpa_dbus_object_desc *obj_desc)
604 {
605         DBusConnection *con;
606
607         DBusObjectPathVTable vtable = {
608                 &free_dbus_object_desc_cb, &message_handler,
609                 NULL, NULL, NULL, NULL
610         };
611
612         /* Do nothing if the control interface is not turned on */
613         if (ctrl_iface == NULL)
614                 return 0;
615
616         con = ctrl_iface->con;
617         obj_desc->connection = con;
618
619         /* Register the message handler for the interface functions */
620         if (!dbus_connection_register_object_path(con, path, &vtable,
621                                                   obj_desc)) {
622                 perror("wpa_dbus_register_iface [dbus]");
623                 wpa_printf(MSG_ERROR, "Could not set up DBus message "
624                            "handler for interface %s\n"
625                            "and object %s.", ifname, path);
626                 return -1;
627         }
628
629         return 0;
630 }
631
632
633 /**
634  * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
635  * @ctrl_iface: Pointer to dbus private data
636  * @path: DBus path to object which will be unregistered
637  * Returns: Zero on success and -1 on failure
638  *
639  * Unregisters DBus object given by its path
640  */
641 int wpa_dbus_unregister_object_per_iface(
642         struct wpas_dbus_priv *ctrl_iface, const char *path)
643 {
644         DBusConnection *con = ctrl_iface->con;
645         if (!dbus_connection_unregister_object_path(con, path))
646                 return -1;
647
648         return 0;
649 }
650
651
652 /**
653  * wpa_dbus_method_register - Registers DBus method for given object
654  * @obj_dsc: Object description for which a method will be registered
655  * @dbus_interface: DBus interface under which method will be registered
656  * @dbus_method: a name the method will be registered with
657  * @method_handler: a function which will be called to handle this method call
658  * @args: method arguments list
659  * Returns: Zero on success and -1 on failure
660  *
661  * Registers DBus method under given name and interface for the object.
662  * Method calls will be handled with given handling function.
663  * Handler function is required to return a DBusMessage pointer which
664  * will be response to method call. Any method call before being handled
665  * must have registered appropriate handler by using this function.
666  */
667 int wpa_dbus_method_register(struct wpa_dbus_object_desc *obj_dsc,
668                              const char *dbus_interface,
669                              const char *dbus_method,
670                              WPADBusMethodHandler method_handler,
671                              const struct wpa_dbus_argument args[])
672 {
673         struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
674         struct wpa_dbus_method_desc *prev_desc;
675         int args_num = 0;
676         int i, error;
677
678         prev_desc = NULL;
679         while (method_dsc) {
680                 prev_desc = method_dsc;
681                 method_dsc = method_dsc->next;
682         }
683
684         /* count args */
685         if (args) {
686                 while (args[args_num].name && args[args_num].type)
687                         args_num++;
688         }
689
690         method_dsc = os_zalloc(sizeof(struct wpa_dbus_method_desc) +
691                                args_num * sizeof(struct wpa_dbus_argument));
692         if (!method_dsc)
693                 goto err;
694
695         if (prev_desc == NULL)
696                 obj_dsc->methods = method_dsc;
697         else
698                 prev_desc->next = method_dsc;
699
700         /* copy interface name */
701         method_dsc->dbus_interface = os_strdup(dbus_interface);
702         if (!method_dsc->dbus_interface)
703                 goto err;
704
705         /* copy method name */
706         method_dsc->dbus_method = os_strdup(dbus_method);
707         if (!method_dsc->dbus_method)
708                 goto err;
709
710         /* copy arguments */
711         error = 0;
712         method_dsc->args_num = args_num;
713         for (i = 0; i < args_num; i++) {
714                 method_dsc->args[i].name = os_strdup(args[i].name);
715                 if (!method_dsc->args[i].name) {
716                         error = 1;
717                         continue;
718                 }
719
720                 method_dsc->args[i].type = os_strdup(args[i].type);
721                 if (!method_dsc->args[i].type) {
722                         error = 1;
723                         continue;
724                 }
725
726                 method_dsc->args[i].dir = args[i].dir;
727         }
728         if (error)
729                 goto err;
730
731         method_dsc->method_handler = method_handler;
732         method_dsc->next = NULL;
733
734         return 0;
735
736 err:
737         wpa_printf(MSG_WARNING, "Failed to register dbus method %s in "
738                    "interface %s", dbus_method, dbus_interface);
739         if (method_dsc) {
740                 os_free(method_dsc->dbus_interface);
741                 os_free(method_dsc->dbus_method);
742                 for (i = 0; i < method_dsc->args_num; i++) {
743                         os_free(method_dsc->args[i].name);
744                         os_free(method_dsc->args[i].type);
745                 }
746
747                 if (prev_desc == NULL)
748                         obj_dsc->methods = NULL;
749                 else
750                         prev_desc->next = NULL;
751
752                 os_free(method_dsc);
753         }
754
755         return -1;
756 }
757
758
759 /**
760  * wpa_dbus_signal_register - Registers DBus signal for given object
761  * @obj_dsc: Object description for which a signal will be registered
762  * @dbus_interface: DBus interface under which signal will be registered
763  * @dbus_signal: a name the signal will be registered with
764  * @args: signal arguments list
765  * Returns: Zero on success and -1 on failure
766  *
767  * Registers DBus signal under given name and interface for the object.
768  * Signal registration is NOT required in order to send signals, but not
769  * registered signals will not be respected in introspection data
770  * therefore it is highly recommended to register every signal before
771  * using it.
772  */
773 int wpa_dbus_signal_register(struct wpa_dbus_object_desc *obj_dsc,
774                              const char *dbus_interface,
775                              const char *dbus_signal,
776                              const struct wpa_dbus_argument args[])
777 {
778
779         struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
780         struct wpa_dbus_signal_desc *prev_desc;
781         int args_num = 0;
782         int i, error = 0;
783
784         prev_desc = NULL;
785         while (signal_dsc) {
786                 prev_desc = signal_dsc;
787                 signal_dsc = signal_dsc->next;
788         }
789
790         /* count args */
791         if (args) {
792                 while (args[args_num].name && args[args_num].type)
793                         args_num++;
794         }
795
796         signal_dsc = os_zalloc(sizeof(struct wpa_dbus_signal_desc) +
797                                args_num * sizeof(struct wpa_dbus_argument));
798         if (!signal_dsc)
799                 goto err;
800
801         if (prev_desc == NULL)
802                 obj_dsc->signals = signal_dsc;
803         else
804                 prev_desc->next = signal_dsc;
805
806         /* copy interface name */
807         signal_dsc->dbus_interface = os_strdup(dbus_interface);
808         if (!signal_dsc->dbus_interface)
809                 goto err;
810
811         /* copy signal name */
812         signal_dsc->dbus_signal = os_strdup(dbus_signal);
813         if (!signal_dsc->dbus_signal)
814                 goto err;
815
816         /* copy arguments */
817         signal_dsc->args_num = args_num;
818         for (i = 0; i < args_num; i++) {
819                 signal_dsc->args[i].name = os_strdup(args[i].name);
820                 if (!signal_dsc->args[i].name) {
821                         error = 1;
822                         continue;
823                 }
824
825                 signal_dsc->args[i].type = os_strdup(args[i].type);
826                 if (!signal_dsc->args[i].type) {
827                         error = 1;
828                         continue;
829                 }
830         }
831         if (error)
832                 goto err;
833
834         signal_dsc->next = NULL;
835
836         return 0;
837
838 err:
839         wpa_printf(MSG_WARNING, "Failed to register dbus signal %s in "
840                    "interface %s", dbus_signal, dbus_interface);
841         if (signal_dsc) {
842                 os_free(signal_dsc->dbus_interface);
843                 os_free(signal_dsc->dbus_signal);
844                 for (i = 0; i < signal_dsc->args_num; i++) {
845                         os_free(signal_dsc->args[i].name);
846                         os_free(signal_dsc->args[i].type);
847                 }
848
849                 if (prev_desc == NULL)
850                         obj_dsc->signals = NULL;
851                 else
852                         prev_desc->next = NULL;
853
854                 os_free(signal_dsc);
855         }
856
857         return -1;
858 }
859
860
861 /**
862  * wpa_dbus_property_register - Registers DBus property for given object
863  * @obj_dsc: Object description for which a property will be registered
864  * @dbus_interface: DBus interface under which method will be registered
865  * @dbus_property: a name the property will be registered with
866  * @type: a property type signature in form of DBus type description
867  * @getter: a function called in order to get property value
868  * @setter: a function called in order to set property value
869  * @access: property access permissions specifier (R, W or RW)
870  * Returns: Zero on success and -1 on failure
871  *
872  * Registers DBus property under given name and interface for the object.
873  * Properties are set with giver setter function and get with getter.Getter
874  * or setter are required to return DBusMessage which is response to Set/Get
875  * method calls. Every property must be registered by this function before
876  * being used.
877  */
878 int wpa_dbus_property_register(struct wpa_dbus_object_desc *obj_dsc,
879                                const char *dbus_interface,
880                                const char *dbus_property,
881                                const char *type,
882                                WPADBusPropertyAccessor getter,
883                                WPADBusPropertyAccessor setter,
884                                enum dbus_prop_access _access)
885 {
886         struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
887         struct wpa_dbus_property_desc *prev_desc;
888
889         prev_desc = NULL;
890         while (property_dsc) {
891                 prev_desc = property_dsc;
892                 property_dsc = property_dsc->next;
893         }
894
895         property_dsc = os_zalloc(sizeof(struct wpa_dbus_property_desc));
896         if (!property_dsc)
897                 goto err;
898
899         if (prev_desc == NULL)
900                 obj_dsc->properties = property_dsc;
901         else
902                 prev_desc->next = property_dsc;
903
904         /* copy interface name */
905         property_dsc->dbus_interface = os_strdup(dbus_interface);
906         if (!property_dsc->dbus_interface)
907                 goto err;
908
909         /* copy property name */
910         property_dsc->dbus_property = os_strdup(dbus_property);
911         if (!property_dsc->dbus_property)
912                 goto err;
913
914         /* copy property type */
915         property_dsc->type = os_strdup(type);
916         if (!property_dsc->type)
917                 goto err;
918
919         property_dsc->getter = getter;
920         property_dsc->setter = setter;
921         property_dsc->access = _access;
922         property_dsc->next = NULL;
923
924         return 0;
925
926 err:
927         wpa_printf(MSG_WARNING, "Failed to register dbus property %s in "
928                    "interface %s", dbus_property, dbus_interface);
929         if (property_dsc) {
930                 os_free(property_dsc->dbus_interface);
931                 os_free(property_dsc->dbus_property);
932                 os_free(property_dsc->type);
933
934                 if (prev_desc == NULL)
935                         obj_dsc->properties = NULL;
936                 else
937                         prev_desc->next = NULL;
938
939                 os_free(property_dsc);
940         }
941
942         return -1;
943 }
944
945
946 /**
947  * wpas_dbus_signal_network_added - Send a property changed signal
948  * @iface: dbus priv struct
949  * @property_getter: propperty getter used to fetch new property value
950  * @getter_arg: argument passed to property getter
951  * @path: path to object which property has changed
952  * @interface_name: signal and property interface
953  * @property_name: name of property which has changed
954  *
955  * Notify listeners about changing value of some property. Signal
956  * contains property name and its value fetched using given property
957  * getter.
958  */
959 void wpa_dbus_signal_property_changed(struct wpas_dbus_priv *iface,
960                                       WPADBusPropertyAccessor property_getter,
961                                       void *getter_arg,
962                                       const char *path,
963                                       const char *interface_name,
964                                       const char *property_name)
965 {
966
967         DBusConnection *connection;
968         DBusMessage *_signal, *getter_reply;
969         DBusMessageIter prop_iter, signal_iter, dict_iter, entry_iter;
970
971         if (!iface)
972                 return;
973         connection = iface->con;
974
975         if (!property_getter) {
976                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
977                            "[dbus]: property getter not specified");
978                 return;
979         }
980
981         if (!path || !interface_name || !property_name) {
982                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
983                            "[dbus]: path interface of property not specified");
984                 return;
985         }
986
987         getter_reply = property_getter(NULL, getter_arg);
988         if (!getter_reply ||
989             dbus_message_get_type(getter_reply) == DBUS_MESSAGE_TYPE_ERROR) {
990                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
991                            "[dbus]: cannot get new value of property %s",
992                            property_name);
993                 return;
994         }
995
996         _signal = dbus_message_new_signal(path, interface_name,
997                                           "PropertiesChanged");
998         if (!_signal) {
999                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1000                            "[dbus]: cannot allocate signal");
1001                 dbus_message_unref(getter_reply);
1002                 return;
1003         }
1004
1005         dbus_message_iter_init(getter_reply, &prop_iter);
1006         dbus_message_iter_init_append(_signal, &signal_iter);
1007
1008         if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
1009                                               "{sv}", &dict_iter)) {
1010                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1011                            "[dbus]: out of memory. cannot open dictionary");
1012                 goto err;
1013         }
1014
1015         if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY,
1016                                               NULL, &entry_iter)) {
1017                 wpa_printf(MSG_ERROR, "iwpa_dbus_signal_property_changed"
1018                            "[dbus]: out of memory. cannot open dictionary "
1019                            "element");
1020                 goto err;
1021         }
1022
1023         if (!dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING,
1024                                             &property_name)) {
1025                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1026                            "[dbus]: out of memory. cannot open add property "
1027                            "name");
1028                 goto err;
1029         }
1030
1031         recursive_iter_copy(&prop_iter, &entry_iter);
1032
1033         if (!dbus_message_iter_close_container(&dict_iter, &entry_iter)) {
1034                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1035                            "[dbus]: out of memory. cannot close dictionary "
1036                            "element");
1037                 goto err;
1038         }
1039
1040         if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
1041                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1042                            "[dbus]: out of memory. cannot close dictionary");
1043                 goto err;
1044         }
1045
1046         dbus_connection_send(connection, _signal, NULL);
1047
1048 err:
1049         dbus_message_unref(getter_reply);
1050         dbus_message_unref(_signal);
1051
1052 }
1053
1054
1055 /**
1056  * wpa_dbus_get_object_properties - Put object's properties into dictionary
1057  * @iface: dbus priv struct
1058  * @path: path to DBus object which properties will be obtained
1059  * @interface: interface name which properties will be obtained
1060  * @dict_iter: correct, open DBus dictionary iterator.
1061  *
1062  * Iterates over all properties registered with object and execute getters
1063  * of those, which are readable and which interface matches interface
1064  * specified as argument. Obtained properties values are stored in
1065  * dict_iter dictionary.
1066  */
1067 void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
1068                                     const char *path, const char *interface,
1069                                     DBusMessageIter *dict_iter)
1070 {
1071         struct wpa_dbus_object_desc *obj_desc = NULL;
1072
1073         dbus_connection_get_object_path_data(iface->con, path,
1074                                              (void **) &obj_desc);
1075         if (!obj_desc) {
1076                 wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
1077                            "could not obtain object's private data: %s", path);
1078                 return;
1079         }
1080
1081         fill_dict_with_properties(dict_iter, obj_desc->properties,
1082                                   interface, obj_desc->user_data);
1083 }