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