Home | History | Annotate | Download | only in dbus
      1 /*
      2  * WPA Supplicant / dbus-based control interface (P2P)
      3  *
      4  * This program is free software; you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License version 2 as
      6  * published by the Free Software Foundation.
      7  *
      8  * Alternatively, this software may be distributed under the terms of BSD
      9  * license.
     10  *
     11  * See README and COPYING for more details.
     12  */
     13 
     14 #include "includes.h"
     15 
     16 #include "utils/includes.h"
     17 #include "common.h"
     18 #include "../config.h"
     19 #include "../wpa_supplicant_i.h"
     20 #include "../wps_supplicant.h"
     21 #include "../notify.h"
     22 #include "dbus_new_helpers.h"
     23 #include "dbus_new.h"
     24 #include "dbus_new_handlers.h"
     25 #include "dbus_new_handlers_p2p.h"
     26 #include "dbus_dict_helpers.h"
     27 #include "p2p/p2p.h"
     28 #include "common/ieee802_11_defs.h"
     29 #include "ap/hostapd.h"
     30 #include "ap/ap_config.h"
     31 #include "ap/wps_hostapd.h"
     32 
     33 #include "../p2p_supplicant.h"
     34 
     35 /**
     36  * Parses out the mac address from the peer object path.
     37  * @peer_path - object path of the form
     38  *	/fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
     39  * @addr - out param must be of ETH_ALEN size
     40  * Returns 0 if valid (including MAC), -1 otherwise
     41  */
     42 static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
     43 {
     44 	char *p;
     45 
     46 	if (!peer_path)
     47 		return -1;
     48 	p = strrchr(peer_path, '/');
     49 	if (!p)
     50 		return -1;
     51 	p++;
     52 	return hwaddr_compact_aton(p, addr);
     53 }
     54 
     55 
     56 /**
     57  * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
     58  * error message
     59  * @message: Pointer to incoming dbus message this error refers to
     60  * Returns: a dbus error message
     61  *
     62  * Convenience function to create and return an invalid persistent group error.
     63  */
     64 static DBusMessage * wpas_dbus_error_persistent_group_unknown(
     65 	DBusMessage *message)
     66 {
     67 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
     68 				      "There is no such persistent group in "
     69 				      "this P2P device.");
     70 }
     71 
     72 
     73 DBusMessage *wpas_dbus_handler_p2p_find(DBusMessage * message,
     74 					struct wpa_supplicant * wpa_s)
     75 {
     76 	struct wpa_dbus_dict_entry entry;
     77 	DBusMessage *reply = NULL;
     78 	DBusMessageIter iter;
     79 	DBusMessageIter iter_dict;
     80 	unsigned int timeout = 0;
     81 	unsigned int searchonly = 0;
     82 	enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
     83 	int num_req_dev_types = 0;
     84 	unsigned int i;
     85 	u8 *req_dev_types = NULL;
     86 
     87 	dbus_message_iter_init(message, &iter);
     88 
     89 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
     90 		goto error;
     91 
     92 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
     93 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
     94 			goto error;
     95 
     96 		if (!os_strcmp(entry.key, "Timeout") &&
     97 		    (entry.type == DBUS_TYPE_INT32)) {
     98 			timeout = entry.uint32_value;
     99 		} else if (!os_strcmp(entry.key, "SearchOnly") &&
    100 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
    101 			searchonly = (entry.bool_value == TRUE) ? 1 : 0;
    102 		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
    103 			if ((entry.type != DBUS_TYPE_ARRAY) ||
    104 			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
    105 				goto error_clear;
    106 
    107 			req_dev_types =
    108 				os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
    109 			if (!req_dev_types)
    110 				goto error_clear;
    111 
    112 			for (i = 0; i < entry.array_len; i++) {
    113 				if (wpabuf_len(entry.binarray_value[i]) !=
    114 							WPS_DEV_TYPE_LEN)
    115 					goto error_clear;
    116 				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
    117 					  wpabuf_head(entry.binarray_value[i]),
    118 					  WPS_DEV_TYPE_LEN);
    119 			}
    120 
    121 			num_req_dev_types = entry.array_len;
    122 		} else
    123 			goto error_clear;
    124 		wpa_dbus_dict_entry_clear(&entry);
    125 	}
    126 
    127 	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
    128 	return reply;
    129 
    130 error_clear:
    131 	os_free(req_dev_types);
    132 	wpa_dbus_dict_entry_clear(&entry);
    133 error:
    134 	reply = wpas_dbus_error_invalid_args(message, entry.key);
    135 	return reply;
    136 }
    137 
    138 DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message,
    139 					     struct wpa_supplicant * wpa_s)
    140 {
    141 	wpas_p2p_stop_find(wpa_s);
    142 	return NULL;
    143 }
    144 
    145 DBusMessage *wpas_dbus_handler_p2p_rejectpeer(DBusMessage * message,
    146 					      struct wpa_supplicant * wpa_s)
    147 {
    148 	DBusMessageIter iter;
    149 	char *peer_object_path = NULL;
    150 	u8 peer_addr[ETH_ALEN];
    151 
    152 	dbus_message_iter_init(message, &iter);
    153 	dbus_message_iter_get_basic(&iter, &peer_object_path);
    154 
    155 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
    156 		return wpas_dbus_error_invalid_args(message, NULL);
    157 
    158 	if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
    159 		return wpas_dbus_error_unknown_error(message,
    160 				"Failed to call wpas_p2p_reject method.");
    161 
    162 	return NULL;
    163 }
    164 
    165 DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message,
    166 					  struct wpa_supplicant * wpa_s)
    167 {
    168 	dbus_int32_t timeout = 0;
    169 
    170 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
    171 				   DBUS_TYPE_INVALID))
    172 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
    173 					      NULL);
    174 
    175 	if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
    176 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
    177 					      NULL);
    178 
    179 	return NULL;
    180 }
    181 
    182 DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message,
    183 						  struct wpa_supplicant * wpa_s)
    184 {
    185 	unsigned int period = 0, interval = 0;
    186 	struct wpa_dbus_dict_entry entry;
    187 	DBusMessageIter iter;
    188 	DBusMessageIter iter_dict;
    189 
    190 	dbus_message_iter_init(message, &iter);
    191 
    192 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
    193 		goto error;
    194 
    195 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    196 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    197 			goto error;
    198 
    199 		if (!strcmp(entry.key, "period") &&
    200 		    (entry.type == DBUS_TYPE_INT32))
    201 			period = entry.uint32_value;
    202 		else if (!strcmp(entry.key, "interval") &&
    203 			 (entry.type == DBUS_TYPE_INT32))
    204 			interval = entry.uint32_value;
    205 		else
    206 			goto error_clear;
    207 		wpa_dbus_dict_entry_clear(&entry);
    208 	}
    209 
    210 	if (wpas_p2p_ext_listen(wpa_s, period, interval))
    211 		return wpas_dbus_error_unknown_error(message,
    212 					"failed to initiate a p2p_ext_listen.");
    213 
    214 	return NULL;
    215 
    216 error_clear:
    217 	wpa_dbus_dict_entry_clear(&entry);
    218 error:
    219 	return wpas_dbus_error_invalid_args(message, entry.key);
    220 }
    221 
    222 DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message,
    223 						    struct wpa_supplicant *
    224 						    wpa_s)
    225 {
    226 	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
    227 	struct wpa_dbus_dict_entry entry;
    228 	DBusMessageIter iter;
    229 	DBusMessageIter iter_dict;
    230 
    231 	dbus_message_iter_init(message, &iter);
    232 
    233 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
    234 		goto error;
    235 
    236 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    237 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    238 			goto error;
    239 
    240 		if (!strcmp(entry.key, "duration1") &&
    241 		    (entry.type == DBUS_TYPE_INT32))
    242 			dur1 = entry.uint32_value;
    243 		else if (!strcmp(entry.key, "interval1") &&
    244 			 entry.type == DBUS_TYPE_INT32)
    245 			int1 = entry.uint32_value;
    246 		else if (!strcmp(entry.key, "duration2") &&
    247 			 entry.type == DBUS_TYPE_INT32)
    248 			dur2 = entry.uint32_value;
    249 		else if (!strcmp(entry.key, "interval2") &&
    250 			 entry.type == DBUS_TYPE_INT32)
    251 			int2 = entry.uint32_value;
    252 		else
    253 			goto error_clear;
    254 
    255 		wpa_dbus_dict_entry_clear(&entry);
    256 	}
    257 	if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
    258 		return wpas_dbus_error_unknown_error(message,
    259 				"Failed to invoke presence request.");
    260 
    261 	return NULL;
    262 
    263 error_clear:
    264 	wpa_dbus_dict_entry_clear(&entry);
    265 error:
    266 	return wpas_dbus_error_invalid_args(message, entry.key);
    267 }
    268 
    269 DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message,
    270 					     struct wpa_supplicant * wpa_s)
    271 {
    272 	DBusMessageIter iter_dict;
    273 	DBusMessage *reply = NULL;
    274 	DBusMessageIter iter;
    275 	struct wpa_dbus_dict_entry entry;
    276 	char *pg_object_path = NULL;
    277 	int persistent_group = 0;
    278 	int freq = 0;
    279 	char *iface = NULL;
    280 	char *net_id_str = NULL;
    281 	unsigned int group_id = 0;
    282 	struct wpa_ssid *ssid;
    283 
    284 	dbus_message_iter_init(message, &iter);
    285 
    286 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
    287 		goto inv_args;
    288 
    289 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    290 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    291 			goto inv_args;
    292 
    293 		if (!strcmp(entry.key, "persistent") &&
    294 		    (entry.type == DBUS_TYPE_BOOLEAN)) {
    295 			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
    296 		} else if (!strcmp(entry.key, "frequency") &&
    297 			   (entry.type == DBUS_TYPE_INT32)) {
    298 			freq = entry.int32_value;
    299 			if (freq <= 0)
    300 				goto inv_args_clear;
    301 		} else if (!strcmp(entry.key, "persistent_group_object") &&
    302 			   entry.type == DBUS_TYPE_OBJECT_PATH)
    303 			pg_object_path = os_strdup(entry.str_value);
    304 		else
    305 			goto inv_args_clear;
    306 
    307 		wpa_dbus_dict_entry_clear(&entry);
    308 	}
    309 
    310 	if (pg_object_path != NULL) {
    311 		/*
    312 		 * A persistent group Object Path is defined meaning we want
    313 		 * to re-invoke a persistent group.
    314 		 */
    315 
    316 		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
    317 							    &net_id_str, NULL);
    318 		if (iface == NULL ||
    319 		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
    320 			reply =
    321 			    wpas_dbus_error_invalid_args(message,
    322 							 pg_object_path);
    323 			goto out;
    324 		}
    325 
    326 		group_id = strtoul(net_id_str, NULL, 10);
    327 		if (errno == EINVAL) {
    328 			reply = wpas_dbus_error_invalid_args(
    329 						message, pg_object_path);
    330 			goto out;
    331 		}
    332 
    333 		/* Get the SSID structure form the persistant group id */
    334 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
    335 		if (ssid == NULL || ssid->disabled != 2)
    336 			goto inv_args;
    337 
    338 		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
    339 			reply = wpas_dbus_error_unknown_error(message,
    340 							      "Failed to reinvoke a persistent group");
    341 			goto out;
    342 		}
    343 	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
    344 		goto inv_args;
    345 
    346 out:
    347 	os_free(pg_object_path);
    348 	os_free(net_id_str);
    349 	os_free(iface);
    350 	return reply;
    351 inv_args_clear:
    352 	wpa_dbus_dict_entry_clear(&entry);
    353 inv_args:
    354 	reply = wpas_dbus_error_invalid_args(message, NULL);
    355 	goto out;
    356 }
    357 
    358 DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
    359 					      struct wpa_supplicant *wpa_s)
    360 {
    361 	if (wpas_p2p_disconnect(wpa_s))
    362 		return wpas_dbus_error_unknown_error(message,
    363 						"failed to disconnect");
    364 
    365 	return NULL;
    366 }
    367 
    368 DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message,
    369 					 struct wpa_supplicant * wpa_s)
    370 {
    371 	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
    372 	wpa_s->force_long_sd = 0;
    373 	p2p_flush(wpa_s->global->p2p);
    374 
    375 	return NULL;
    376 }
    377 
    378 DBusMessage *wpas_dbus_handler_p2p_connect(DBusMessage * message,
    379 					   struct wpa_supplicant * wpa_s)
    380 {
    381 	DBusMessageIter iter_dict;
    382 	DBusMessage *reply = NULL;
    383 	DBusMessageIter iter;
    384 	struct wpa_dbus_dict_entry entry;
    385 	char *peer_object_path = NULL;
    386 	int persistent_group = 0;
    387 	int join = 0;
    388 	int authorize_only = 0;
    389 	int go_intent = -1;
    390 	int freq = 0;
    391 	u8 addr[ETH_ALEN];
    392 	char *pin = NULL;
    393 	enum p2p_wps_method wps_method = WPS_NOT_READY;
    394 	int new_pin;
    395 	char *err_msg = NULL;
    396 	char *iface = NULL;
    397 
    398 	dbus_message_iter_init(message, &iter);
    399 
    400 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
    401 		goto inv_args;
    402 
    403 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    404 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    405 			goto inv_args;
    406 
    407 		if (!strcmp(entry.key, "peer") &&
    408 		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
    409 			peer_object_path = os_strdup(entry.str_value);
    410 		} else if (!strcmp(entry.key, "persistent") &&
    411 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
    412 			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
    413 		} else if (!strcmp(entry.key, "join") &&
    414 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
    415 			join = (entry.bool_value == TRUE) ? 1 : 0;
    416 		} else if (!strcmp(entry.key, "authorize_only") &&
    417 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
    418 			authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
    419 		} else if (!strcmp(entry.key, "frequency") &&
    420 			   (entry.type == DBUS_TYPE_INT32)) {
    421 			freq = entry.int32_value;
    422 			if (freq <= 0)
    423 				goto inv_args_clear;
    424 		} else if (!strcmp(entry.key, "go_intent") &&
    425 			   (entry.type == DBUS_TYPE_INT32)) {
    426 			go_intent = entry.int32_value;
    427 			if ((go_intent < 0) || (go_intent > 15))
    428 				goto inv_args_clear;
    429 		} else if (!strcmp(entry.key, "wps_method") &&
    430 			   (entry.type == DBUS_TYPE_STRING)) {
    431 			if (!strcmp(entry.str_value, "pbc"))
    432 				wps_method = WPS_PBC;
    433 			else if (!strcmp(entry.str_value, "pin"))
    434 				wps_method = WPS_PIN_DISPLAY;
    435 			else if (!strcmp(entry.str_value, "label"))
    436 				wps_method = WPS_PIN_LABEL;
    437 			else if (!strcmp(entry.str_value, "display"))
    438 				wps_method = WPS_PIN_DISPLAY;
    439 			else if (!strcmp(entry.str_value, "keypad"))
    440 				wps_method = WPS_PIN_KEYPAD;
    441 			else
    442 				goto inv_args_clear;
    443 		} else if (!strcmp(entry.key, "pin") &&
    444 			   (entry.type == DBUS_TYPE_STRING)) {
    445 			pin = os_strdup(entry.str_value);
    446 		} else
    447 			goto inv_args_clear;
    448 
    449 		wpa_dbus_dict_entry_clear(&entry);
    450 	}
    451 
    452 	if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
    453 	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
    454 	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) {
    455 		reply = wpas_dbus_error_invalid_args(message, NULL);
    456 		goto inv_args;
    457 	}
    458 
    459 	/*
    460 	 * Validate the wps_method specified and the pin value.
    461 	 */
    462 	if ((!pin || !pin[0]) &&
    463 	    ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
    464 		goto inv_args;
    465 
    466 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
    467 				   persistent_group, join, authorize_only,
    468 				   go_intent, freq);
    469 
    470 	if (new_pin >= 0) {
    471 		reply = dbus_message_new_method_return(message);
    472 		dbus_message_append_args(reply, DBUS_TYPE_INT32,
    473 					 &new_pin, DBUS_TYPE_INVALID);
    474 	} else {
    475 		switch (new_pin) {
    476 		case -2:
    477 			err_msg = "connect failed due to"
    478 					" channel unavailability.";
    479 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
    480 			break;
    481 
    482 		case -3:
    483 			err_msg = "connect failed due to"
    484 					" unsupported channel.";
    485 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
    486 			break;
    487 
    488 		default:
    489 			err_msg = "connect failed due to"
    490 					" unspecified error.";
    491 			iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
    492 			break;
    493 		}
    494 		/*
    495 		 * TODO::
    496 		 * Do we need specialized errors corresponding to above
    497 		 * error conditions as against just returning a different
    498 		 * error message?
    499 		 */
    500 		reply = dbus_message_new_error(message, iface, err_msg);
    501 	}
    502 
    503 out:
    504 	os_free(peer_object_path);
    505 	os_free(pin);
    506 	return reply;
    507 inv_args_clear:
    508 	wpa_dbus_dict_entry_clear(&entry);
    509 inv_args:
    510 	reply = wpas_dbus_error_invalid_args(message, NULL);
    511 	goto out;
    512 }
    513 
    514 DBusMessage *wpas_dbus_handler_p2p_invite(DBusMessage * message,
    515 					  struct wpa_supplicant *wpa_s)
    516 {
    517 	DBusMessageIter iter_dict;
    518 	DBusMessage *reply = NULL;
    519 	DBusMessageIter iter;
    520 	struct wpa_dbus_dict_entry entry;
    521 	char *peer_object_path = NULL;
    522 	char *pg_object_path = NULL;
    523 	char *iface = NULL;
    524 	char *net_id_str = NULL;
    525 	u8 peer_addr[ETH_ALEN];
    526 	unsigned int group_id = 0;
    527 	int persistent = 0;
    528 	struct wpa_ssid *ssid;
    529 
    530 	dbus_message_iter_init(message, &iter);
    531 
    532 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
    533 		goto err;
    534 
    535 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    536 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    537 			goto err;
    538 
    539 		if (!strcmp(entry.key, "peer") &&
    540 		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
    541 			peer_object_path = os_strdup(entry.str_value);
    542 			wpa_dbus_dict_entry_clear(&entry);
    543 		} else if (!strcmp(entry.key, "persistent_group_object") &&
    544 			   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
    545 			pg_object_path = os_strdup(entry.str_value);
    546 			persistent = 1;
    547 			wpa_dbus_dict_entry_clear(&entry);
    548 		} else {
    549 			wpa_dbus_dict_entry_clear(&entry);
    550 			goto err;
    551 		}
    552 	}
    553 
    554 	if (!peer_object_path ||
    555 	    (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
    556 	    (p2p_get_peer_info(wpa_s->global->p2p,
    557 			       peer_addr, 0, NULL, 0) < 0)) {
    558 		goto err;
    559 	}
    560 
    561 	if (persistent) {
    562 		/*
    563 		 * A group ID is defined meaning we want to re-invoke a
    564 		 * persisatnt group
    565 		 */
    566 
    567 		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
    568 							    &net_id_str, NULL);
    569 		if (iface == NULL ||
    570 		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
    571 			reply =
    572 			    wpas_dbus_error_invalid_args(message,
    573 							 pg_object_path);
    574 			goto out;
    575 		}
    576 
    577 		group_id = strtoul(net_id_str, NULL, 10);
    578 		if (errno == EINVAL) {
    579 			reply = wpas_dbus_error_invalid_args(
    580 						message, pg_object_path);
    581 			goto out;
    582 		}
    583 
    584 		/* Get the SSID structure form the persistant group id */
    585 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
    586 		if (ssid == NULL || ssid->disabled != 2)
    587 			goto err;
    588 
    589 		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
    590 			reply = wpas_dbus_error_unknown_error(
    591 					message,
    592 					"Failed to reinvoke a persistent group");
    593 			goto out;
    594 		}
    595 	} else {
    596 		/*
    597 		 * No group ID means propose to a peer to join my active group
    598 		 */
    599 		if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
    600 					 peer_addr, NULL)) {
    601 			reply = wpas_dbus_error_unknown_error(
    602 					message,
    603 					"Failed to join to an active group");
    604 			goto out;
    605 		}
    606 	}
    607 
    608 out:
    609 	os_free(pg_object_path);
    610 	os_free(peer_object_path);
    611 	return reply;
    612 
    613 err:
    614 	reply = wpas_dbus_error_invalid_args(message, NULL);
    615 	goto out;
    616 }
    617 
    618 DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message,
    619 						 struct wpa_supplicant *wpa_s)
    620 {
    621 	DBusMessageIter iter;
    622 	char *peer_object_path = NULL;
    623 	char *config_method = NULL;
    624 	u8 peer_addr[ETH_ALEN];
    625 
    626 	dbus_message_iter_init(message, &iter);
    627 	dbus_message_iter_get_basic(&iter, &peer_object_path);
    628 
    629 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
    630 		return wpas_dbus_error_invalid_args(message, NULL);
    631 
    632 	dbus_message_iter_next(&iter);
    633 	dbus_message_iter_get_basic(&iter, &config_method);
    634 
    635 	/*
    636 	 * Validation checks on config_method are being duplicated here
    637 	 * to be able to return invalid args reply since the error code
    638 	 * from p2p module are not granular enough (yet).
    639 	 */
    640 	if (os_strcmp(config_method, "display") &&
    641 	    os_strcmp(config_method, "keypad") &&
    642 	    os_strcmp(config_method, "pbc") &&
    643 	    os_strcmp(config_method, "pushbutton"))
    644 		return wpas_dbus_error_invalid_args(message, NULL);
    645 
    646 	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
    647 		return wpas_dbus_error_unknown_error(message,
    648 				"Failed to send provision discovery request");
    649 
    650 	return NULL;
    651 }
    652 
    653 /*
    654  * P2P Device property accessor methods.
    655  */
    656 
    657 DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message,
    658 						    struct wpa_supplicant *
    659 						    wpa_s)
    660 {
    661 	DBusMessage *reply = NULL;
    662 	DBusMessageIter iter, variant_iter, dict_iter;
    663 	DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
    664 		iter_secdev_dict_array;
    665 	const char *dev_name;
    666 	int num_vendor_extensions = 0;
    667 	int i;
    668 	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
    669 
    670 	if (message == NULL)
    671 		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
    672 	else
    673 		reply = dbus_message_new_method_return(message);
    674 
    675 	if (!reply)
    676 		goto err_no_mem;
    677 
    678 	dbus_message_iter_init_append(reply, &iter);
    679 
    680 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
    681 					      "a{sv}", &variant_iter) ||
    682 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
    683 		goto err_no_mem;
    684 
    685 	/* DeviceName */
    686 	dev_name = wpa_s->conf->device_name;
    687 	if (dev_name &&
    688 	    !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
    689 		goto err_no_mem;
    690 
    691 	/* Primary device type */
    692 	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
    693 	    				     (char *)wpa_s->conf->device_type,
    694 	    				     WPS_DEV_TYPE_LEN))
    695 		goto err_no_mem;
    696 
    697 	/* Secondary device types */
    698 	if (wpa_s->conf->num_sec_device_types) {
    699 		if (!wpa_dbus_dict_begin_array(&dict_iter,
    700 					       "SecondaryDeviceTypes",
    701 					       DBUS_TYPE_ARRAY_AS_STRING
    702 					       DBUS_TYPE_BYTE_AS_STRING,
    703 					       &iter_secdev_dict_entry,
    704 					       &iter_secdev_dict_val,
    705 					       &iter_secdev_dict_array))
    706 			goto err_no_mem;
    707 
    708 		for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
    709 			wpa_dbus_dict_bin_array_add_element(
    710 				&iter_secdev_dict_array,
    711 				wpa_s->conf->sec_device_type[i],
    712 				WPS_DEV_TYPE_LEN);
    713 
    714 		if (!wpa_dbus_dict_end_array(&dict_iter,
    715 					     &iter_secdev_dict_entry,
    716 					     &iter_secdev_dict_val,
    717 					     &iter_secdev_dict_array))
    718 			goto err_no_mem;
    719 	}
    720 
    721 	/* Vendor Extensions */
    722 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
    723 		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
    724 			continue;
    725 		vendor_ext[num_vendor_extensions++] =
    726 			wpa_s->conf->wps_vendor_ext[i];
    727 	}
    728 
    729 	if (num_vendor_extensions &&
    730 	    !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
    731 					       "VendorExtension",
    732 					       vendor_ext,
    733 					       num_vendor_extensions))
    734 		goto err_no_mem;
    735 
    736 	/* GO Intent */
    737 	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
    738 					 wpa_s->conf->p2p_go_intent))
    739 		goto err_no_mem;
    740 
    741 	/* Persistant Reconnect */
    742 	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
    743 				       wpa_s->conf->persistent_reconnect))
    744 		goto err_no_mem;
    745 
    746 	/* Listen Reg Class */
    747 	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
    748 					 wpa_s->conf->p2p_listen_reg_class))
    749 		goto err_no_mem;
    750 
    751 	/* Listen Channel */
    752 	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
    753 					 wpa_s->conf->p2p_listen_channel))
    754 		goto err_no_mem;
    755 
    756 	/* Oper Reg Class */
    757 	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
    758 					 wpa_s->conf->p2p_oper_reg_class))
    759 		goto err_no_mem;
    760 
    761 	/* Oper Channel */
    762 	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
    763 					 wpa_s->conf->p2p_oper_channel))
    764 		goto err_no_mem;
    765 
    766 	/* SSID Postfix */
    767 	if (wpa_s->conf->p2p_ssid_postfix &&
    768 	    !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
    769 					 wpa_s->conf->p2p_ssid_postfix))
    770 		goto err_no_mem;
    771 
    772 	/* Intra Bss */
    773 	if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
    774 				       wpa_s->conf->p2p_intra_bss))
    775 		goto err_no_mem;
    776 
    777 	/* Group Idle */
    778 	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
    779 					 wpa_s->conf->p2p_group_idle))
    780 		goto err_no_mem;
    781 
    782 	/* Dissasociation low ack */
    783 	if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
    784 					 wpa_s->conf->disassoc_low_ack))
    785 		goto err_no_mem;
    786 
    787 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
    788 	    !dbus_message_iter_close_container(&iter, &variant_iter))
    789 		goto err_no_mem;
    790 
    791 	return reply;
    792 err_no_mem:
    793 	dbus_message_unref(reply);
    794 	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
    795 }
    796 
    797 DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
    798 						    struct wpa_supplicant *
    799 						    wpa_s)
    800 {
    801 	DBusMessage *reply = NULL;
    802 	DBusMessageIter iter, variant_iter;
    803 	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
    804 	DBusMessageIter iter_dict;
    805 	unsigned int i;
    806 
    807 	dbus_message_iter_init(message, &iter);
    808 
    809 	dbus_message_iter_next(&iter);
    810 	dbus_message_iter_next(&iter);
    811 
    812 	dbus_message_iter_recurse(&iter, &variant_iter);
    813 
    814 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
    815 		return wpas_dbus_error_invalid_args(message, NULL);
    816 
    817 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    818 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    819 			return wpas_dbus_error_invalid_args(message, NULL);
    820 
    821 		if (os_strcmp(entry.key, "DeviceName") == 0) {
    822 			char *devname;
    823 
    824 			if (entry.type != DBUS_TYPE_STRING)
    825 				goto error_clear;
    826 
    827 			devname = os_strdup(entry.str_value);
    828 			if (devname == NULL)
    829 				goto err_no_mem_clear;
    830 
    831 			os_free(wpa_s->conf->device_name);
    832 			wpa_s->conf->device_name = devname;
    833 
    834 			wpa_s->conf->changed_parameters |=
    835 							CFG_CHANGED_DEVICE_NAME;
    836 		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
    837 			if (entry.type != DBUS_TYPE_ARRAY ||
    838 			    entry.array_type != DBUS_TYPE_BYTE ||
    839 			    entry.array_len != WPS_DEV_TYPE_LEN)
    840 				goto error_clear;
    841 
    842 			os_memcpy(wpa_s->conf->device_type,
    843 				  entry.bytearray_value,
    844 				  WPS_DEV_TYPE_LEN);
    845 			wpa_s->conf->changed_parameters |=
    846 				CFG_CHANGED_DEVICE_TYPE;
    847 		} else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
    848 			if (entry.type != DBUS_TYPE_ARRAY ||
    849 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
    850 			    entry.array_len > MAX_SEC_DEVICE_TYPES)
    851 				goto error;
    852 
    853 			for (i = 0; i < entry.array_len; i++)
    854 				if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
    855 					goto err_no_mem_clear;
    856 			for (i = 0; i < entry.array_len; i++)
    857 				os_memcpy(wpa_s->conf->sec_device_type[i],
    858 					  wpabuf_head(entry.binarray_value[i]),
    859 					  WPS_DEV_TYPE_LEN);
    860 			wpa_s->conf->num_sec_device_types = entry.array_len;
    861 			wpa_s->conf->changed_parameters |=
    862 					CFG_CHANGED_SEC_DEVICE_TYPE;
    863 		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
    864 			if ((entry.type != DBUS_TYPE_ARRAY) ||
    865 			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
    866 			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
    867 				goto error_clear;
    868 
    869 			wpa_s->conf->changed_parameters |=
    870 					CFG_CHANGED_VENDOR_EXTENSION;
    871 
    872 			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
    873 				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
    874 				if (i < entry.array_len) {
    875 					wpa_s->conf->wps_vendor_ext[i] =
    876 						entry.binarray_value[i];
    877 					entry.binarray_value[i] = NULL;
    878 				} else
    879 					wpa_s->conf->wps_vendor_ext[i] = NULL;
    880 			}
    881 		} else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
    882 			   (entry.type == DBUS_TYPE_UINT32) &&
    883 			   (entry.uint32_value <= 15))
    884 			wpa_s->conf->p2p_go_intent = entry.uint32_value;
    885 
    886 		else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
    887 			 (entry.type == DBUS_TYPE_BOOLEAN))
    888 			wpa_s->conf->persistent_reconnect = entry.bool_value;
    889 
    890 		else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
    891 			 (entry.type == DBUS_TYPE_UINT32)) {
    892 			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
    893 			wpa_s->conf->changed_parameters |=
    894 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
    895 		} else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
    896 			   (entry.type == DBUS_TYPE_UINT32)) {
    897 			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
    898 			wpa_s->conf->changed_parameters |=
    899 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
    900 		} else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
    901 			   (entry.type == DBUS_TYPE_UINT32)) {
    902 			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
    903 			wpa_s->conf->changed_parameters |=
    904 				CFG_CHANGED_P2P_OPER_CHANNEL;
    905 		} else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
    906 			   (entry.type == DBUS_TYPE_UINT32)) {
    907 			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
    908 			wpa_s->conf->changed_parameters |=
    909 				CFG_CHANGED_P2P_OPER_CHANNEL;
    910 		} else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
    911 			char *postfix;
    912 
    913 			if (entry.type != DBUS_TYPE_STRING)
    914 				goto error_clear;
    915 
    916 			postfix = os_strdup(entry.str_value);
    917 			if (!postfix)
    918 				goto err_no_mem_clear;
    919 
    920 			os_free(wpa_s->conf->p2p_ssid_postfix);
    921 			wpa_s->conf->p2p_ssid_postfix = postfix;
    922 
    923 			wpa_s->conf->changed_parameters |=
    924 					CFG_CHANGED_P2P_SSID_POSTFIX;
    925 		} else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
    926 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
    927 			wpa_s->conf->p2p_intra_bss = entry.bool_value;
    928 			wpa_s->conf->changed_parameters |=
    929 						      CFG_CHANGED_P2P_INTRA_BSS;
    930 		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
    931 			   (entry.type == DBUS_TYPE_UINT32))
    932 			wpa_s->conf->p2p_group_idle = entry.uint32_value;
    933 		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
    934 			 entry.type == DBUS_TYPE_UINT32)
    935 			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
    936 		else
    937 			goto error_clear;
    938 
    939 		wpa_dbus_dict_entry_clear(&entry);
    940 	}
    941 
    942 	if (wpa_s->conf->changed_parameters) {
    943 		/* Some changed parameters requires to update config*/
    944 		wpa_supplicant_update_config(wpa_s);
    945 	}
    946 
    947 	return reply;
    948 
    949  error_clear:
    950 	wpa_dbus_dict_entry_clear(&entry);
    951  error:
    952 	reply = wpas_dbus_error_invalid_args(message, entry.key);
    953 	wpa_dbus_dict_entry_clear(&entry);
    954 
    955 	return reply;
    956  err_no_mem_clear:
    957 	wpa_dbus_dict_entry_clear(&entry);
    958 	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
    959 }
    960 
    961 DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
    962 					struct wpa_supplicant * wpa_s)
    963 {
    964 	DBusMessage *reply = NULL;
    965 	struct p2p_data *p2p = wpa_s->global->p2p;
    966 	int next = 0, i = 0;
    967 	int num = 0, out_of_mem = 0;
    968 	const u8 *addr;
    969 	const struct p2p_peer_info *peer_info = NULL;
    970 
    971 	struct dl_list peer_objpath_list;
    972 	struct peer_objpath_node {
    973 		struct dl_list list;
    974 		char path[WPAS_DBUS_OBJECT_PATH_MAX];
    975 	} *node, *tmp;
    976 
    977 	char **peer_obj_paths = NULL;
    978 
    979 	dl_list_init(&peer_objpath_list);
    980 
    981 	/* Get the first peer info */
    982 	peer_info = p2p_get_peer_found(p2p, NULL, next);
    983 
    984 	/* Get next and accumulate them */
    985 	next = 1;
    986 	while (peer_info != NULL) {
    987 		node = os_zalloc(sizeof(struct peer_objpath_node));
    988 		if (!node) {
    989 			out_of_mem = 1;
    990 			goto error;
    991 		}
    992 
    993 		addr = peer_info->p2p_device_addr;
    994 		os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
    995 			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
    996 			    "/" COMPACT_MACSTR,
    997 			    wpa_s->dbus_new_path, MAC2STR(addr));
    998 		dl_list_add_tail(&peer_objpath_list, &node->list);
    999 		num++;
   1000 
   1001 		peer_info = p2p_get_peer_found(p2p, addr, next);
   1002 	}
   1003 
   1004 	/*
   1005 	 * Now construct the peer object paths in a form suitable for
   1006 	 * array_property_getter helper below.
   1007 	 */
   1008 	peer_obj_paths = os_zalloc(num * sizeof(char *));
   1009 
   1010 	if (!peer_obj_paths) {
   1011 		out_of_mem = 1;
   1012 		goto error;
   1013 	}
   1014 
   1015 	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
   1016 			      struct peer_objpath_node, list)
   1017 		peer_obj_paths[i++] = node->path;
   1018 
   1019 	reply = wpas_dbus_simple_array_property_getter(message,
   1020 						       DBUS_TYPE_OBJECT_PATH,
   1021 						       peer_obj_paths, num);
   1022 
   1023 error:
   1024 	if (peer_obj_paths)
   1025 		os_free(peer_obj_paths);
   1026 
   1027 	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
   1028 			      struct peer_objpath_node, list) {
   1029 		dl_list_del(&node->list);
   1030 		os_free(node);
   1031 	}
   1032 	if (out_of_mem)
   1033 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
   1034 					       NULL);
   1035 
   1036 	return reply;
   1037 }
   1038 
   1039 enum wpas_p2p_role {
   1040 	WPAS_P2P_ROLE_DEVICE,
   1041 	WPAS_P2P_ROLE_GO,
   1042 	WPAS_P2P_ROLE_CLIENT,
   1043 };
   1044 
   1045 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
   1046 {
   1047 	struct wpa_ssid *ssid = wpa_s->current_ssid;
   1048 
   1049 	if (!ssid)
   1050 		return WPAS_P2P_ROLE_DEVICE;
   1051 	if (wpa_s->wpa_state != WPA_COMPLETED)
   1052 		return WPAS_P2P_ROLE_DEVICE;
   1053 
   1054 	switch (ssid->mode) {
   1055 	case WPAS_MODE_P2P_GO:
   1056 	case WPAS_MODE_P2P_GROUP_FORMATION:
   1057 		return WPAS_P2P_ROLE_GO;
   1058 	case WPAS_MODE_INFRA:
   1059 		if (ssid->p2p_group)
   1060 			return WPAS_P2P_ROLE_CLIENT;
   1061 		return WPAS_P2P_ROLE_DEVICE;
   1062 	default:
   1063 		return WPAS_P2P_ROLE_DEVICE;
   1064 	}
   1065 }
   1066 
   1067 DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
   1068 				       struct wpa_supplicant * wpa_s)
   1069 {
   1070 	char *str;
   1071 
   1072 	switch (wpas_get_p2p_role(wpa_s)) {
   1073 	case WPAS_P2P_ROLE_GO:
   1074 		str = "GO";
   1075 		break;
   1076 	case WPAS_P2P_ROLE_CLIENT:
   1077 		str = "client";
   1078 		break;
   1079 	default:
   1080 		str = "device";
   1081 	}
   1082 
   1083 	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
   1084 						&str);
   1085 }
   1086 
   1087 DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
   1088 					struct wpa_supplicant * wpa_s)
   1089 {
   1090 	if (wpa_s->dbus_groupobj_path == NULL)
   1091 		return NULL;
   1092 
   1093 	return wpas_dbus_simple_property_getter(message,
   1094 						DBUS_TYPE_OBJECT_PATH,
   1095 						&wpa_s->dbus_groupobj_path);
   1096 }
   1097 
   1098 DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
   1099 					 struct wpa_supplicant * wpa_s)
   1100 {
   1101 	char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
   1102 
   1103 	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
   1104 		return NULL;
   1105 
   1106 	os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
   1107 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
   1108 		    wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
   1109 	path = go_peer_obj_path;
   1110 	return wpas_dbus_simple_property_getter(message,
   1111 						DBUS_TYPE_OBJECT_PATH, &path);
   1112 }
   1113 
   1114 /*
   1115  * Peer object properties accessor methods
   1116  */
   1117 
   1118 DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
   1119 						  struct peer_handler_args *
   1120 						  peer_args)
   1121 {
   1122 	DBusMessage *reply = NULL;
   1123 	DBusMessageIter iter, variant_iter, dict_iter;
   1124 	const struct p2p_peer_info *info = NULL;
   1125 	char devtype[WPS_DEV_TYPE_BUFSIZE];
   1126 
   1127 	/* get the peer info */
   1128 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1129 				  peer_args->p2p_device_addr, 0);
   1130 	if (info == NULL)
   1131 		return NULL;
   1132 
   1133 	if (message == NULL)
   1134 		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
   1135 	else
   1136 		reply = dbus_message_new_method_return(message);
   1137 
   1138 	if (!reply)
   1139 		goto err_no_mem;
   1140 
   1141 	dbus_message_iter_init_append(reply, &iter);
   1142 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
   1143 					      "a{sv}", &variant_iter) ||
   1144 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
   1145 		goto err_no_mem;
   1146 
   1147 	/* Fill out the dictionary */
   1148 	wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
   1149 	if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
   1150 					 info->device_name))
   1151 		goto err_no_mem;
   1152 	if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
   1153 					 devtype))
   1154 		goto err_no_mem;
   1155 	if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
   1156 					 info->config_methods))
   1157 		goto err_no_mem;
   1158 	if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
   1159 					 info->level))
   1160 		goto err_no_mem;
   1161 	if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
   1162 				       info->dev_capab))
   1163 		goto err_no_mem;
   1164 	if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
   1165 				       info->group_capab))
   1166 		goto err_no_mem;
   1167 
   1168 	if (info->wps_sec_dev_type_list_len) {
   1169 		char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
   1170 		u8 *sec_dev_type_list = NULL;
   1171 		char secdevtype[WPS_DEV_TYPE_BUFSIZE];
   1172 		int num_sec_dev_types = 0;
   1173 		int i;
   1174 
   1175 		sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
   1176 
   1177 		if (sec_dev_type_list == NULL)
   1178 			goto err_no_mem;
   1179 
   1180 		os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
   1181 			  info->wps_sec_dev_type_list_len);
   1182 
   1183 		for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
   1184 		       i < (int) (info->wps_sec_dev_type_list_len /
   1185 				  WPS_DEV_TYPE_LEN);
   1186 		     i++) {
   1187 			sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
   1188 
   1189 			if (!sec_dev_types[i] ||
   1190 			    wps_dev_type_bin2str(
   1191 					&sec_dev_type_list[i *
   1192 							   WPS_DEV_TYPE_LEN],
   1193 					sec_dev_types[i],
   1194 					sizeof(secdevtype)) == NULL) {
   1195 				while (--i >= 0)
   1196 					os_free(sec_dev_types[i]);
   1197 				os_free(sec_dev_type_list);
   1198 				goto err_no_mem;
   1199 			}
   1200 
   1201 			num_sec_dev_types++;
   1202 		}
   1203 
   1204 		os_free(sec_dev_type_list);
   1205 
   1206 		if (num_sec_dev_types) {
   1207 			if (!wpa_dbus_dict_append_string_array(&dict_iter,
   1208 						"SecondaryDeviceTypes",
   1209 						(const char **)sec_dev_types,
   1210 						num_sec_dev_types)) {
   1211 				for (i = 0; i < num_sec_dev_types; i++)
   1212 					os_free(sec_dev_types[i]);
   1213 				goto err_no_mem;
   1214 			}
   1215 
   1216 			for (i = 0; i < num_sec_dev_types; i++)
   1217 				os_free(sec_dev_types[i]);
   1218 		}
   1219 	}
   1220 
   1221 	{
   1222 		/* Add WPS vendor extensions attribute */
   1223 		const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
   1224 		int i, num = 0;
   1225 
   1226 		for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
   1227 			if (info->wps_vendor_ext[i] == NULL)
   1228 				continue;
   1229 			vendor_extension[num] = info->wps_vendor_ext[i];
   1230 			num++;
   1231 		}
   1232 
   1233 		if (!wpa_dbus_dict_append_wpabuf_array(
   1234 					&dict_iter, "VendorExtension",
   1235 					vendor_extension, num))
   1236 			goto err_no_mem;
   1237 	}
   1238 
   1239 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
   1240 	    !dbus_message_iter_close_container(&iter, &variant_iter))
   1241 		goto err_no_mem;
   1242 
   1243 	return reply;
   1244 err_no_mem:
   1245 	dbus_message_unref(reply);
   1246 	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
   1247 }
   1248 
   1249 DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
   1250 					   struct peer_handler_args * peer_args)
   1251 {
   1252 	return NULL;
   1253 }
   1254 
   1255 
   1256 /**
   1257  * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
   1258  * @message: Pointer to incoming dbus message
   1259  * @wpa_s: wpa_supplicant structure for a network interface
   1260  * Returns: a dbus message containing an array of all persistent group
   1261  * dbus object paths.
   1262  *
   1263  * Getter for "Networks" property.
   1264  */
   1265 DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
   1266 						 struct wpa_supplicant *wpa_s)
   1267 {
   1268 	DBusMessage *reply = NULL;
   1269 	struct wpa_ssid *ssid;
   1270 	char **paths;
   1271 	unsigned int i = 0, num = 0;
   1272 
   1273 	if (wpa_s->conf == NULL) {
   1274 		wpa_printf(MSG_ERROR, "dbus: %s: "
   1275 			   "An error occurred getting persistent groups list",
   1276 			   __func__);
   1277 		return wpas_dbus_error_unknown_error(message, NULL);
   1278 	}
   1279 
   1280 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
   1281 		if (network_is_persistent_group(ssid))
   1282 			num++;
   1283 
   1284 	paths = os_zalloc(num * sizeof(char *));
   1285 	if (!paths) {
   1286 		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
   1287 					      NULL);
   1288 	}
   1289 
   1290 	/* Loop through configured networks and append object path of each */
   1291 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
   1292 		if (!network_is_persistent_group(ssid))
   1293 			continue;
   1294 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
   1295 		if (paths[i] == NULL) {
   1296 			reply = dbus_message_new_error(message,
   1297 						       DBUS_ERROR_NO_MEMORY,
   1298 						       NULL);
   1299 			goto out;
   1300 		}
   1301 		/* Construct the object path for this network. */
   1302 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
   1303 			    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
   1304 			    wpa_s->dbus_new_path, ssid->id);
   1305 	}
   1306 
   1307 	reply = wpas_dbus_simple_array_property_getter(message,
   1308 						       DBUS_TYPE_OBJECT_PATH,
   1309 						       paths, num);
   1310 
   1311 out:
   1312 	while (i)
   1313 		os_free(paths[--i]);
   1314 	os_free(paths);
   1315 	return reply;
   1316 }
   1317 
   1318 
   1319 /**
   1320  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
   1321  *	group
   1322  * @message: Pointer to incoming dbus message
   1323  * @net: wpa_supplicant structure for a network interface and
   1324  * wpa_ssid structure for a configured persistent group (internally network)
   1325  * Returns: DBus message with network properties or DBus error on failure
   1326  *
   1327  * Getter for "Properties" property of a persistent group.
   1328  */
   1329 DBusMessage * wpas_dbus_getter_persistent_group_properties(
   1330 	DBusMessage *message, struct network_handler_args *net)
   1331 {
   1332 	/*
   1333 	 * Leveraging the fact that persistent group object is still
   1334 	 * represented in same manner as network within.
   1335 	 */
   1336 	return wpas_dbus_getter_network_properties(message, net);
   1337 }
   1338 
   1339 
   1340 /**
   1341  * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
   1342  *	group
   1343  * @message: Pointer to incoming dbus message
   1344  * @net: wpa_supplicant structure for a network interface and
   1345  * wpa_ssid structure for a configured persistent group (internally network)
   1346  * Returns: DBus message with network properties or DBus error on failure
   1347  *
   1348  * Setter for "Properties" property of a persistent group.
   1349  */
   1350 DBusMessage * wpas_dbus_setter_persistent_group_properties(
   1351 	DBusMessage *message, struct network_handler_args *net)
   1352 {
   1353 	struct wpa_ssid *ssid = net->ssid;
   1354 	DBusMessage *reply = NULL;
   1355 	DBusMessageIter	iter, variant_iter;
   1356 
   1357 	dbus_message_iter_init(message, &iter);
   1358 
   1359 	dbus_message_iter_next(&iter);
   1360 	dbus_message_iter_next(&iter);
   1361 
   1362 	dbus_message_iter_recurse(&iter, &variant_iter);
   1363 
   1364 	/*
   1365 	 * Leveraging the fact that persistent group object is still
   1366 	 * represented in same manner as network within.
   1367 	 */
   1368 	reply = set_network_properties(message, net->wpa_s, ssid,
   1369 				       &variant_iter);
   1370 	if (reply)
   1371 		wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
   1372 			   "persistent group properties");
   1373 
   1374 	return reply;
   1375 }
   1376 
   1377 
   1378 /**
   1379  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
   1380  *	persistent_group
   1381  * @message: Pointer to incoming dbus message
   1382  * @wpa_s: wpa_supplicant structure for a network interface
   1383  * Returns: A dbus message containing the object path of the new
   1384  * persistent group
   1385  *
   1386  * Handler function for "AddPersistentGroup" method call of a P2P Device
   1387  * interface.
   1388  */
   1389 DBusMessage * wpas_dbus_handler_add_persistent_group(
   1390 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   1391 {
   1392 	DBusMessage *reply = NULL;
   1393 	DBusMessageIter	iter;
   1394 	struct wpa_ssid *ssid = NULL;
   1395 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
   1396 
   1397 	dbus_message_iter_init(message, &iter);
   1398 
   1399 	ssid = wpa_config_add_network(wpa_s->conf);
   1400 	if (ssid == NULL) {
   1401 		wpa_printf(MSG_ERROR, "dbus: %s: "
   1402 			   "Cannot add new persistent group", __func__);
   1403 		reply = wpas_dbus_error_unknown_error(
   1404 			message,
   1405 			"wpa_supplicant could not add "
   1406 			"a persistent group on this interface.");
   1407 		goto err;
   1408 	}
   1409 
   1410 	/* Mark the ssid as being a persistent group before the notification */
   1411 	ssid->disabled = 2;
   1412 	ssid->p2p_persistent_group = 1;
   1413 	wpas_notify_persistent_group_added(wpa_s, ssid);
   1414 
   1415 	wpa_config_set_network_defaults(ssid);
   1416 
   1417 	reply = set_network_properties(message, wpa_s, ssid, &iter);
   1418 	if (reply) {
   1419 		wpa_printf(MSG_DEBUG, "dbus: %s: "
   1420 			   "Control interface could not set persistent group "
   1421 			   "properties", __func__);
   1422 		goto err;
   1423 	}
   1424 
   1425 	/* Construct the object path for this network. */
   1426 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
   1427 		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
   1428 		    wpa_s->dbus_new_path, ssid->id);
   1429 
   1430 	reply = dbus_message_new_method_return(message);
   1431 	if (reply == NULL) {
   1432 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
   1433 					       NULL);
   1434 		goto err;
   1435 	}
   1436 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
   1437 				      DBUS_TYPE_INVALID)) {
   1438 		dbus_message_unref(reply);
   1439 		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
   1440 					       NULL);
   1441 		goto err;
   1442 	}
   1443 
   1444 	return reply;
   1445 
   1446 err:
   1447 	if (ssid) {
   1448 		wpas_notify_persistent_group_removed(wpa_s, ssid);
   1449 		wpa_config_remove_network(wpa_s->conf, ssid->id);
   1450 	}
   1451 	return reply;
   1452 }
   1453 
   1454 
   1455 /**
   1456  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
   1457  *	group
   1458  * @message: Pointer to incoming dbus message
   1459  * @wpa_s: wpa_supplicant structure for a network interface
   1460  * Returns: NULL on success or dbus error on failure
   1461  *
   1462  * Handler function for "RemovePersistentGroup" method call of a P2P Device
   1463  * interface.
   1464  */
   1465 DBusMessage * wpas_dbus_handler_remove_persistent_group(
   1466 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   1467 {
   1468 	DBusMessage *reply = NULL;
   1469 	const char *op;
   1470 	char *iface = NULL, *persistent_group_id = NULL;
   1471 	int id;
   1472 	struct wpa_ssid *ssid;
   1473 
   1474 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
   1475 			      DBUS_TYPE_INVALID);
   1476 
   1477 	/*
   1478 	 * Extract the network ID and ensure the network is actually a child of
   1479 	 * this interface.
   1480 	 */
   1481 	iface = wpas_dbus_new_decompose_object_path(op, 1,
   1482 						    &persistent_group_id,
   1483 						    NULL);
   1484 	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
   1485 		reply = wpas_dbus_error_invalid_args(message, op);
   1486 		goto out;
   1487 	}
   1488 
   1489 	id = strtoul(persistent_group_id, NULL, 10);
   1490 	if (errno == EINVAL) {
   1491 		reply = wpas_dbus_error_invalid_args(message, op);
   1492 		goto out;
   1493 	}
   1494 
   1495 	ssid = wpa_config_get_network(wpa_s->conf, id);
   1496 	if (ssid == NULL) {
   1497 		reply = wpas_dbus_error_persistent_group_unknown(message);
   1498 		goto out;
   1499 	}
   1500 
   1501 	wpas_notify_persistent_group_removed(wpa_s, ssid);
   1502 
   1503 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
   1504 		wpa_printf(MSG_ERROR, "dbus: %s: "
   1505 			   "error occurred when removing persistent group %d",
   1506 			   __func__, id);
   1507 		reply = wpas_dbus_error_unknown_error(
   1508 			message,
   1509 			"error removing the specified persistent group on "
   1510 			"this interface.");
   1511 		goto out;
   1512 	}
   1513 
   1514 out:
   1515 	os_free(iface);
   1516 	os_free(persistent_group_id);
   1517 	return reply;
   1518 }
   1519 
   1520 
   1521 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
   1522 				    struct wpa_ssid *ssid)
   1523 {
   1524 	wpas_notify_persistent_group_removed(wpa_s, ssid);
   1525 
   1526 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
   1527 		wpa_printf(MSG_ERROR, "dbus: %s: "
   1528 			   "error occurred when removing persistent group %d",
   1529 			   __func__, ssid->id);
   1530 		return;
   1531 	}
   1532 }
   1533 
   1534 
   1535 /**
   1536  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
   1537  * persistent groups
   1538  * @message: Pointer to incoming dbus message
   1539  * @wpa_s: wpa_supplicant structure for a network interface
   1540  * Returns: NULL on success or dbus error on failure
   1541  *
   1542  * Handler function for "RemoveAllPersistentGroups" method call of a
   1543  * P2P Device interface.
   1544  */
   1545 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
   1546 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   1547 {
   1548 	struct wpa_ssid *ssid, *next;
   1549 	struct wpa_config *config;
   1550 
   1551 	config = wpa_s->conf;
   1552 	ssid = config->ssid;
   1553 	while (ssid) {
   1554 		next = ssid->next;
   1555 		if (network_is_persistent_group(ssid))
   1556 			remove_persistent_group(wpa_s, ssid);
   1557 		ssid = next;
   1558 	}
   1559 	return NULL;
   1560 }
   1561 
   1562 
   1563 /*
   1564  * Group object properties accessor methods
   1565  */
   1566 
   1567 DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
   1568 						struct wpa_supplicant * wpa_s)
   1569 {
   1570 	DBusMessage *reply = NULL;
   1571 	struct wpa_ssid *ssid;
   1572 	unsigned int num_members;
   1573 	char **paths;
   1574 	unsigned int i;
   1575 	void *next = NULL;
   1576 	const u8 *addr;
   1577 
   1578 	/* Ensure we are a GO */
   1579 	if (wpa_s->wpa_state != WPA_COMPLETED)
   1580 		goto out;
   1581 
   1582 	ssid = wpa_s->conf->ssid;
   1583 	/* At present WPAS P2P_GO mode only applicable for p2p_go */
   1584 	if (ssid->mode != WPAS_MODE_P2P_GO &&
   1585 	    ssid->mode != WPAS_MODE_AP &&
   1586 	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
   1587 		goto out;
   1588 
   1589 	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
   1590 
   1591 	paths = os_zalloc(num_members * sizeof(char *));
   1592 	if (!paths)
   1593 		goto out_of_memory;
   1594 
   1595 	i = 0;
   1596 	while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
   1597 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
   1598 		if (!paths[i])
   1599 			goto out_of_memory;
   1600 		os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
   1601 			    "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
   1602 			    "/" COMPACT_MACSTR,
   1603 			    wpa_s->dbus_groupobj_path, MAC2STR(addr));
   1604 		i++;
   1605 	}
   1606 
   1607 	reply = wpas_dbus_simple_array_property_getter(message,
   1608 						       DBUS_TYPE_OBJECT_PATH,
   1609 						       paths, num_members);
   1610 
   1611 out_free:
   1612 	for (i = 0; i < num_members; i++)
   1613 		os_free(paths[i]);
   1614 	os_free(paths);
   1615 out:
   1616 	return reply;
   1617 out_of_memory:
   1618 	reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
   1619 	goto out_free;
   1620 }
   1621 
   1622 
   1623 DBusMessage *wpas_dbus_getter_p2p_group_properties(
   1624 	DBusMessage *message,
   1625 	struct wpa_supplicant *wpa_s)
   1626 {
   1627 	DBusMessage *reply = NULL;
   1628 	DBusMessageIter iter, variant_iter, dict_iter;
   1629 	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
   1630 	const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
   1631 	int num_vendor_ext = 0;
   1632 	int i;
   1633 
   1634 	if (!hapd) {
   1635 		reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
   1636 					       NULL);
   1637 		return reply;
   1638 	}
   1639 
   1640 	if (message == NULL)
   1641 		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
   1642 	else
   1643 		reply = dbus_message_new_method_return(message);
   1644 
   1645 	if (!reply)
   1646 		goto err_no_mem;
   1647 
   1648 	dbus_message_iter_init_append(reply, &iter);
   1649 
   1650 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
   1651 					      "a{sv}", &variant_iter) ||
   1652 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
   1653 		goto err_no_mem;
   1654 
   1655 	/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
   1656 	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
   1657 		if (hapd->conf->wps_vendor_ext[i] == NULL)
   1658 			continue;
   1659 		vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
   1660 	}
   1661 
   1662 	if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
   1663 					       "WPSVendorExtensions",
   1664 					       vendor_ext, num_vendor_ext))
   1665 		goto err_no_mem;
   1666 
   1667 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
   1668 	    !dbus_message_iter_close_container(&iter, &variant_iter))
   1669 		goto err_no_mem;
   1670 
   1671 	return reply;
   1672 
   1673 err_no_mem:
   1674 	dbus_message_unref(reply);
   1675 	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
   1676 }
   1677 
   1678 DBusMessage *wpas_dbus_setter_p2p_group_properties(
   1679 	DBusMessage *message,
   1680 	struct wpa_supplicant *wpa_s)
   1681 {
   1682 	DBusMessage *reply = NULL;
   1683 	DBusMessageIter iter, variant_iter;
   1684 	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
   1685 	DBusMessageIter iter_dict;
   1686 	unsigned int i;
   1687 
   1688 	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
   1689 
   1690 	if (!hapd)
   1691 		goto error;
   1692 
   1693 	dbus_message_iter_init(message, &iter);
   1694 
   1695 	dbus_message_iter_next(&iter);
   1696 	dbus_message_iter_next(&iter);
   1697 
   1698 	dbus_message_iter_recurse(&iter, &variant_iter);
   1699 
   1700 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
   1701 		return wpas_dbus_error_invalid_args(message, NULL);
   1702 
   1703 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1704 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
   1705 			reply = wpas_dbus_error_invalid_args(message, NULL);
   1706 			break;
   1707 		}
   1708 
   1709 		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
   1710 			if (entry.type != DBUS_TYPE_ARRAY ||
   1711 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
   1712 			    entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
   1713 				goto error;
   1714 
   1715 			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
   1716 				if (i < entry.array_len) {
   1717 					hapd->conf->wps_vendor_ext[i] =
   1718 						entry.binarray_value[i];
   1719 					entry.binarray_value[i] = NULL;
   1720 				} else
   1721 					hapd->conf->wps_vendor_ext[i] = NULL;
   1722 			}
   1723 
   1724 			hostapd_update_wps(hapd);
   1725 		} else
   1726 			goto error;
   1727 
   1728 		wpa_dbus_dict_entry_clear(&entry);
   1729 	}
   1730 
   1731 	return reply;
   1732 
   1733 error:
   1734 	reply = wpas_dbus_error_invalid_args(message, entry.key);
   1735 	wpa_dbus_dict_entry_clear(&entry);
   1736 
   1737 	return reply;
   1738 }
   1739 
   1740 DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
   1741 					       struct wpa_supplicant * wpa_s)
   1742 {
   1743 	DBusMessageIter iter_dict;
   1744 	DBusMessage *reply = NULL;
   1745 	DBusMessageIter iter;
   1746 	struct wpa_dbus_dict_entry entry;
   1747 	int upnp = 0;
   1748 	int bonjour = 0;
   1749 	char *service = NULL;
   1750 	struct wpabuf *query = NULL;
   1751 	struct wpabuf *resp = NULL;
   1752 	u8 version = 0;
   1753 
   1754 	dbus_message_iter_init(message, &iter);
   1755 
   1756 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
   1757 		goto error;
   1758 
   1759 	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1760 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1761 			goto error;
   1762 
   1763 		if (!strcmp(entry.key, "service_type") &&
   1764 		    (entry.type == DBUS_TYPE_STRING)) {
   1765 			if (!strcmp(entry.str_value, "upnp"))
   1766 				upnp = 1;
   1767 			else if (!strcmp(entry.str_value, "bonjour"))
   1768 				bonjour = 1;
   1769 			else
   1770 				goto error_clear;
   1771 			wpa_dbus_dict_entry_clear(&entry);
   1772 		}
   1773 	}
   1774 
   1775 	if (upnp == 1) {
   1776 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1777 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1778 				goto error;
   1779 
   1780 			if (!strcmp(entry.key, "version") &&
   1781 			    entry.type == DBUS_TYPE_INT32)
   1782 				version = entry.uint32_value;
   1783 			else if (!strcmp(entry.key, "service") &&
   1784 				 entry.type == DBUS_TYPE_STRING)
   1785 				service = os_strdup(entry.str_value);
   1786 			wpa_dbus_dict_entry_clear(&entry);
   1787 		}
   1788 		if (version <= 0 || service == NULL)
   1789 			goto error;
   1790 
   1791 		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
   1792 			goto error;
   1793 
   1794 		os_free(service);
   1795 	} else if (bonjour == 1) {
   1796 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1797 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1798 				goto error;
   1799 
   1800 			if (!strcmp(entry.key, "query")) {
   1801 				if ((entry.type != DBUS_TYPE_ARRAY) ||
   1802 				    (entry.array_type != DBUS_TYPE_BYTE))
   1803 					goto error_clear;
   1804 				query = wpabuf_alloc_copy(entry.bytearray_value,
   1805 							  entry.array_len);
   1806 			} else if (!strcmp(entry.key, "response")) {
   1807 				if ((entry.type != DBUS_TYPE_ARRAY) ||
   1808 				    (entry.array_type != DBUS_TYPE_BYTE))
   1809 					goto error_clear;
   1810 				resp = wpabuf_alloc_copy(entry.bytearray_value,
   1811 							 entry.array_len);
   1812 			}
   1813 
   1814 			wpa_dbus_dict_entry_clear(&entry);
   1815 		}
   1816 
   1817 		if (query == NULL || resp == NULL)
   1818 			goto error;
   1819 
   1820 		if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
   1821 			wpabuf_free(query);
   1822 			wpabuf_free(resp);
   1823 			goto error;
   1824 		}
   1825 	} else
   1826 		goto error;
   1827 
   1828 	return reply;
   1829 error_clear:
   1830 	wpa_dbus_dict_entry_clear(&entry);
   1831 error:
   1832 	return wpas_dbus_error_invalid_args(message, NULL);
   1833 }
   1834 
   1835 DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
   1836 						  struct wpa_supplicant * wpa_s)
   1837 {
   1838 	DBusMessageIter iter_dict;
   1839 	DBusMessage *reply = NULL;
   1840 	DBusMessageIter iter;
   1841 	struct wpa_dbus_dict_entry entry;
   1842 	int upnp = 0;
   1843 	int bonjour = 0;
   1844 	int ret = 0;
   1845 	char *service = NULL;
   1846 	struct wpabuf *query = NULL;
   1847 	u8 version = 0;
   1848 
   1849 	dbus_message_iter_init(message, &iter);
   1850 
   1851 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
   1852 		goto error;
   1853 
   1854 	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1855 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1856 			goto error;
   1857 
   1858 		if (!strcmp(entry.key, "service_type") &&
   1859 		    (entry.type == DBUS_TYPE_STRING)) {
   1860 			if (!strcmp(entry.str_value, "upnp"))
   1861 				upnp = 1;
   1862 			else if (!strcmp(entry.str_value, "bonjour"))
   1863 				bonjour = 1;
   1864 			else
   1865 				goto error_clear;
   1866 			wpa_dbus_dict_entry_clear(&entry);
   1867 		}
   1868 	}
   1869 	if (upnp == 1) {
   1870 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1871 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1872 				goto error;
   1873 			if (!strcmp(entry.key, "version") &&
   1874 			    entry.type == DBUS_TYPE_INT32)
   1875 				version = entry.uint32_value;
   1876 			else if (!strcmp(entry.key, "service") &&
   1877 				 entry.type == DBUS_TYPE_STRING)
   1878 				service = os_strdup(entry.str_value);
   1879 			else
   1880 				goto error_clear;
   1881 
   1882 			wpa_dbus_dict_entry_clear(&entry);
   1883 		}
   1884 
   1885 		if (version <= 0 || service == NULL)
   1886 			goto error;
   1887 
   1888 		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
   1889 		os_free(service);
   1890 		if (ret != 0)
   1891 			goto error;
   1892 	} else if (bonjour == 1) {
   1893 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1894 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1895 				goto error;
   1896 
   1897 			if (!strcmp(entry.key, "query")) {
   1898 				if ((entry.type != DBUS_TYPE_ARRAY) ||
   1899 				    (entry.array_type != DBUS_TYPE_BYTE))
   1900 					goto error_clear;
   1901 				query = wpabuf_alloc_copy(entry.bytearray_value,
   1902 							  entry.array_len);
   1903 			} else
   1904 				goto error_clear;
   1905 
   1906 			wpa_dbus_dict_entry_clear(&entry);
   1907 		}
   1908 
   1909 		if (query == NULL)
   1910 			goto error;
   1911 
   1912 		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
   1913 		if (ret != 0)
   1914 			goto error;
   1915 		wpabuf_free(query);
   1916 	} else
   1917 		goto error;
   1918 
   1919 	return reply;
   1920 error_clear:
   1921 	wpa_dbus_dict_entry_clear(&entry);
   1922 error:
   1923 	return wpas_dbus_error_invalid_args(message, NULL);
   1924 }
   1925 
   1926 DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
   1927 						 struct wpa_supplicant * wpa_s)
   1928 {
   1929 	wpas_p2p_service_flush(wpa_s);
   1930 	return NULL;
   1931 }
   1932 
   1933 DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
   1934 						  struct wpa_supplicant * wpa_s)
   1935 {
   1936 	DBusMessageIter iter_dict;
   1937 	DBusMessage *reply = NULL;
   1938 	DBusMessageIter iter;
   1939 	struct wpa_dbus_dict_entry entry;
   1940 	int upnp = 0;
   1941 	char *service = NULL;
   1942 	char *peer_object_path = NULL;
   1943 	struct wpabuf *tlv = NULL;
   1944 	u8 version = 0;
   1945 	u64 ref = 0;
   1946 	u8 addr[ETH_ALEN];
   1947 
   1948 	dbus_message_iter_init(message, &iter);
   1949 
   1950 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
   1951 		goto error;
   1952 
   1953 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1954 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   1955 			goto error;
   1956 		if (!strcmp(entry.key, "peer_object") &&
   1957 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
   1958 			peer_object_path = os_strdup(entry.str_value);
   1959 		} else if (!strcmp(entry.key, "service_type") &&
   1960 			   entry.type == DBUS_TYPE_STRING) {
   1961 			if (!strcmp(entry.str_value, "upnp"))
   1962 				upnp = 1;
   1963 			else
   1964 				goto error_clear;
   1965 		} else if (!strcmp(entry.key, "version") &&
   1966 			   entry.type == DBUS_TYPE_INT32) {
   1967 			version = entry.uint32_value;
   1968 		} else if (!strcmp(entry.key, "service") &&
   1969 			   entry.type == DBUS_TYPE_STRING) {
   1970 			service = os_strdup(entry.str_value);
   1971 		} else if (!strcmp(entry.key, "tlv")) {
   1972 			if (entry.type != DBUS_TYPE_ARRAY ||
   1973 			    entry.array_type != DBUS_TYPE_BYTE)
   1974 				goto error_clear;
   1975 			tlv = wpabuf_alloc_copy(entry.bytearray_value,
   1976 						entry.array_len);
   1977 		} else
   1978 			goto error_clear;
   1979 
   1980 		wpa_dbus_dict_entry_clear(&entry);
   1981 	}
   1982 
   1983 	if (!peer_object_path ||
   1984 	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
   1985 	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
   1986 		goto error;
   1987 
   1988 	if (upnp == 1) {
   1989 		if (version <= 0 || service == NULL)
   1990 			goto error;
   1991 
   1992 		ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
   1993 							      version, service);
   1994 	} else {
   1995 		if (tlv == NULL)
   1996 			goto error;
   1997 		ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
   1998 		wpabuf_free(tlv);
   1999 	}
   2000 
   2001 	if (ref != 0) {
   2002 		reply = dbus_message_new_method_return(message);
   2003 		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
   2004 					 &ref, DBUS_TYPE_INVALID);
   2005 	} else {
   2006 		reply = wpas_dbus_error_unknown_error(message,
   2007 				"Unable to send SD request");
   2008 	}
   2009 out:
   2010 	os_free(service);
   2011 	os_free(peer_object_path);
   2012 	return reply;
   2013 error_clear:
   2014 	wpa_dbus_dict_entry_clear(&entry);
   2015 error:
   2016 	if (tlv)
   2017 		wpabuf_free(tlv);
   2018 	reply = wpas_dbus_error_invalid_args(message, NULL);
   2019 	goto out;
   2020 }
   2021 
   2022 DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
   2023 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   2024 {
   2025 	DBusMessageIter iter_dict;
   2026 	DBusMessage *reply = NULL;
   2027 	DBusMessageIter iter;
   2028 	struct wpa_dbus_dict_entry entry;
   2029 	char *peer_object_path = NULL;
   2030 	struct wpabuf *tlv = NULL;
   2031 	int freq = 0;
   2032 	int dlg_tok = 0;
   2033 	u8 addr[ETH_ALEN];
   2034 
   2035 	dbus_message_iter_init(message, &iter);
   2036 
   2037 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
   2038 		goto error;
   2039 
   2040 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   2041 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   2042 			goto error;
   2043 
   2044 		if (!strcmp(entry.key, "peer_object") &&
   2045 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
   2046 			peer_object_path = os_strdup(entry.str_value);
   2047 		} else if (!strcmp(entry.key, "frequency") &&
   2048 			   entry.type == DBUS_TYPE_INT32) {
   2049 			freq = entry.uint32_value;
   2050 		} else if (!strcmp(entry.key, "dialog_token") &&
   2051 			   entry.type == DBUS_TYPE_UINT32) {
   2052 			dlg_tok = entry.uint32_value;
   2053 		} else if (!strcmp(entry.key, "tlvs")) {
   2054 			if (entry.type != DBUS_TYPE_ARRAY ||
   2055 			    entry.array_type != DBUS_TYPE_BYTE)
   2056 				goto error_clear;
   2057 			tlv = wpabuf_alloc_copy(entry.bytearray_value,
   2058 						entry.array_len);
   2059 		} else
   2060 			goto error_clear;
   2061 
   2062 		wpa_dbus_dict_entry_clear(&entry);
   2063 	}
   2064 	if (!peer_object_path ||
   2065 	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
   2066 	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
   2067 		goto error;
   2068 
   2069 	if (tlv == NULL)
   2070 		goto error;
   2071 
   2072 	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
   2073 	wpabuf_free(tlv);
   2074 out:
   2075 	os_free(peer_object_path);
   2076 	return reply;
   2077 error_clear:
   2078 	wpa_dbus_dict_entry_clear(&entry);
   2079 error:
   2080 	reply = wpas_dbus_error_invalid_args(message, NULL);
   2081 	goto out;
   2082 }
   2083 
   2084 DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
   2085 							 *wpa_s)
   2086 {
   2087 	DBusMessageIter iter;
   2088 	u64 req = 0;
   2089 
   2090 	dbus_message_iter_init(message, &iter);
   2091 	dbus_message_iter_get_basic(&iter, &req);
   2092 
   2093 	if (req == 0)
   2094 		goto error;
   2095 
   2096 	if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
   2097 		goto error;
   2098 
   2099 	return NULL;
   2100 error:
   2101 	return wpas_dbus_error_invalid_args(message, NULL);
   2102 }
   2103 
   2104 DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
   2105 						  struct wpa_supplicant * wpa_s)
   2106 {
   2107 	wpas_p2p_sd_service_update(wpa_s);
   2108 	return NULL;
   2109 }
   2110 
   2111 DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
   2112 						      struct wpa_supplicant *
   2113 						      wpa_s)
   2114 {
   2115 	DBusMessageIter iter;
   2116 	int ext = 0;
   2117 
   2118 	dbus_message_iter_init(message, &iter);
   2119 	dbus_message_iter_get_basic(&iter, &ext);
   2120 
   2121 	wpa_s->p2p_sd_over_ctrl_iface = ext;
   2122 
   2123 	return NULL;
   2124 
   2125 }
   2126