D-Bus: Move NetworkRequest signal to correct registration array
[mech_eap.git] / wpa_supplicant / dbus / dbus_dict_helpers.c
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8
9 #include "includes.h"
10 #include <dbus/dbus.h>
11
12 #include "common.h"
13 #include "wpabuf.h"
14 #include "dbus_dict_helpers.h"
15
16
17 /**
18  * Start a dict in a dbus message.  Should be paired with a call to
19  * wpa_dbus_dict_close_write().
20  *
21  * @param iter A valid dbus message iterator
22  * @param iter_dict (out) A dict iterator to pass to further dict functions
23  * @return TRUE on success, FALSE on failure
24  *
25  */
26 dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
27                                      DBusMessageIter *iter_dict)
28 {
29         dbus_bool_t result;
30
31         if (!iter || !iter_dict)
32                 return FALSE;
33
34         result = dbus_message_iter_open_container(
35                 iter,
36                 DBUS_TYPE_ARRAY,
37                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
38                 DBUS_TYPE_STRING_AS_STRING
39                 DBUS_TYPE_VARIANT_AS_STRING
40                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
41                 iter_dict);
42         return result;
43 }
44
45
46 /**
47  * End a dict element in a dbus message.  Should be paired with
48  * a call to wpa_dbus_dict_open_write().
49  *
50  * @param iter valid dbus message iterator, same as passed to
51  *    wpa_dbus_dict_open_write()
52  * @param iter_dict a dbus dict iterator returned from
53  *    wpa_dbus_dict_open_write()
54  * @return TRUE on success, FALSE on failure
55  *
56  */
57 dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
58                                       DBusMessageIter *iter_dict)
59 {
60         if (!iter || !iter_dict)
61                 return FALSE;
62
63         return dbus_message_iter_close_container(iter, iter_dict);
64 }
65
66
67 const char * wpa_dbus_type_as_string(const int type)
68 {
69         switch (type) {
70         case DBUS_TYPE_BYTE:
71                 return DBUS_TYPE_BYTE_AS_STRING;
72         case DBUS_TYPE_BOOLEAN:
73                 return DBUS_TYPE_BOOLEAN_AS_STRING;
74         case DBUS_TYPE_INT16:
75                 return DBUS_TYPE_INT16_AS_STRING;
76         case DBUS_TYPE_UINT16:
77                 return DBUS_TYPE_UINT16_AS_STRING;
78         case DBUS_TYPE_INT32:
79                 return DBUS_TYPE_INT32_AS_STRING;
80         case DBUS_TYPE_UINT32:
81                 return DBUS_TYPE_UINT32_AS_STRING;
82         case DBUS_TYPE_INT64:
83                 return DBUS_TYPE_INT64_AS_STRING;
84         case DBUS_TYPE_UINT64:
85                 return DBUS_TYPE_UINT64_AS_STRING;
86         case DBUS_TYPE_DOUBLE:
87                 return DBUS_TYPE_DOUBLE_AS_STRING;
88         case DBUS_TYPE_STRING:
89                 return DBUS_TYPE_STRING_AS_STRING;
90         case DBUS_TYPE_OBJECT_PATH:
91                 return DBUS_TYPE_OBJECT_PATH_AS_STRING;
92         case DBUS_TYPE_ARRAY:
93                 return DBUS_TYPE_ARRAY_AS_STRING;
94         default:
95                 return NULL;
96         }
97 }
98
99
100 static dbus_bool_t _wpa_dbus_add_dict_entry_start(
101         DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
102         const char *key, const int value_type)
103 {
104         if (!dbus_message_iter_open_container(iter_dict,
105                                               DBUS_TYPE_DICT_ENTRY, NULL,
106                                               iter_dict_entry))
107                 return FALSE;
108
109         return dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
110                                               &key);
111 }
112
113
114 static dbus_bool_t _wpa_dbus_add_dict_entry_end(
115         DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
116         DBusMessageIter *iter_dict_val)
117 {
118         if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
119                 return FALSE;
120
121         return dbus_message_iter_close_container(iter_dict, iter_dict_entry);
122 }
123
124
125 static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
126                                                   const char *key,
127                                                   const int value_type,
128                                                   const void *value)
129 {
130         DBusMessageIter iter_dict_entry, iter_dict_val;
131         const char *type_as_string = NULL;
132
133         if (key == NULL)
134                 return FALSE;
135
136         type_as_string = wpa_dbus_type_as_string(value_type);
137         if (!type_as_string)
138                 return FALSE;
139
140         if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
141                                             key, value_type) ||
142             !dbus_message_iter_open_container(&iter_dict_entry,
143                                               DBUS_TYPE_VARIANT,
144                                               type_as_string, &iter_dict_val) ||
145             !dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
146                 return FALSE;
147
148         return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
149                                             &iter_dict_val);
150 }
151
152
153 static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
154         DBusMessageIter *iter_dict, const char *key,
155         const char *value, const dbus_uint32_t value_len)
156 {
157         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
158         dbus_uint32_t i;
159
160         if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
161                                             key, DBUS_TYPE_ARRAY) ||
162             !dbus_message_iter_open_container(&iter_dict_entry,
163                                               DBUS_TYPE_VARIANT,
164                                               DBUS_TYPE_ARRAY_AS_STRING
165                                               DBUS_TYPE_BYTE_AS_STRING,
166                                               &iter_dict_val) ||
167             !dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
168                                               DBUS_TYPE_BYTE_AS_STRING,
169                                               &iter_array))
170                 return FALSE;
171
172         for (i = 0; i < value_len; i++) {
173                 if (!dbus_message_iter_append_basic(&iter_array,
174                                                     DBUS_TYPE_BYTE,
175                                                     &(value[i])))
176                         return FALSE;
177         }
178
179         if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
180                 return FALSE;
181
182         return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
183                                             &iter_dict_val);
184 }
185
186
187 /**
188  * Add a string entry to the dict.
189  *
190  * @param iter_dict A valid DBusMessageIter returned from
191  *    wpa_dbus_dict_open_write()
192  * @param key The key of the dict item
193  * @param value The string value
194  * @return TRUE on success, FALSE on failure
195  *
196  */
197 dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
198                                         const char *key, const char *value)
199 {
200         if (!value)
201                 return FALSE;
202         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
203                                               &value);
204 }
205
206
207 /**
208  * Add a byte entry to the dict.
209  *
210  * @param iter_dict A valid DBusMessageIter returned from
211  *    wpa_dbus_dict_open_write()
212  * @param key The key of the dict item
213  * @param value The byte value
214  * @return TRUE on success, FALSE on failure
215  *
216  */
217 dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
218                                       const char *key, const char value)
219 {
220         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
221                                               &value);
222 }
223
224
225 /**
226  * Add a boolean entry to the dict.
227  *
228  * @param iter_dict A valid DBusMessageIter returned from
229  *    wpa_dbus_dict_open_write()
230  * @param key The key of the dict item
231  * @param value The boolean value
232  * @return TRUE on success, FALSE on failure
233  *
234  */
235 dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
236                                       const char *key, const dbus_bool_t value)
237 {
238         return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
239                                               DBUS_TYPE_BOOLEAN, &value);
240 }
241
242
243 /**
244  * Add a 16-bit signed integer entry to the dict.
245  *
246  * @param iter_dict A valid DBusMessageIter returned from
247  *    wpa_dbus_dict_open_write()
248  * @param key The key of the dict item
249  * @param value The 16-bit signed integer value
250  * @return TRUE on success, FALSE on failure
251  *
252  */
253 dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
254                                        const char *key,
255                                        const dbus_int16_t value)
256 {
257         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
258                                               &value);
259 }
260
261
262 /**
263  * Add a 16-bit unsigned integer entry to the dict.
264  *
265  * @param iter_dict A valid DBusMessageIter returned from
266  *    wpa_dbus_dict_open_write()
267  * @param key The key of the dict item
268  * @param value The 16-bit unsigned integer value
269  * @return TRUE on success, FALSE on failure
270  *
271  */
272 dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
273                                         const char *key,
274                                         const dbus_uint16_t value)
275 {
276         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
277                                               &value);
278 }
279
280
281 /**
282  * Add a 32-bit signed integer to the dict.
283  *
284  * @param iter_dict A valid DBusMessageIter returned from
285  *    wpa_dbus_dict_open_write()
286  * @param key The key of the dict item
287  * @param value The 32-bit signed integer value
288  * @return TRUE on success, FALSE on failure
289  *
290  */
291 dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
292                                        const char *key,
293                                        const dbus_int32_t value)
294 {
295         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
296                                               &value);
297 }
298
299
300 /**
301  * Add a 32-bit unsigned integer entry to the dict.
302  *
303  * @param iter_dict A valid DBusMessageIter returned from
304  *    wpa_dbus_dict_open_write()
305  * @param key The key of the dict item
306  * @param value The 32-bit unsigned integer value
307  * @return TRUE on success, FALSE on failure
308  *
309  */
310 dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
311                                         const char *key,
312                                         const dbus_uint32_t value)
313 {
314         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
315                                               &value);
316 }
317
318
319 /**
320  * Add a 64-bit integer entry to the dict.
321  *
322  * @param iter_dict A valid DBusMessageIter returned from
323  *    wpa_dbus_dict_open_write()
324  * @param key The key of the dict item
325  * @param value The 64-bit integer value
326  * @return TRUE on success, FALSE on failure
327  *
328  */
329 dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
330                                        const char *key,
331                                        const dbus_int64_t value)
332 {
333         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
334                                               &value);
335 }
336
337
338 /**
339  * Add a 64-bit unsigned integer entry to the dict.
340  *
341  * @param iter_dict A valid DBusMessageIter returned from
342  *    wpa_dbus_dict_open_write()
343  * @param key The key of the dict item
344  * @param value The 64-bit unsigned integer value
345  * @return TRUE on success, FALSE on failure
346  *
347  */
348 dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
349                                         const char *key,
350                                         const dbus_uint64_t value)
351 {
352         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
353                                               &value);
354 }
355
356
357 /**
358  * Add a double-precision floating point entry to the dict.
359  *
360  * @param iter_dict A valid DBusMessageIter returned from
361  *    wpa_dbus_dict_open_write()
362  * @param key The key of the dict item
363  * @param value The double-precision floating point value
364  * @return TRUE on success, FALSE on failure
365  *
366  */
367 dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
368                                         const char *key, const double value)
369 {
370         return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
371                                               &value);
372 }
373
374
375 /**
376  * Add a DBus object path entry to the dict.
377  *
378  * @param iter_dict A valid DBusMessageIter returned from
379  *    wpa_dbus_dict_open_write()
380  * @param key The key of the dict item
381  * @param value The DBus object path value
382  * @return TRUE on success, FALSE on failure
383  *
384  */
385 dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
386                                              const char *key,
387                                              const char *value)
388 {
389         if (!value)
390                 return FALSE;
391         return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
392                                               DBUS_TYPE_OBJECT_PATH, &value);
393 }
394
395
396 /**
397  * Add a byte array entry to the dict.
398  *
399  * @param iter_dict A valid DBusMessageIter returned from
400  *    wpa_dbus_dict_open_write()
401  * @param key The key of the dict item
402  * @param value The byte array
403  * @param value_len The length of the byte array, in bytes
404  * @return TRUE on success, FALSE on failure
405  *
406  */
407 dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
408                                             const char *key,
409                                             const char *value,
410                                             const dbus_uint32_t value_len)
411 {
412         if (!key || (!value && value_len != 0))
413                 return FALSE;
414         return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
415                                                    value_len);
416 }
417
418
419 /**
420  * Begin an array entry in the dict
421  *
422  * @param iter_dict A valid DBusMessageIter returned from
423  *                  wpa_dbus_dict_open_write()
424  * @param key The key of the dict item
425  * @param type The type of the contained data
426  * @param iter_dict_entry A private DBusMessageIter provided by the caller to
427  *                        be passed to wpa_dbus_dict_end_string_array()
428  * @param iter_dict_val A private DBusMessageIter provided by the caller to
429  *                      be passed to wpa_dbus_dict_end_string_array()
430  * @param iter_array On return, the DBusMessageIter to be passed to
431  *                   wpa_dbus_dict_string_array_add_element()
432  * @return TRUE on success, FALSE on failure
433  *
434  */
435 dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
436                                       const char *key, const char *type,
437                                       DBusMessageIter *iter_dict_entry,
438                                       DBusMessageIter *iter_dict_val,
439                                       DBusMessageIter *iter_array)
440 {
441         char array_type[10];
442         int err;
443
444         err = os_snprintf(array_type, sizeof(array_type),
445                           DBUS_TYPE_ARRAY_AS_STRING "%s",
446                           type);
447         if (os_snprintf_error(sizeof(array_type), err))
448                 return FALSE;
449
450         if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
451             !_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
452                                             key, DBUS_TYPE_ARRAY) ||
453             !dbus_message_iter_open_container(iter_dict_entry,
454                                               DBUS_TYPE_VARIANT,
455                                               array_type,
456                                               iter_dict_val))
457                 return FALSE;
458
459         return dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
460                                                 type, iter_array);
461 }
462
463
464 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
465                                              const char *key,
466                                              DBusMessageIter *iter_dict_entry,
467                                              DBusMessageIter *iter_dict_val,
468                                              DBusMessageIter *iter_array)
469 {
470         return wpa_dbus_dict_begin_array(
471                 iter_dict, key,
472                 DBUS_TYPE_STRING_AS_STRING,
473                 iter_dict_entry, iter_dict_val, iter_array);
474 }
475
476
477 /**
478  * Add a single string element to a string array dict entry
479  *
480  * @param iter_array A valid DBusMessageIter returned from
481  *                   wpa_dbus_dict_begin_string_array()'s
482  *                   iter_array parameter
483  * @param elem The string element to be added to the dict entry's string array
484  * @return TRUE on success, FALSE on failure
485  *
486  */
487 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
488                                                    const char *elem)
489 {
490         if (!iter_array || !elem)
491                 return FALSE;
492
493         return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
494                                               &elem);
495 }
496
497
498 /**
499  * Add a single byte array element to a string array dict entry
500  *
501  * @param iter_array A valid DBusMessageIter returned from
502  *                   wpa_dbus_dict_begin_array()'s iter_array
503  *                   parameter -- note that wpa_dbus_dict_begin_array()
504  *                   must have been called with "ay" as the type
505  * @param value The data to be added to the dict entry's array
506  * @param value_len The length of the data
507  * @return TRUE on success, FALSE on failure
508  *
509  */
510 dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
511                                                 const u8 *value,
512                                                 size_t value_len)
513 {
514         DBusMessageIter iter_bytes;
515         size_t i;
516
517         if (!iter_array || !value ||
518             !dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
519                                               DBUS_TYPE_BYTE_AS_STRING,
520                                               &iter_bytes))
521                 return FALSE;
522
523         for (i = 0; i < value_len; i++) {
524                 if (!dbus_message_iter_append_basic(&iter_bytes,
525                                                     DBUS_TYPE_BYTE,
526                                                     &(value[i])))
527                         return FALSE;
528         }
529
530         return dbus_message_iter_close_container(iter_array, &iter_bytes);
531 }
532
533
534 /**
535  * End an array dict entry
536  *
537  * @param iter_dict A valid DBusMessageIter returned from
538  *                  wpa_dbus_dict_open_write()
539  * @param iter_dict_entry A private DBusMessageIter returned from
540  *                        wpa_dbus_dict_begin_string_array() or
541  *                        wpa_dbus_dict_begin_array()
542  * @param iter_dict_val A private DBusMessageIter returned from
543  *                      wpa_dbus_dict_begin_string_array() or
544  *                      wpa_dbus_dict_begin_array()
545  * @param iter_array A DBusMessageIter returned from
546  *                   wpa_dbus_dict_begin_string_array() or
547  *                   wpa_dbus_dict_begin_array()
548  * @return TRUE on success, FALSE on failure
549  *
550  */
551 dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
552                                     DBusMessageIter *iter_dict_entry,
553                                     DBusMessageIter *iter_dict_val,
554                                     DBusMessageIter *iter_array)
555 {
556         if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
557             !dbus_message_iter_close_container(iter_dict_val, iter_array))
558                 return FALSE;
559
560         return _wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
561                                             iter_dict_val);
562 }
563
564
565 /**
566  * Convenience function to add an entire string array to the dict.
567  *
568  * @param iter_dict A valid DBusMessageIter returned from
569  *                  wpa_dbus_dict_open_write()
570  * @param key The key of the dict item
571  * @param items The array of strings
572  * @param num_items The number of strings in the array
573  * @return TRUE on success, FALSE on failure
574  *
575  */
576 dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
577                                               const char *key,
578                                               const char **items,
579                                               const dbus_uint32_t num_items)
580 {
581         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
582         dbus_uint32_t i;
583
584         if (!key || (!items && num_items != 0) ||
585             !wpa_dbus_dict_begin_string_array(iter_dict, key,
586                                               &iter_dict_entry, &iter_dict_val,
587                                               &iter_array))
588                 return FALSE;
589
590         for (i = 0; i < num_items; i++) {
591                 if (!wpa_dbus_dict_string_array_add_element(&iter_array,
592                                                             items[i]))
593                         return FALSE;
594         }
595
596         return wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
597                                               &iter_dict_val, &iter_array);
598 }
599
600
601 /**
602  * Convenience function to add an wpabuf binary array to the dict.
603  *
604  * @param iter_dict A valid DBusMessageIter returned from
605  *                  wpa_dbus_dict_open_write()
606  * @param key The key of the dict item
607  * @param items The array of wpabuf structures
608  * @param num_items The number of strings in the array
609  * @return TRUE on success, FALSE on failure
610  *
611  */
612 dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
613                                               const char *key,
614                                               const struct wpabuf **items,
615                                               const dbus_uint32_t num_items)
616 {
617         DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
618         dbus_uint32_t i;
619
620         if (!key ||
621             (!items && num_items != 0) ||
622             !wpa_dbus_dict_begin_array(iter_dict, key,
623                                        DBUS_TYPE_ARRAY_AS_STRING
624                                        DBUS_TYPE_BYTE_AS_STRING,
625                                        &iter_dict_entry, &iter_dict_val,
626                                        &iter_array))
627                 return FALSE;
628
629         for (i = 0; i < num_items; i++) {
630                 if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
631                                                          wpabuf_head(items[i]),
632                                                          wpabuf_len(items[i])))
633                         return FALSE;
634         }
635
636         return wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
637                                        &iter_dict_val, &iter_array);
638 }
639
640
641 /*****************************************************/
642 /* Stuff for reading dicts                           */
643 /*****************************************************/
644
645 /**
646  * Start reading from a dbus dict.
647  *
648  * @param iter A valid DBusMessageIter pointing to the start of the dict
649  * @param iter_dict (out) A DBusMessageIter to be passed to
650  *    wpa_dbus_dict_read_next_entry()
651  * @error on failure a descriptive error
652  * @return TRUE on success, FALSE on failure
653  *
654  */
655 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
656                                     DBusMessageIter *iter_dict,
657                                     DBusError *error)
658 {
659         int type;
660
661         wpa_printf(MSG_MSGDUMP, "%s: start reading a dict entry", __func__);
662         if (!iter || !iter_dict) {
663                 dbus_set_error_const(error, DBUS_ERROR_FAILED,
664                                      "[internal] missing message iterators");
665                 return FALSE;
666         }
667
668         type = dbus_message_iter_get_arg_type(iter);
669         if (type != DBUS_TYPE_ARRAY ||
670             dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
671                 wpa_printf(MSG_DEBUG,
672                            "%s: unexpected message argument types (arg=%c element=%c)",
673                            __func__, type,
674                            type != DBUS_TYPE_ARRAY ? '?' :
675                            dbus_message_iter_get_element_type(iter));
676                 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
677                                      "unexpected message argument types");
678                 return FALSE;
679         }
680
681         dbus_message_iter_recurse(iter, iter_dict);
682         return TRUE;
683 }
684
685
686 #define BYTE_ARRAY_CHUNK_SIZE 34
687 #define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
688
689 static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
690         DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
691 {
692         dbus_uint32_t count = 0;
693         dbus_bool_t success = FALSE;
694         char *buffer, *nbuffer;
695
696         entry->bytearray_value = NULL;
697         entry->array_type = DBUS_TYPE_BYTE;
698
699         buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
700         if (!buffer)
701                 return FALSE;
702
703         entry->bytearray_value = buffer;
704         entry->array_len = 0;
705         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
706                 char byte;
707
708                 if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
709                         nbuffer = os_realloc_array(
710                                 buffer, count + BYTE_ARRAY_CHUNK_SIZE,
711                                 BYTE_ARRAY_ITEM_SIZE);
712                         if (nbuffer == NULL) {
713                                 os_free(buffer);
714                                 wpa_printf(MSG_ERROR,
715                                            "dbus: %s out of memory trying to retrieve the string array",
716                                            __func__);
717                                 goto done;
718                         }
719                         buffer = nbuffer;
720                 }
721                 entry->bytearray_value = buffer;
722
723                 dbus_message_iter_get_basic(iter, &byte);
724                 entry->bytearray_value[count] = byte;
725                 entry->array_len = ++count;
726                 dbus_message_iter_next(iter);
727         }
728         wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
729                         entry->bytearray_value, entry->array_len);
730
731         /* Zero-length arrays are valid. */
732         if (entry->array_len == 0) {
733                 os_free(entry->bytearray_value);
734                 entry->bytearray_value = NULL;
735         }
736
737         success = TRUE;
738
739 done:
740         return success;
741 }
742
743
744 #define STR_ARRAY_CHUNK_SIZE 8
745 #define STR_ARRAY_ITEM_SIZE (sizeof(char *))
746
747 static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
748         DBusMessageIter *iter, int array_type,
749         struct wpa_dbus_dict_entry *entry)
750 {
751         dbus_uint32_t count = 0;
752         dbus_bool_t success = FALSE;
753         char **buffer, **nbuffer;
754
755         entry->strarray_value = NULL;
756         entry->array_type = DBUS_TYPE_STRING;
757
758         buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
759         if (buffer == NULL)
760                 return FALSE;
761
762         entry->strarray_value = buffer;
763         entry->array_len = 0;
764         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
765                 const char *value;
766                 char *str;
767
768                 if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
769                         nbuffer = os_realloc_array(
770                                 buffer, count + STR_ARRAY_CHUNK_SIZE,
771                                 STR_ARRAY_ITEM_SIZE);
772                         if (nbuffer == NULL) {
773                                 os_free(buffer);
774                                 wpa_printf(MSG_ERROR,
775                                            "dbus: %s out of memory trying to retrieve the string array",
776                                            __func__);
777                                 goto done;
778                         }
779                         buffer = nbuffer;
780                 }
781                 entry->strarray_value = buffer;
782
783                 dbus_message_iter_get_basic(iter, &value);
784                 wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
785                            __func__, wpa_debug_show_keys ? value : "[omitted]");
786                 str = os_strdup(value);
787                 if (str == NULL) {
788                         wpa_printf(MSG_ERROR,
789                                    "dbus: %s out of memory trying to duplicate the string array",
790                                    __func__);
791                         goto done;
792                 }
793                 entry->strarray_value[count] = str;
794                 entry->array_len = ++count;
795                 dbus_message_iter_next(iter);
796         }
797         wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
798                    __func__, entry->array_len);
799
800         /* Zero-length arrays are valid. */
801         if (entry->array_len == 0) {
802                 os_free(entry->strarray_value);
803                 entry->strarray_value = NULL;
804         }
805
806         success = TRUE;
807
808 done:
809         return success;
810 }
811
812
813 #define BIN_ARRAY_CHUNK_SIZE 10
814 #define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
815
816 static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
817         DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
818 {
819         struct wpa_dbus_dict_entry tmpentry;
820         size_t buflen = 0;
821         int i, type;
822
823         entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
824         entry->array_len = 0;
825         entry->binarray_value = NULL;
826
827         type = dbus_message_iter_get_arg_type(iter);
828         wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
829         if (type == DBUS_TYPE_INVALID) {
830                 /* Likely an empty array of arrays */
831                 return TRUE;
832         }
833         if (type != DBUS_TYPE_ARRAY) {
834                 wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
835                            __func__, type);
836                 return FALSE;
837         }
838
839         type = dbus_message_iter_get_element_type(iter);
840         if (type != DBUS_TYPE_BYTE) {
841                 wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
842                            __func__, type);
843                 return FALSE;
844         }
845
846         while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
847                 DBusMessageIter iter_array;
848
849                 if (entry->array_len == buflen) {
850                         struct wpabuf **newbuf;
851
852                         buflen += BIN_ARRAY_CHUNK_SIZE;
853
854                         newbuf = os_realloc_array(entry->binarray_value,
855                                                   buflen, BIN_ARRAY_ITEM_SIZE);
856                         if (!newbuf)
857                                 goto cleanup;
858                         entry->binarray_value = newbuf;
859                 }
860
861                 dbus_message_iter_recurse(iter, &iter_array);
862                 os_memset(&tmpentry, 0, sizeof(tmpentry));
863                 tmpentry.type = DBUS_TYPE_ARRAY;
864                 if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
865                     == FALSE)
866                         goto cleanup;
867
868                 entry->binarray_value[entry->array_len] =
869                         wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
870                                               tmpentry.array_len);
871                 if (entry->binarray_value[entry->array_len] == NULL) {
872                         wpa_dbus_dict_entry_clear(&tmpentry);
873                         goto cleanup;
874                 }
875                 entry->array_len++;
876                 dbus_message_iter_next(iter);
877         }
878         wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
879                    __func__, entry->array_len);
880
881         return TRUE;
882
883  cleanup:
884         for (i = 0; i < (int) entry->array_len; i++)
885                 wpabuf_free(entry->binarray_value[i]);
886         os_free(entry->binarray_value);
887         entry->array_len = 0;
888         entry->binarray_value = NULL;
889         return FALSE;
890 }
891
892
893 static dbus_bool_t _wpa_dbus_dict_entry_get_array(
894         DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
895 {
896         int array_type = dbus_message_iter_get_element_type(iter_dict_val);
897         dbus_bool_t success = FALSE;
898         DBusMessageIter iter_array;
899
900         wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
901
902         dbus_message_iter_recurse(iter_dict_val, &iter_array);
903
904         switch (array_type) {
905         case DBUS_TYPE_BYTE:
906                 success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
907                                                               entry);
908                 break;
909         case DBUS_TYPE_STRING:
910                 success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
911                                                                 array_type,
912                                                                 entry);
913                 break;
914         case DBUS_TYPE_ARRAY:
915                 success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
916                 break;
917         default:
918                 wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
919                            __func__, array_type);
920                 break;
921         }
922
923         return success;
924 }
925
926
927 static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
928         struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter)
929 {
930         const char *v;
931
932         switch (entry->type) {
933         case DBUS_TYPE_OBJECT_PATH:
934                 dbus_message_iter_get_basic(iter, &v);
935                 wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
936                            __func__, v);
937                 entry->str_value = os_strdup(v);
938                 if (entry->str_value == NULL)
939                         return FALSE;
940                 break;
941         case DBUS_TYPE_STRING:
942                 dbus_message_iter_get_basic(iter, &v);
943                 wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
944                            __func__, wpa_debug_show_keys ? v : "[omitted]");
945                 entry->str_value = os_strdup(v);
946                 if (entry->str_value == NULL)
947                         return FALSE;
948                 break;
949         case DBUS_TYPE_BOOLEAN:
950                 dbus_message_iter_get_basic(iter, &entry->bool_value);
951                 wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
952                            __func__, entry->bool_value);
953                 break;
954         case DBUS_TYPE_BYTE:
955                 dbus_message_iter_get_basic(iter, &entry->byte_value);
956                 wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
957                            __func__, entry->byte_value);
958                 break;
959         case DBUS_TYPE_INT16:
960                 dbus_message_iter_get_basic(iter, &entry->int16_value);
961                 wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
962                            __func__, entry->int16_value);
963                 break;
964         case DBUS_TYPE_UINT16:
965                 dbus_message_iter_get_basic(iter, &entry->uint16_value);
966                 wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
967                            __func__, entry->uint16_value);
968                 break;
969         case DBUS_TYPE_INT32:
970                 dbus_message_iter_get_basic(iter, &entry->int32_value);
971                 wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
972                            __func__, entry->int32_value);
973                 break;
974         case DBUS_TYPE_UINT32:
975                 dbus_message_iter_get_basic(iter, &entry->uint32_value);
976                 wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
977                            __func__, entry->uint32_value);
978                 break;
979         case DBUS_TYPE_INT64:
980                 dbus_message_iter_get_basic(iter, &entry->int64_value);
981                 wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
982                            __func__, (long long int) entry->int64_value);
983                 break;
984         case DBUS_TYPE_UINT64:
985                 dbus_message_iter_get_basic(iter, &entry->uint64_value);
986                 wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
987                            __func__,
988                            (unsigned long long int) entry->uint64_value);
989                 break;
990         case DBUS_TYPE_DOUBLE:
991                 dbus_message_iter_get_basic(iter, &entry->double_value);
992                 wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
993                            __func__, entry->double_value);
994                 break;
995         case DBUS_TYPE_ARRAY:
996                 return _wpa_dbus_dict_entry_get_array(iter, entry);
997         default:
998                 wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
999                            __func__, entry->type);
1000                 return FALSE;
1001         }
1002
1003         return TRUE;
1004 }
1005
1006
1007 /**
1008  * Read the current key/value entry from the dict.  Entries are dynamically
1009  * allocated when needed and must be freed after use with the
1010  * wpa_dbus_dict_entry_clear() function.
1011  *
1012  * The returned entry object will be filled with the type and value of the next
1013  * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
1014  * occurred.
1015  *
1016  * @param iter_dict A valid DBusMessageIter returned from
1017  *    wpa_dbus_dict_open_read()
1018  * @param entry A valid dict entry object into which the dict key and value
1019  *    will be placed
1020  * @return TRUE on success, FALSE on failure
1021  *
1022  */
1023 dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
1024                                     struct wpa_dbus_dict_entry * entry)
1025 {
1026         DBusMessageIter iter_dict_entry, iter_dict_val;
1027         int type;
1028         const char *key;
1029
1030         if (!iter_dict || !entry ||
1031             dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
1032                 wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
1033                 goto error;
1034         }
1035
1036         dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
1037         dbus_message_iter_get_basic(&iter_dict_entry, &key);
1038         wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
1039         entry->key = key;
1040
1041         if (!dbus_message_iter_next(&iter_dict_entry)) {
1042                 wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
1043                 goto error;
1044         }
1045         type = dbus_message_iter_get_arg_type(&iter_dict_entry);
1046         if (type != DBUS_TYPE_VARIANT) {
1047                 wpa_printf(MSG_DEBUG,
1048                            "%s: unexpected dict entry variant type: %c",
1049                            __func__, type);
1050                 goto error;
1051         }
1052
1053         dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
1054         entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
1055         wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
1056                    __func__, entry->type);
1057         entry->array_type = DBUS_TYPE_INVALID;
1058         if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
1059                 wpa_printf(MSG_DEBUG,
1060                            "%s: failed to fetch dict values from variant",
1061                            __func__);
1062                 goto error;
1063         }
1064
1065         dbus_message_iter_next(iter_dict);
1066         return TRUE;
1067
1068 error:
1069         if (entry) {
1070                 wpa_dbus_dict_entry_clear(entry);
1071                 entry->type = DBUS_TYPE_INVALID;
1072                 entry->array_type = DBUS_TYPE_INVALID;
1073         }
1074
1075         return FALSE;
1076 }
1077
1078
1079 /**
1080  * Return whether or not there are additional dictionary entries.
1081  *
1082  * @param iter_dict A valid DBusMessageIter returned from
1083  *    wpa_dbus_dict_open_read()
1084  * @return TRUE if more dict entries exists, FALSE if no more dict entries
1085  * exist
1086  */
1087 dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
1088 {
1089         if (!iter_dict)
1090                 return FALSE;
1091         return dbus_message_iter_get_arg_type(iter_dict) ==
1092                 DBUS_TYPE_DICT_ENTRY;
1093 }
1094
1095
1096 /**
1097  * Free any memory used by the entry object.
1098  *
1099  * @param entry The entry object
1100  */
1101 void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
1102 {
1103         unsigned int i;
1104
1105         if (!entry)
1106                 return;
1107         switch (entry->type) {
1108         case DBUS_TYPE_OBJECT_PATH:
1109         case DBUS_TYPE_STRING:
1110                 os_free(entry->str_value);
1111                 break;
1112         case DBUS_TYPE_ARRAY:
1113                 switch (entry->array_type) {
1114                 case DBUS_TYPE_BYTE:
1115                         os_free(entry->bytearray_value);
1116                         break;
1117                 case DBUS_TYPE_STRING:
1118                         for (i = 0; i < entry->array_len; i++)
1119                                 os_free(entry->strarray_value[i]);
1120                         os_free(entry->strarray_value);
1121                         break;
1122                 case WPAS_DBUS_TYPE_BINARRAY:
1123                         for (i = 0; i < entry->array_len; i++)
1124                                 wpabuf_free(entry->binarray_value[i]);
1125                         os_free(entry->binarray_value);
1126                         break;
1127                 }
1128                 break;
1129         }
1130
1131         os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
1132 }