dbus: Use common code for checking key parameter
[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, 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                 wpa_printf(MSG_ERROR, "dbus: Could not set up message "
554                            "handler");
555                 return -1;
556         }
557
558         /* Register our service with the message bus */
559         dbus_error_init(&error);
560         switch (dbus_bus_request_name(iface->con, dbus_service,
561                                       0, &error)) {
562         case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
563                 ret = 0;
564                 break;
565         case DBUS_REQUEST_NAME_REPLY_EXISTS:
566         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
567         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
568                 wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
569                            "already registered");
570                 break;
571         default:
572                 wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
573                            "%s %s", error.name, error.message);
574                 break;
575         }
576         dbus_error_free(&error);
577
578         if (ret != 0)
579                 return -1;
580
581         wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
582
583         return 0;
584 }
585
586
587 /**
588  * wpa_dbus_register_object_per_iface - Register a new object with dbus
589  * @ctrl_iface: pointer to dbus private data
590  * @path: DBus path to object
591  * @ifname: interface name
592  * @obj_desc: description of object's methods, signals and properties
593  * Returns: 0 on success, -1 on error
594  *
595  * Registers a new interface with dbus and assigns it a dbus object path.
596  */
597 int wpa_dbus_register_object_per_iface(
598         struct wpas_dbus_priv *ctrl_iface,
599         const char *path, const char *ifname,
600         struct wpa_dbus_object_desc *obj_desc)
601 {
602         DBusConnection *con;
603
604         DBusObjectPathVTable vtable = {
605                 &free_dbus_object_desc_cb, &message_handler,
606                 NULL, NULL, NULL, NULL
607         };
608
609         /* Do nothing if the control interface is not turned on */
610         if (ctrl_iface == NULL)
611                 return 0;
612
613         con = ctrl_iface->con;
614         obj_desc->connection = con;
615
616         /* Register the message handler for the interface functions */
617         if (!dbus_connection_register_object_path(con, path, &vtable,
618                                                   obj_desc)) {
619                 wpa_printf(MSG_ERROR, "dbus: Could not set up message "
620                            "handler for interface %s object %s", ifname, path);
621                 return -1;
622         }
623
624         return 0;
625 }
626
627
628 /**
629  * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
630  * @ctrl_iface: Pointer to dbus private data
631  * @path: DBus path to object which will be unregistered
632  * Returns: Zero on success and -1 on failure
633  *
634  * Unregisters DBus object given by its path
635  */
636 int wpa_dbus_unregister_object_per_iface(
637         struct wpas_dbus_priv *ctrl_iface, const char *path)
638 {
639         DBusConnection *con = ctrl_iface->con;
640         if (!dbus_connection_unregister_object_path(con, path))
641                 return -1;
642
643         return 0;
644 }
645
646
647 /**
648  * wpa_dbus_method_register - Registers DBus method for given object
649  * @obj_dsc: Object description for which a method will be registered
650  * @dbus_interface: DBus interface under which method will be registered
651  * @dbus_method: a name the method will be registered with
652  * @method_handler: a function which will be called to handle this method call
653  * @args: method arguments list
654  * Returns: Zero on success and -1 on failure
655  *
656  * Registers DBus method under given name and interface for the object.
657  * Method calls will be handled with given handling function.
658  * Handler function is required to return a DBusMessage pointer which
659  * will be response to method call. Any method call before being handled
660  * must have registered appropriate handler by using this function.
661  */
662 int wpa_dbus_method_register(struct wpa_dbus_object_desc *obj_dsc,
663                              const char *dbus_interface,
664                              const char *dbus_method,
665                              WPADBusMethodHandler method_handler,
666                              const struct wpa_dbus_argument args[])
667 {
668         struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
669         struct wpa_dbus_method_desc *prev_desc;
670         int args_num = 0;
671         int i, error;
672
673         prev_desc = NULL;
674         while (method_dsc) {
675                 prev_desc = method_dsc;
676                 method_dsc = method_dsc->next;
677         }
678
679         /* count args */
680         if (args) {
681                 while (args[args_num].name && args[args_num].type)
682                         args_num++;
683         }
684
685         method_dsc = os_zalloc(sizeof(struct wpa_dbus_method_desc) +
686                                args_num * sizeof(struct wpa_dbus_argument));
687         if (!method_dsc)
688                 goto err;
689
690         if (prev_desc == NULL)
691                 obj_dsc->methods = method_dsc;
692         else
693                 prev_desc->next = method_dsc;
694
695         /* copy interface name */
696         method_dsc->dbus_interface = os_strdup(dbus_interface);
697         if (!method_dsc->dbus_interface)
698                 goto err;
699
700         /* copy method name */
701         method_dsc->dbus_method = os_strdup(dbus_method);
702         if (!method_dsc->dbus_method)
703                 goto err;
704
705         /* copy arguments */
706         error = 0;
707         method_dsc->args_num = args_num;
708         for (i = 0; i < args_num; i++) {
709                 method_dsc->args[i].name = os_strdup(args[i].name);
710                 if (!method_dsc->args[i].name) {
711                         error = 1;
712                         continue;
713                 }
714
715                 method_dsc->args[i].type = os_strdup(args[i].type);
716                 if (!method_dsc->args[i].type) {
717                         error = 1;
718                         continue;
719                 }
720
721                 method_dsc->args[i].dir = args[i].dir;
722         }
723         if (error)
724                 goto err;
725
726         method_dsc->method_handler = method_handler;
727         method_dsc->next = NULL;
728
729         return 0;
730
731 err:
732         wpa_printf(MSG_WARNING, "Failed to register dbus method %s in "
733                    "interface %s", dbus_method, dbus_interface);
734         if (method_dsc) {
735                 os_free(method_dsc->dbus_interface);
736                 os_free(method_dsc->dbus_method);
737                 for (i = 0; i < method_dsc->args_num; i++) {
738                         os_free(method_dsc->args[i].name);
739                         os_free(method_dsc->args[i].type);
740                 }
741
742                 if (prev_desc == NULL)
743                         obj_dsc->methods = NULL;
744                 else
745                         prev_desc->next = NULL;
746
747                 os_free(method_dsc);
748         }
749
750         return -1;
751 }
752
753
754 /**
755  * wpa_dbus_signal_register - Registers DBus signal for given object
756  * @obj_dsc: Object description for which a signal will be registered
757  * @dbus_interface: DBus interface under which signal will be registered
758  * @dbus_signal: a name the signal will be registered with
759  * @args: signal arguments list
760  * Returns: Zero on success and -1 on failure
761  *
762  * Registers DBus signal under given name and interface for the object.
763  * Signal registration is NOT required in order to send signals, but not
764  * registered signals will not be respected in introspection data
765  * therefore it is highly recommended to register every signal before
766  * using it.
767  */
768 int wpa_dbus_signal_register(struct wpa_dbus_object_desc *obj_dsc,
769                              const char *dbus_interface,
770                              const char *dbus_signal,
771                              const struct wpa_dbus_argument args[])
772 {
773
774         struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
775         struct wpa_dbus_signal_desc *prev_desc;
776         int args_num = 0;
777         int i, error = 0;
778
779         prev_desc = NULL;
780         while (signal_dsc) {
781                 prev_desc = signal_dsc;
782                 signal_dsc = signal_dsc->next;
783         }
784
785         /* count args */
786         if (args) {
787                 while (args[args_num].name && args[args_num].type)
788                         args_num++;
789         }
790
791         signal_dsc = os_zalloc(sizeof(struct wpa_dbus_signal_desc) +
792                                args_num * sizeof(struct wpa_dbus_argument));
793         if (!signal_dsc)
794                 goto err;
795
796         if (prev_desc == NULL)
797                 obj_dsc->signals = signal_dsc;
798         else
799                 prev_desc->next = signal_dsc;
800
801         /* copy interface name */
802         signal_dsc->dbus_interface = os_strdup(dbus_interface);
803         if (!signal_dsc->dbus_interface)
804                 goto err;
805
806         /* copy signal name */
807         signal_dsc->dbus_signal = os_strdup(dbus_signal);
808         if (!signal_dsc->dbus_signal)
809                 goto err;
810
811         /* copy arguments */
812         signal_dsc->args_num = args_num;
813         for (i = 0; i < args_num; i++) {
814                 signal_dsc->args[i].name = os_strdup(args[i].name);
815                 if (!signal_dsc->args[i].name) {
816                         error = 1;
817                         continue;
818                 }
819
820                 signal_dsc->args[i].type = os_strdup(args[i].type);
821                 if (!signal_dsc->args[i].type) {
822                         error = 1;
823                         continue;
824                 }
825         }
826         if (error)
827                 goto err;
828
829         signal_dsc->next = NULL;
830
831         return 0;
832
833 err:
834         wpa_printf(MSG_WARNING, "Failed to register dbus signal %s in "
835                    "interface %s", dbus_signal, dbus_interface);
836         if (signal_dsc) {
837                 os_free(signal_dsc->dbus_interface);
838                 os_free(signal_dsc->dbus_signal);
839                 for (i = 0; i < signal_dsc->args_num; i++) {
840                         os_free(signal_dsc->args[i].name);
841                         os_free(signal_dsc->args[i].type);
842                 }
843
844                 if (prev_desc == NULL)
845                         obj_dsc->signals = NULL;
846                 else
847                         prev_desc->next = NULL;
848
849                 os_free(signal_dsc);
850         }
851
852         return -1;
853 }
854
855
856 /**
857  * wpa_dbus_property_register - Registers DBus property for given object
858  * @obj_dsc: Object description for which a property will be registered
859  * @dbus_interface: DBus interface under which method will be registered
860  * @dbus_property: a name the property will be registered with
861  * @type: a property type signature in form of DBus type description
862  * @getter: a function called in order to get property value
863  * @setter: a function called in order to set property value
864  * @access: property access permissions specifier (R, W or RW)
865  * Returns: Zero on success and -1 on failure
866  *
867  * Registers DBus property under given name and interface for the object.
868  * Properties are set with giver setter function and get with getter.Getter
869  * or setter are required to return DBusMessage which is response to Set/Get
870  * method calls. Every property must be registered by this function before
871  * being used.
872  */
873 int wpa_dbus_property_register(struct wpa_dbus_object_desc *obj_dsc,
874                                const char *dbus_interface,
875                                const char *dbus_property,
876                                const char *type,
877                                WPADBusPropertyAccessor getter,
878                                WPADBusPropertyAccessor setter,
879                                enum dbus_prop_access _access)
880 {
881         struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
882         struct wpa_dbus_property_desc *prev_desc;
883
884         prev_desc = NULL;
885         while (property_dsc) {
886                 prev_desc = property_dsc;
887                 property_dsc = property_dsc->next;
888         }
889
890         property_dsc = os_zalloc(sizeof(struct wpa_dbus_property_desc));
891         if (!property_dsc)
892                 goto err;
893
894         if (prev_desc == NULL)
895                 obj_dsc->properties = property_dsc;
896         else
897                 prev_desc->next = property_dsc;
898
899         /* copy interface name */
900         property_dsc->dbus_interface = os_strdup(dbus_interface);
901         if (!property_dsc->dbus_interface)
902                 goto err;
903
904         /* copy property name */
905         property_dsc->dbus_property = os_strdup(dbus_property);
906         if (!property_dsc->dbus_property)
907                 goto err;
908
909         /* copy property type */
910         property_dsc->type = os_strdup(type);
911         if (!property_dsc->type)
912                 goto err;
913
914         property_dsc->getter = getter;
915         property_dsc->setter = setter;
916         property_dsc->access = _access;
917         property_dsc->next = NULL;
918
919         return 0;
920
921 err:
922         wpa_printf(MSG_WARNING, "Failed to register dbus property %s in "
923                    "interface %s", dbus_property, dbus_interface);
924         if (property_dsc) {
925                 os_free(property_dsc->dbus_interface);
926                 os_free(property_dsc->dbus_property);
927                 os_free(property_dsc->type);
928
929                 if (prev_desc == NULL)
930                         obj_dsc->properties = NULL;
931                 else
932                         prev_desc->next = NULL;
933
934                 os_free(property_dsc);
935         }
936
937         return -1;
938 }
939
940
941 /**
942  * wpas_dbus_signal_network_added - Send a property changed signal
943  * @iface: dbus priv struct
944  * @property_getter: propperty getter used to fetch new property value
945  * @getter_arg: argument passed to property getter
946  * @path: path to object which property has changed
947  * @interface_name: signal and property interface
948  * @property_name: name of property which has changed
949  *
950  * Notify listeners about changing value of some property. Signal
951  * contains property name and its value fetched using given property
952  * getter.
953  */
954 void wpa_dbus_signal_property_changed(struct wpas_dbus_priv *iface,
955                                       WPADBusPropertyAccessor property_getter,
956                                       void *getter_arg,
957                                       const char *path,
958                                       const char *interface_name,
959                                       const char *property_name)
960 {
961
962         DBusConnection *connection;
963         DBusMessage *_signal, *getter_reply;
964         DBusMessageIter prop_iter, signal_iter, dict_iter, entry_iter;
965
966         if (!iface)
967                 return;
968         connection = iface->con;
969
970         if (!property_getter) {
971                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
972                            "[dbus]: property getter not specified");
973                 return;
974         }
975
976         if (!path || !interface_name || !property_name) {
977                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
978                            "[dbus]: path interface of property not specified");
979                 return;
980         }
981
982         getter_reply = property_getter(NULL, getter_arg);
983         if (!getter_reply ||
984             dbus_message_get_type(getter_reply) == DBUS_MESSAGE_TYPE_ERROR) {
985                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
986                            "[dbus]: cannot get new value of property %s",
987                            property_name);
988                 return;
989         }
990
991         _signal = dbus_message_new_signal(path, interface_name,
992                                           "PropertiesChanged");
993         if (!_signal) {
994                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
995                            "[dbus]: cannot allocate signal");
996                 dbus_message_unref(getter_reply);
997                 return;
998         }
999
1000         dbus_message_iter_init(getter_reply, &prop_iter);
1001         dbus_message_iter_init_append(_signal, &signal_iter);
1002
1003         if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
1004                                               "{sv}", &dict_iter)) {
1005                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1006                            "[dbus]: out of memory. cannot open dictionary");
1007                 goto err;
1008         }
1009
1010         if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY,
1011                                               NULL, &entry_iter)) {
1012                 wpa_printf(MSG_ERROR, "iwpa_dbus_signal_property_changed"
1013                            "[dbus]: out of memory. cannot open dictionary "
1014                            "element");
1015                 goto err;
1016         }
1017
1018         if (!dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING,
1019                                             &property_name)) {
1020                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1021                            "[dbus]: out of memory. cannot open add property "
1022                            "name");
1023                 goto err;
1024         }
1025
1026         recursive_iter_copy(&prop_iter, &entry_iter);
1027
1028         if (!dbus_message_iter_close_container(&dict_iter, &entry_iter)) {
1029                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1030                            "[dbus]: out of memory. cannot close dictionary "
1031                            "element");
1032                 goto err;
1033         }
1034
1035         if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
1036                 wpa_printf(MSG_ERROR, "wpa_dbus_signal_property_changed"
1037                            "[dbus]: out of memory. cannot close dictionary");
1038                 goto err;
1039         }
1040
1041         dbus_connection_send(connection, _signal, NULL);
1042
1043 err:
1044         dbus_message_unref(getter_reply);
1045         dbus_message_unref(_signal);
1046
1047 }
1048
1049
1050 /**
1051  * wpa_dbus_get_object_properties - Put object's properties into dictionary
1052  * @iface: dbus priv struct
1053  * @path: path to DBus object which properties will be obtained
1054  * @interface: interface name which properties will be obtained
1055  * @dict_iter: correct, open DBus dictionary iterator.
1056  *
1057  * Iterates over all properties registered with object and execute getters
1058  * of those, which are readable and which interface matches interface
1059  * specified as argument. Obtained properties values are stored in
1060  * dict_iter dictionary.
1061  */
1062 void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
1063                                     const char *path, const char *interface,
1064                                     DBusMessageIter *dict_iter)
1065 {
1066         struct wpa_dbus_object_desc *obj_desc = NULL;
1067
1068         dbus_connection_get_object_path_data(iface->con, path,
1069                                              (void **) &obj_desc);
1070         if (!obj_desc) {
1071                 wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
1072                            "could not obtain object's private data: %s", path);
1073                 return;
1074         }
1075
1076         fill_dict_with_properties(dict_iter, obj_desc->properties,
1077                                   interface, obj_desc->user_data);
1078 }