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