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