Home | History | Annotate | Line # | 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 "../bss.h"
     18 #include "dbus_new_helpers.h"
     19 #include "dbus_new.h"
     20 #include "dbus_new_handlers.h"
     21 #include "dbus_new_handlers_p2p.h"
     22 #include "dbus_dict_helpers.h"
     23 #include "p2p/p2p.h"
     24 #include "common/ieee802_11_defs.h"
     25 #include "ap/hostapd.h"
     26 #include "ap/ap_config.h"
     27 #include "ap/wps_hostapd.h"
     28 
     29 #include "../p2p_supplicant.h"
     30 #include "../wifi_display.h"
     31 
     32 
     33 static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
     34 {
     35 	if (entry.type != DBUS_TYPE_ARRAY ||
     36 	    entry.array_type != DBUS_TYPE_BYTE ||
     37 	    entry.array_len != 4)
     38 		return 0;
     39 
     40 	return 1;
     41 }
     42 
     43 
     44 static dbus_bool_t no_p2p_mgmt_interface(DBusError *error)
     45 {
     46 	dbus_set_error_const(error, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
     47 			     "Could not find P2P mgmt interface");
     48 	return FALSE;
     49 }
     50 
     51 
     52 /**
     53  * Parses out the mac address from the peer object path.
     54  * @peer_path - object path of the form
     55  *	/fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
     56  * @addr - out param must be of ETH_ALEN size
     57  * Returns 0 if valid (including MAC), -1 otherwise
     58  */
     59 static int parse_peer_object_path(const char *peer_path, u8 addr[ETH_ALEN])
     60 {
     61 	const char *p;
     62 
     63 	if (!peer_path)
     64 		return -1;
     65 	p = os_strrchr(peer_path, '/');
     66 	if (!p)
     67 		return -1;
     68 	p++;
     69 	return hwaddr_compact_aton(p, addr);
     70 }
     71 
     72 
     73 /**
     74  * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
     75  * error message
     76  * @message: Pointer to incoming dbus message this error refers to
     77  * Returns: a dbus error message
     78  *
     79  * Convenience function to create and return an invalid persistent group error.
     80  */
     81 static DBusMessage *
     82 wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
     83 {
     84 	return dbus_message_new_error(
     85 		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
     86 		"There is no such persistent group in this P2P device.");
     87 }
     88 
     89 
     90 /**
     91  * wpas_dbus_error_no_p2p_mgmt_iface - Return a new InterfaceUnknown error
     92  * message
     93  * @message: Pointer to incoming dbus message this error refers to
     94  * Returns: a dbus error message
     95  *
     96  * Convenience function to create and return an unknown interface error.
     97  */
     98 static DBusMessage * wpas_dbus_error_no_p2p_mgmt_iface(DBusMessage *message)
     99 {
    100 	wpa_printf(MSG_DEBUG, "dbus: Could not find P2P mgmt interface");
    101 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
    102 				      "Could not find P2P mgmt interface");
    103 }
    104 
    105 
    106 DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
    107 					 struct wpa_supplicant *wpa_s)
    108 {
    109 	struct wpa_dbus_dict_entry entry;
    110 	DBusMessage *reply = NULL;
    111 	DBusMessageIter iter;
    112 	DBusMessageIter iter_dict;
    113 	unsigned int timeout = 0;
    114 	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
    115 	int num_req_dev_types = 0;
    116 	unsigned int i;
    117 	u8 *req_dev_types = NULL;
    118 	unsigned int freq = 0;
    119 
    120 	dbus_message_iter_init(message, &iter);
    121 	entry.key = NULL;
    122 
    123 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
    124 		goto error;
    125 
    126 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    127 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    128 			goto error;
    129 
    130 		if (os_strcmp(entry.key, "Timeout") == 0 &&
    131 		    entry.type == DBUS_TYPE_INT32) {
    132 			timeout = entry.uint32_value;
    133 		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
    134 			if (entry.type != DBUS_TYPE_ARRAY ||
    135 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY)
    136 				goto error_clear;
    137 
    138 			os_free(req_dev_types);
    139 			req_dev_types =
    140 				os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
    141 			if (!req_dev_types)
    142 				goto error_clear;
    143 
    144 			for (i = 0; i < entry.array_len; i++) {
    145 				if (wpabuf_len(entry.binarray_value[i]) !=
    146 				    WPS_DEV_TYPE_LEN)
    147 					goto error_clear;
    148 				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
    149 					  wpabuf_head(entry.binarray_value[i]),
    150 					  WPS_DEV_TYPE_LEN);
    151 			}
    152 			num_req_dev_types = entry.array_len;
    153 		} else if (os_strcmp(entry.key, "DiscoveryType") == 0 &&
    154 			   entry.type == DBUS_TYPE_STRING) {
    155 			if (os_strcmp(entry.str_value, "start_with_full") == 0)
    156 				type = P2P_FIND_START_WITH_FULL;
    157 			else if (os_strcmp(entry.str_value, "social") == 0)
    158 				type = P2P_FIND_ONLY_SOCIAL;
    159 			else if (os_strcmp(entry.str_value, "progressive") == 0)
    160 				type = P2P_FIND_PROGRESSIVE;
    161 			else
    162 				goto error_clear;
    163 		} else if (os_strcmp(entry.key, "freq") == 0 &&
    164 			   (entry.type == DBUS_TYPE_INT32 ||
    165 			    entry.type == DBUS_TYPE_UINT32)) {
    166 			freq = entry.uint32_value;
    167 		} else
    168 			goto error_clear;
    169 		wpa_dbus_dict_entry_clear(&entry);
    170 	}
    171 
    172 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    173 	if (!wpa_s) {
    174 		reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
    175 		goto error_nop2p;
    176 	}
    177 
    178 	if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
    179 			  req_dev_types, NULL, 0, 0, NULL, freq, false))
    180 		reply = wpas_dbus_error_unknown_error(
    181 			message, "Could not start P2P find");
    182 
    183 	os_free(req_dev_types);
    184 	return reply;
    185 
    186 error_clear:
    187 	wpa_dbus_dict_entry_clear(&entry);
    188 error:
    189 	reply = wpas_dbus_error_invalid_args(message, entry.key);
    190 error_nop2p:
    191 	os_free(req_dev_types);
    192 	return reply;
    193 }
    194 
    195 
    196 DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
    197 					      struct wpa_supplicant *wpa_s)
    198 {
    199 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    200 	if (wpa_s)
    201 		wpas_p2p_stop_find(wpa_s);
    202 	return NULL;
    203 }
    204 
    205 
    206 DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
    207 					       struct wpa_supplicant *wpa_s)
    208 {
    209 	DBusMessageIter iter;
    210 	char *peer_object_path = NULL;
    211 	u8 peer_addr[ETH_ALEN];
    212 
    213 	dbus_message_iter_init(message, &iter);
    214 	dbus_message_iter_get_basic(&iter, &peer_object_path);
    215 
    216 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
    217 		return wpas_dbus_error_invalid_args(message, NULL);
    218 
    219 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    220 	if (!wpa_s)
    221 		return wpas_dbus_error_no_p2p_mgmt_iface(message);
    222 
    223 	if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
    224 		return wpas_dbus_error_unknown_error(message,
    225 				"Failed to call wpas_p2p_reject method.");
    226 
    227 	return NULL;
    228 }
    229 
    230 
    231 DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
    232 					   struct wpa_supplicant *wpa_s)
    233 {
    234 	dbus_int32_t timeout = 0;
    235 
    236 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
    237 				   DBUS_TYPE_INVALID))
    238 		return wpas_dbus_error_no_memory(message);
    239 
    240 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    241 	if (!wpa_s)
    242 		return wpas_dbus_error_no_p2p_mgmt_iface(message);
    243 
    244 	if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
    245 		return dbus_message_new_error(message,
    246 					      WPAS_DBUS_ERROR_UNKNOWN_ERROR,
    247 					      "Could not start P2P listen");
    248 	}
    249 
    250 	return NULL;
    251 }
    252 
    253 
    254 DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
    255 	DBusMessage *message, struct wpa_supplicant *wpa_s)
    256 {
    257 	unsigned int period = 0, interval = 0;
    258 	struct wpa_dbus_dict_entry entry;
    259 	DBusMessageIter iter;
    260 	DBusMessageIter iter_dict;
    261 
    262 	dbus_message_iter_init(message, &iter);
    263 	entry.key = NULL;
    264 
    265 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
    266 		goto error;
    267 
    268 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    269 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    270 			goto error;
    271 
    272 		if (os_strcmp(entry.key, "period") == 0 &&
    273 		    entry.type == DBUS_TYPE_INT32)
    274 			period = entry.uint32_value;
    275 		else if (os_strcmp(entry.key, "interval") == 0 &&
    276 			 entry.type == DBUS_TYPE_INT32)
    277 			interval = entry.uint32_value;
    278 		else
    279 			goto error_clear;
    280 		wpa_dbus_dict_entry_clear(&entry);
    281 	}
    282 
    283 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    284 	if (!wpa_s)
    285 		return wpas_dbus_error_no_p2p_mgmt_iface(message);
    286 
    287 	if (wpas_p2p_ext_listen(wpa_s, period, interval))
    288 		return wpas_dbus_error_unknown_error(
    289 			message, "failed to initiate a p2p_ext_listen.");
    290 
    291 	return NULL;
    292 
    293 error_clear:
    294 	wpa_dbus_dict_entry_clear(&entry);
    295 error:
    296 	return wpas_dbus_error_invalid_args(message, entry.key);
    297 }
    298 
    299 
    300 DBusMessage * wpas_dbus_handler_p2p_presence_request(
    301 	DBusMessage *message, struct wpa_supplicant *wpa_s)
    302 {
    303 	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
    304 	struct wpa_dbus_dict_entry entry;
    305 	DBusMessageIter iter;
    306 	DBusMessageIter iter_dict;
    307 
    308 	dbus_message_iter_init(message, &iter);
    309 	entry.key = NULL;
    310 
    311 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
    312 		goto error;
    313 
    314 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    315 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    316 			goto error;
    317 
    318 		if (os_strcmp(entry.key, "duration1") == 0 &&
    319 		    entry.type == DBUS_TYPE_INT32)
    320 			dur1 = entry.uint32_value;
    321 		else if (os_strcmp(entry.key, "interval1") == 0 &&
    322 			 entry.type == DBUS_TYPE_INT32)
    323 			int1 = entry.uint32_value;
    324 		else if (os_strcmp(entry.key, "duration2") == 0 &&
    325 			 entry.type == DBUS_TYPE_INT32)
    326 			dur2 = entry.uint32_value;
    327 		else if (os_strcmp(entry.key, "interval2") == 0 &&
    328 			 entry.type == DBUS_TYPE_INT32)
    329 			int2 = entry.uint32_value;
    330 		else
    331 			goto error_clear;
    332 
    333 		wpa_dbus_dict_entry_clear(&entry);
    334 	}
    335 
    336 	if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
    337 		return wpas_dbus_error_unknown_error(message,
    338 				"Failed to invoke presence request.");
    339 
    340 	return NULL;
    341 
    342 error_clear:
    343 	wpa_dbus_dict_entry_clear(&entry);
    344 error:
    345 	return wpas_dbus_error_invalid_args(message, entry.key);
    346 }
    347 
    348 
    349 DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
    350 					      struct wpa_supplicant *wpa_s)
    351 {
    352 	DBusMessageIter iter_dict;
    353 	DBusMessage *reply = NULL;
    354 	DBusMessageIter iter;
    355 	struct wpa_dbus_dict_entry entry;
    356 	char *pg_object_path = NULL;
    357 	int persistent_group = 0;
    358 	int freq = 0;
    359 	int retry_limit = 0;
    360 	char *iface = NULL;
    361 	unsigned int group_id = 0;
    362 	struct wpa_ssid *ssid;
    363 	u8 go_bssid_buf[ETH_ALEN], *go_bssid = NULL;
    364 	bool allow_6ghz = false;
    365 	int vht = wpa_s->conf->p2p_go_vht;
    366 	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
    367 	int he = wpa_s->conf->p2p_go_he;
    368 	int edmg = wpa_s->conf->p2p_go_edmg;
    369 	int max_oper_chwidth, chwidth = 0, freq2 = 0;
    370 
    371 	dbus_message_iter_init(message, &iter);
    372 
    373 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
    374 		goto inv_args;
    375 
    376 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    377 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    378 			goto inv_args;
    379 
    380 		if (os_strcmp(entry.key, "persistent") == 0 &&
    381 		    entry.type == DBUS_TYPE_BOOLEAN) {
    382 			persistent_group = entry.bool_value;
    383 		} else if (os_strcmp(entry.key, "frequency") == 0 &&
    384 			   entry.type == DBUS_TYPE_INT32) {
    385 			freq = entry.int32_value;
    386 			if (freq <= 0)
    387 				goto inv_args_clear;
    388 		} else if (os_strcmp(entry.key, "retry_limit") == 0 &&
    389 			   entry.type == DBUS_TYPE_INT32) {
    390 			retry_limit = entry.int32_value;
    391 			if (retry_limit <= 0)
    392 				goto inv_args_clear;
    393 		} else if (os_strcmp(entry.key, "persistent_group_object") ==
    394 			   0 &&
    395 			   entry.type == DBUS_TYPE_OBJECT_PATH) {
    396 			pg_object_path = os_strdup(entry.str_value);
    397 		} else if (os_strcmp(entry.key, "go_bssid") == 0 &&
    398 			   entry.type == DBUS_TYPE_STRING) {
    399 			if (hwaddr_aton(entry.str_value, go_bssid_buf))
    400 				goto inv_args_clear;
    401 			go_bssid = go_bssid_buf;
    402 		} else if (os_strcmp(entry.key, "ht40") == 0 &&
    403 			   entry.type == DBUS_TYPE_BOOLEAN) {
    404 			ht40 = entry.bool_value;
    405 		} else if (os_strcmp(entry.key, "vht") == 0 &&
    406 			   entry.type == DBUS_TYPE_BOOLEAN) {
    407 			vht = entry.bool_value;
    408 			ht40 |= vht;
    409 		} else if (os_strcmp(entry.key, "he") == 0 &&
    410 			   entry.type == DBUS_TYPE_BOOLEAN) {
    411 			he = entry.bool_value;
    412 		} else if (os_strcmp(entry.key, "edmg") == 0 &&
    413 			   entry.type == DBUS_TYPE_BOOLEAN) {
    414 			edmg = entry.bool_value;
    415 		} else if (os_strcmp(entry.key, "allow_6ghz") == 0 &&
    416 			   entry.type == DBUS_TYPE_BOOLEAN) {
    417 			allow_6ghz = entry.bool_value;
    418 		} else if (os_strcmp(entry.key, "freq2") == 0 &&
    419 			   entry.type == DBUS_TYPE_INT32) {
    420 			freq2 = entry.int32_value;
    421 		} else if (os_strcmp(entry.key, "max_oper_chwidth") == 0 &&
    422 			   entry.type == DBUS_TYPE_INT32) {
    423 			chwidth = entry.int32_value;
    424 		} else {
    425 			goto inv_args_clear;
    426 		}
    427 
    428 		wpa_dbus_dict_entry_clear(&entry);
    429 	}
    430 
    431 	max_oper_chwidth = chwidth_freq2_to_ch_width(chwidth, freq2);
    432 	if (max_oper_chwidth < 0)
    433 		goto inv_args;
    434 
    435 	if (allow_6ghz && chwidth == 40)
    436 		max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
    437 
    438 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    439 	if (!wpa_s) {
    440 		reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
    441 		goto out;
    442 	}
    443 
    444 	if (pg_object_path != NULL) {
    445 		char *net_id_str;
    446 
    447 		/*
    448 		 * A persistent group Object Path is defined meaning we want
    449 		 * to re-invoke a persistent group.
    450 		 */
    451 
    452 		iface = wpas_dbus_new_decompose_object_path(
    453 			pg_object_path, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
    454 			&net_id_str);
    455 		if (iface == NULL || net_id_str == NULL ||
    456 		    !wpa_s->parent->dbus_new_path ||
    457 		    os_strcmp(iface, wpa_s->parent->dbus_new_path) != 0) {
    458 			reply =
    459 			    wpas_dbus_error_invalid_args(message,
    460 							 pg_object_path);
    461 			goto out;
    462 		}
    463 
    464 		group_id = strtoul(net_id_str, NULL, 10);
    465 		if (errno == EINVAL) {
    466 			reply = wpas_dbus_error_invalid_args(
    467 						message, pg_object_path);
    468 			goto out;
    469 		}
    470 
    471 		/* Get the SSID structure from the persistent group id */
    472 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
    473 		if (ssid == NULL || ssid->disabled != 2)
    474 			goto inv_args;
    475 
    476 		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
    477 						  freq2, ht40, vht,
    478 						  max_oper_chwidth, he, edmg,
    479 						  NULL, 0, 0, allow_6ghz,
    480 						  retry_limit, go_bssid)) {
    481 			reply = wpas_dbus_error_unknown_error(
    482 				message,
    483 				"Failed to reinvoke a persistent group");
    484 			goto out;
    485 		}
    486 	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, freq2,
    487 				      ht40, vht, max_oper_chwidth, he, edmg,
    488 				      allow_6ghz))
    489 		goto inv_args;
    490 
    491 out:
    492 	os_free(pg_object_path);
    493 	os_free(iface);
    494 	return reply;
    495 inv_args_clear:
    496 	wpa_dbus_dict_entry_clear(&entry);
    497 inv_args:
    498 	reply = wpas_dbus_error_invalid_args(message, NULL);
    499 	goto out;
    500 }
    501 
    502 
    503 DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
    504 					       struct wpa_supplicant *wpa_s)
    505 {
    506 	if (wpas_p2p_disconnect(wpa_s))
    507 		return wpas_dbus_error_unknown_error(message,
    508 						"failed to disconnect");
    509 
    510 	return NULL;
    511 }
    512 
    513 
    514 static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
    515 					      DBusMessage *message,
    516 					      DBusMessage **out_reply,
    517 					      DBusError *error)
    518 {
    519 	/* Return an error message or an error if P2P isn't available */
    520 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
    521 		if (out_reply) {
    522 			*out_reply = dbus_message_new_error(
    523 				message, DBUS_ERROR_FAILED,
    524 				"P2P is not available for this interface");
    525 		}
    526 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
    527 				     "P2P is not available for this interface");
    528 		return FALSE;
    529 	}
    530 	if (!wpa_s->global->p2p_init_wpa_s) {
    531 		if (out_reply)
    532 			*out_reply = wpas_dbus_error_no_p2p_mgmt_iface(
    533 				message);
    534 		return no_p2p_mgmt_interface(error);
    535 	}
    536 	return TRUE;
    537 }
    538 
    539 
    540 DBusMessage * wpas_dbus_handler_p2p_remove_client(DBusMessage *message,
    541 						  struct wpa_supplicant *wpa_s)
    542 {
    543 	DBusMessageIter iter_dict;
    544 	DBusMessage *reply = NULL;
    545 	DBusMessageIter iter;
    546 	struct wpa_dbus_dict_entry entry;
    547 	char *peer_object_path = NULL;
    548 	char *interface_addr = NULL;
    549 	u8 peer_addr[ETH_ALEN];
    550 
    551 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
    552 		return reply;
    553 
    554 	dbus_message_iter_init(message, &iter);
    555 
    556 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
    557 		goto err;
    558 
    559 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    560 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    561 			goto err;
    562 
    563 		if (os_strcmp(entry.key, "peer") == 0 &&
    564 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
    565 			os_free(peer_object_path);
    566 			peer_object_path = os_strdup(entry.str_value);
    567 			wpa_dbus_dict_entry_clear(&entry);
    568 		} else if (os_strcmp(entry.key, "iface") == 0 &&
    569 			   entry.type == DBUS_TYPE_STRING) {
    570 			os_free(interface_addr);
    571 			interface_addr = os_strdup(entry.str_value);
    572 			wpa_dbus_dict_entry_clear(&entry);
    573 		} else {
    574 			wpa_dbus_dict_entry_clear(&entry);
    575 			goto err;
    576 		}
    577 	}
    578 
    579 	if ((!peer_object_path && !interface_addr) ||
    580 	    (peer_object_path &&
    581 	     (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
    582 	      !p2p_peer_known(wpa_s->global->p2p, peer_addr))) ||
    583 	    (interface_addr && hwaddr_aton(interface_addr, peer_addr) < 0))
    584 		goto err;
    585 
    586 	wpas_p2p_remove_client(wpa_s, peer_addr, interface_addr != NULL);
    587 	reply = NULL;
    588 out:
    589 	os_free(peer_object_path);
    590 	os_free(interface_addr);
    591 	return reply;
    592 err:
    593 	reply = wpas_dbus_error_invalid_args(message, "Invalid address format");
    594 	goto out;
    595 }
    596 
    597 
    598 DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
    599 					  struct wpa_supplicant *wpa_s)
    600 {
    601 	DBusMessage *reply = NULL;
    602 
    603 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
    604 		return reply;
    605 
    606 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    607 
    608 	wpas_p2p_stop_find(wpa_s);
    609 	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
    610 	wpa_s->force_long_sd = 0;
    611 	p2p_flush(wpa_s->global->p2p);
    612 
    613 	return NULL;
    614 }
    615 
    616 
    617 DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
    618 					    struct wpa_supplicant *wpa_s)
    619 {
    620 	DBusMessageIter iter_dict;
    621 	DBusMessage *reply = NULL;
    622 	DBusMessageIter iter;
    623 	struct wpa_dbus_dict_entry entry;
    624 	char *peer_object_path = NULL;
    625 	int persistent_group = 0;
    626 	int join = 0;
    627 	int authorize_only = 0;
    628 	int go_intent = -1;
    629 	int freq = 0;
    630 	u8 addr[ETH_ALEN];
    631 	char *pin = NULL;
    632 	enum p2p_wps_method wps_method = WPS_NOT_READY;
    633 	int new_pin;
    634 	char *err_msg = NULL;
    635 	char *iface = NULL;
    636 	int ret;
    637 
    638 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
    639 		return reply;
    640 
    641 	dbus_message_iter_init(message, &iter);
    642 
    643 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
    644 		goto inv_args;
    645 
    646 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    647 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    648 			goto inv_args;
    649 
    650 		if (os_strcmp(entry.key, "peer") == 0 &&
    651 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
    652 			peer_object_path = os_strdup(entry.str_value);
    653 		} else if (os_strcmp(entry.key, "persistent") == 0 &&
    654 			   entry.type == DBUS_TYPE_BOOLEAN) {
    655 			persistent_group = entry.bool_value;
    656 		} else if (os_strcmp(entry.key, "join") == 0 &&
    657 			   entry.type == DBUS_TYPE_BOOLEAN) {
    658 			join = entry.bool_value;
    659 		} else if (os_strcmp(entry.key, "authorize_only") == 0 &&
    660 			   entry.type == DBUS_TYPE_BOOLEAN) {
    661 			authorize_only = entry.bool_value;
    662 		} else if (os_strcmp(entry.key, "frequency") == 0 &&
    663 			   entry.type == DBUS_TYPE_INT32) {
    664 			freq = entry.int32_value;
    665 			if (freq <= 0)
    666 				goto inv_args_clear;
    667 		} else if (os_strcmp(entry.key, "go_intent") == 0 &&
    668 			   entry.type == DBUS_TYPE_INT32) {
    669 			go_intent = entry.int32_value;
    670 			if ((go_intent < 0) || (go_intent > 15))
    671 				goto inv_args_clear;
    672 		} else if (os_strcmp(entry.key, "wps_method") == 0 &&
    673 			   entry.type == DBUS_TYPE_STRING) {
    674 			if (os_strcmp(entry.str_value, "pbc") == 0)
    675 				wps_method = WPS_PBC;
    676 			else if (os_strcmp(entry.str_value, "pin") == 0)
    677 				wps_method = WPS_PIN_DISPLAY;
    678 			else if (os_strcmp(entry.str_value, "display") == 0)
    679 				wps_method = WPS_PIN_DISPLAY;
    680 			else if (os_strcmp(entry.str_value, "keypad") == 0)
    681 				wps_method = WPS_PIN_KEYPAD;
    682 			else
    683 				goto inv_args_clear;
    684 		} else if (os_strcmp(entry.key, "pin") == 0 &&
    685 			   entry.type == DBUS_TYPE_STRING) {
    686 			pin = os_strdup(entry.str_value);
    687 		} else
    688 			goto inv_args_clear;
    689 
    690 		wpa_dbus_dict_entry_clear(&entry);
    691 	}
    692 
    693 	if (wps_method == WPS_NOT_READY ||
    694 	    parse_peer_object_path(peer_object_path, addr) < 0 ||
    695 	    !p2p_peer_known(wpa_s->global->p2p, addr))
    696 		goto inv_args;
    697 
    698 	/*
    699 	 * Validate the wps_method specified and the pin value.
    700 	 */
    701 	if ((!pin || !pin[0]) && wps_method == WPS_PIN_KEYPAD)
    702 		goto inv_args;
    703 
    704 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    705 
    706 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
    707 				   persistent_group, 0, join, authorize_only,
    708 				   go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
    709 				   NULL, 0, false);
    710 
    711 	if (new_pin >= 0) {
    712 		char npin[9];
    713 		char *generated_pin;
    714 
    715 		ret = os_snprintf(npin, sizeof(npin), "%08d", new_pin);
    716 		if (os_snprintf_error(sizeof(npin), ret)) {
    717 			reply = wpas_dbus_error_unknown_error(message,
    718 							      "invalid PIN");
    719 			goto out;
    720 		}
    721 		generated_pin = npin;
    722 		reply = dbus_message_new_method_return(message);
    723 		dbus_message_append_args(reply, DBUS_TYPE_STRING,
    724 					 &generated_pin, DBUS_TYPE_INVALID);
    725 	} else {
    726 		switch (new_pin) {
    727 		case -2:
    728 			err_msg =
    729 				"connect failed due to channel unavailability.";
    730 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
    731 			break;
    732 
    733 		case -3:
    734 			err_msg = "connect failed due to unsupported channel.";
    735 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
    736 			break;
    737 
    738 		default:
    739 			err_msg = "connect failed due to unspecified error.";
    740 			iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
    741 			break;
    742 		}
    743 
    744 		/*
    745 		 * TODO:
    746 		 * Do we need specialized errors corresponding to above
    747 		 * error conditions as against just returning a different
    748 		 * error message?
    749 		 */
    750 		reply = dbus_message_new_error(message, iface, err_msg);
    751 	}
    752 
    753 out:
    754 	os_free(peer_object_path);
    755 	os_free(pin);
    756 	return reply;
    757 inv_args_clear:
    758 	wpa_dbus_dict_entry_clear(&entry);
    759 inv_args:
    760 	reply = wpas_dbus_error_invalid_args(message, NULL);
    761 	goto out;
    762 }
    763 
    764 
    765 /**
    766  * wpas_dbus_handler_p2p_cancel - Cancel P2P group formation
    767  * @message: Pointer to incoming dbus message
    768  * @wpa_s: %wpa_supplicant data structure
    769  * Returns: NULL on success or DBus error on failure
    770  *
    771  * Handler for "Cancel" method call. Returns NULL if P2P cancel succeeds or DBus
    772  * error on P2P cancel failure
    773  */
    774 DBusMessage * wpas_dbus_handler_p2p_cancel(DBusMessage *message,
    775 					   struct wpa_supplicant *wpa_s)
    776 {
    777 	if (wpas_p2p_cancel(wpa_s))
    778 		return wpas_dbus_error_unknown_error(message,
    779 						     "P2P cancel failed");
    780 
    781 	return NULL;
    782 }
    783 
    784 
    785 DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
    786 					   struct wpa_supplicant *wpa_s)
    787 {
    788 	DBusMessageIter iter_dict;
    789 	DBusMessage *reply = NULL;
    790 	DBusMessageIter iter;
    791 	struct wpa_dbus_dict_entry entry;
    792 	char *peer_object_path = NULL;
    793 	char *pg_object_path = NULL;
    794 	char *iface = NULL;
    795 	u8 peer_addr[ETH_ALEN];
    796 	unsigned int group_id = 0;
    797 	int persistent = 0;
    798 	struct wpa_ssid *ssid;
    799 	const char *group_ifname;
    800 
    801 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
    802 		return reply;
    803 
    804 	dbus_message_iter_init(message, &iter);
    805 
    806 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
    807 		goto err;
    808 
    809 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
    810 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
    811 			goto err;
    812 
    813 		if (os_strcmp(entry.key, "peer") == 0 &&
    814 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
    815 			peer_object_path = os_strdup(entry.str_value);
    816 			wpa_dbus_dict_entry_clear(&entry);
    817 		} else if (os_strcmp(entry.key, "persistent_group_object") ==
    818 			   0 &&
    819 			   entry.type == DBUS_TYPE_OBJECT_PATH) {
    820 			pg_object_path = os_strdup(entry.str_value);
    821 			persistent = 1;
    822 			wpa_dbus_dict_entry_clear(&entry);
    823 		} else {
    824 			wpa_dbus_dict_entry_clear(&entry);
    825 			goto err;
    826 		}
    827 	}
    828 
    829 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
    830 	    !p2p_peer_known(wpa_s->global->p2p, peer_addr))
    831 		goto err;
    832 
    833 	/* Capture the interface name for the group first */
    834 	group_ifname = wpa_s->ifname;
    835 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    836 
    837 	if (persistent) {
    838 		char *net_id_str;
    839 		/*
    840 		 * A group ID is defined meaning we want to re-invoke a
    841 		 * persistent group
    842 		 */
    843 
    844 		iface = wpas_dbus_new_decompose_object_path(
    845 			pg_object_path,
    846 			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
    847 			&net_id_str);
    848 		if (iface == NULL || net_id_str == NULL ||
    849 		    !wpa_s->parent->dbus_new_path ||
    850 		    os_strcmp(iface, wpa_s->parent->dbus_new_path) != 0) {
    851 			reply = wpas_dbus_error_invalid_args(message,
    852 							     pg_object_path);
    853 			goto out;
    854 		}
    855 
    856 		group_id = strtoul(net_id_str, NULL, 10);
    857 		if (errno == EINVAL) {
    858 			reply = wpas_dbus_error_invalid_args(
    859 				message, pg_object_path);
    860 			goto out;
    861 		}
    862 
    863 		/* Get the SSID structure from the persistent group id */
    864 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
    865 		if (ssid == NULL || ssid->disabled != 2)
    866 			goto err;
    867 
    868 		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
    869 				    0, 0, 0, false) < 0) {
    870 			reply = wpas_dbus_error_unknown_error(
    871 				message,
    872 				"Failed to reinvoke a persistent group");
    873 			goto out;
    874 		}
    875 	} else {
    876 		/*
    877 		 * No group ID means propose to a peer to join my active group
    878 		 */
    879 		if (wpas_p2p_invite_group(wpa_s, group_ifname,
    880 					  peer_addr, NULL, false)) {
    881 			reply = wpas_dbus_error_unknown_error(
    882 				message, "Failed to join to an active group");
    883 			goto out;
    884 		}
    885 	}
    886 
    887 out:
    888 	os_free(iface);
    889 	os_free(pg_object_path);
    890 	os_free(peer_object_path);
    891 	return reply;
    892 
    893 err:
    894 	reply = wpas_dbus_error_invalid_args(message, NULL);
    895 	goto out;
    896 }
    897 
    898 
    899 DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
    900 						  struct wpa_supplicant *wpa_s)
    901 {
    902 	DBusMessageIter iter;
    903 	char *peer_object_path = NULL;
    904 	char *config_method = NULL;
    905 	u8 peer_addr[ETH_ALEN];
    906 
    907 	dbus_message_iter_init(message, &iter);
    908 	dbus_message_iter_get_basic(&iter, &peer_object_path);
    909 
    910 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
    911 		return wpas_dbus_error_invalid_args(message, NULL);
    912 
    913 	dbus_message_iter_next(&iter);
    914 	dbus_message_iter_get_basic(&iter, &config_method);
    915 
    916 	/*
    917 	 * Validation checks on config_method are being duplicated here
    918 	 * to be able to return invalid args reply since the error code
    919 	 * from p2p module are not granular enough (yet).
    920 	 */
    921 	if (os_strcmp(config_method, "display") &&
    922 	    os_strcmp(config_method, "keypad") &&
    923 	    os_strcmp(config_method, "pbc") &&
    924 	    os_strcmp(config_method, "pushbutton"))
    925 		return wpas_dbus_error_invalid_args(message, NULL);
    926 
    927 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    928 	if (!wpa_s)
    929 		return wpas_dbus_error_no_p2p_mgmt_iface(message);
    930 
    931 	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
    932 			       WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
    933 		return wpas_dbus_error_unknown_error(message,
    934 				"Failed to send provision discovery request");
    935 
    936 	return NULL;
    937 }
    938 
    939 
    940 /*
    941  * P2P Device property accessor methods.
    942  */
    943 
    944 dbus_bool_t wpas_dbus_getter_p2p_device_config(
    945 	const struct wpa_dbus_property_desc *property_desc,
    946 	DBusMessageIter *iter, DBusError *error, void *user_data)
    947 {
    948 	struct wpa_supplicant *wpa_s = user_data;
    949 	DBusMessageIter variant_iter, dict_iter;
    950 	DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
    951 		iter_secdev_dict_array;
    952 	const char *dev_name;
    953 	int num_vendor_extensions = 0;
    954 	int i;
    955 	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
    956 
    957 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
    958 		return FALSE;
    959 
    960 	wpa_s = wpa_s->global->p2p_init_wpa_s;
    961 
    962 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
    963 					      "a{sv}", &variant_iter) ||
    964 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
    965 		goto err_no_mem;
    966 
    967 	/* DeviceName */
    968 	dev_name = wpa_s->conf->device_name;
    969 	if (dev_name &&
    970 	    !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
    971 		goto err_no_mem;
    972 
    973 	/* Primary device type */
    974 	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
    975 					     (char *) wpa_s->conf->device_type,
    976 					     WPS_DEV_TYPE_LEN))
    977 		goto err_no_mem;
    978 
    979 	/* Secondary device types */
    980 	if (wpa_s->conf->num_sec_device_types) {
    981 		if (!wpa_dbus_dict_begin_array(&dict_iter,
    982 					       "SecondaryDeviceTypes",
    983 					       DBUS_TYPE_ARRAY_AS_STRING
    984 					       DBUS_TYPE_BYTE_AS_STRING,
    985 					       &iter_secdev_dict_entry,
    986 					       &iter_secdev_dict_val,
    987 					       &iter_secdev_dict_array))
    988 			goto err_no_mem;
    989 
    990 		for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
    991 			wpa_dbus_dict_bin_array_add_element(
    992 				&iter_secdev_dict_array,
    993 				wpa_s->conf->sec_device_type[i],
    994 				WPS_DEV_TYPE_LEN);
    995 
    996 		if (!wpa_dbus_dict_end_array(&dict_iter,
    997 					     &iter_secdev_dict_entry,
    998 					     &iter_secdev_dict_val,
    999 					     &iter_secdev_dict_array))
   1000 			goto err_no_mem;
   1001 	}
   1002 
   1003 	/* GO IP address */
   1004 	if (WPA_GET_BE32(wpa_s->conf->ip_addr_go) &&
   1005 	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
   1006 					     (char *) wpa_s->conf->ip_addr_go,
   1007 					     4))
   1008 		goto err_no_mem;
   1009 
   1010 	/* IP address mask */
   1011 	if (WPA_GET_BE32(wpa_s->conf->ip_addr_mask) &&
   1012 	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
   1013 					     (char *) wpa_s->conf->ip_addr_mask,
   1014 					     4))
   1015 		goto err_no_mem;
   1016 
   1017 	/* IP address start */
   1018 	if (WPA_GET_BE32(wpa_s->conf->ip_addr_start) &&
   1019 	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrStart",
   1020 					     (char *)
   1021 					     wpa_s->conf->ip_addr_start,
   1022 					     4))
   1023 		goto err_no_mem;
   1024 
   1025 	/* IP address end */
   1026 	if (WPA_GET_BE32(wpa_s->conf->ip_addr_end) &&
   1027 	    !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrEnd",
   1028 					     (char *) wpa_s->conf->ip_addr_end,
   1029 					     4))
   1030 		goto err_no_mem;
   1031 
   1032 	/* Vendor Extensions */
   1033 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
   1034 		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
   1035 			continue;
   1036 		vendor_ext[num_vendor_extensions++] =
   1037 			wpa_s->conf->wps_vendor_ext[i];
   1038 	}
   1039 
   1040 	if ((num_vendor_extensions &&
   1041 	     !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
   1042 						"VendorExtension",
   1043 						vendor_ext,
   1044 						num_vendor_extensions)) ||
   1045 	    !wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
   1046 					 wpa_s->conf->p2p_go_intent) ||
   1047 	    !wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
   1048 				       wpa_s->conf->persistent_reconnect) ||
   1049 	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
   1050 					 wpa_s->conf->p2p_listen_reg_class) ||
   1051 	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
   1052 					 wpa_s->conf->p2p_listen_channel) ||
   1053 	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
   1054 					 wpa_s->conf->p2p_oper_reg_class) ||
   1055 	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
   1056 					 wpa_s->conf->p2p_oper_channel) ||
   1057 	    (wpa_s->conf->p2p_ssid_postfix &&
   1058 	     !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
   1059 					  wpa_s->conf->p2p_ssid_postfix)) ||
   1060 	    !wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
   1061 				       wpa_s->conf->p2p_intra_bss) ||
   1062 	    !wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
   1063 					 wpa_s->conf->p2p_group_idle) ||
   1064 	    !wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
   1065 					 wpa_s->conf->disassoc_low_ack) ||
   1066 	    !wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
   1067 				       wpa_s->conf->p2p_no_group_iface) ||
   1068 	    !wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
   1069 					 wpa_s->conf->p2p_search_delay) ||
   1070 	    !wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
   1071 	    !dbus_message_iter_close_container(iter, &variant_iter))
   1072 		goto err_no_mem;
   1073 
   1074 	return TRUE;
   1075 
   1076 err_no_mem:
   1077 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1078 	return FALSE;
   1079 }
   1080 
   1081 
   1082 dbus_bool_t wpas_dbus_setter_p2p_device_config(
   1083 	const struct wpa_dbus_property_desc *property_desc,
   1084 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1085 {
   1086 	struct wpa_supplicant *wpa_s = user_data;
   1087 	DBusMessageIter variant_iter, iter_dict;
   1088 	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
   1089 	unsigned int i;
   1090 
   1091 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
   1092 		return FALSE;
   1093 
   1094 	wpa_s = wpa_s->global->p2p_init_wpa_s;
   1095 
   1096 	dbus_message_iter_recurse(iter, &variant_iter);
   1097 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
   1098 		return FALSE;
   1099 
   1100 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   1101 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
   1102 			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
   1103 					     "invalid message format");
   1104 			return FALSE;
   1105 		}
   1106 
   1107 		if (os_strcmp(entry.key, "DeviceName") == 0) {
   1108 			char *devname;
   1109 
   1110 			if (entry.type != DBUS_TYPE_STRING ||
   1111 			    os_strlen(entry.str_value) > WPS_DEV_NAME_MAX_LEN)
   1112 				goto error;
   1113 
   1114 			devname = os_strdup(entry.str_value);
   1115 			if (devname == NULL)
   1116 				goto err_no_mem_clear;
   1117 
   1118 			os_free(wpa_s->conf->device_name);
   1119 			wpa_s->conf->device_name = devname;
   1120 
   1121 			wpa_s->conf->changed_parameters |=
   1122 				CFG_CHANGED_DEVICE_NAME;
   1123 		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
   1124 			if (entry.type != DBUS_TYPE_ARRAY ||
   1125 			    entry.array_type != DBUS_TYPE_BYTE ||
   1126 			    entry.array_len != WPS_DEV_TYPE_LEN)
   1127 				goto error;
   1128 
   1129 			os_memcpy(wpa_s->conf->device_type,
   1130 				  entry.bytearray_value,
   1131 				  WPS_DEV_TYPE_LEN);
   1132 			wpa_s->conf->changed_parameters |=
   1133 				CFG_CHANGED_DEVICE_TYPE;
   1134 		} else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
   1135 			if (entry.type != DBUS_TYPE_ARRAY ||
   1136 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
   1137 			    entry.array_len > MAX_SEC_DEVICE_TYPES)
   1138 				goto error;
   1139 
   1140 			for (i = 0; i < entry.array_len; i++)
   1141 				if (wpabuf_len(entry.binarray_value[i]) !=
   1142 				    WPS_DEV_TYPE_LEN)
   1143 					goto err_no_mem_clear;
   1144 			for (i = 0; i < entry.array_len; i++)
   1145 				os_memcpy(wpa_s->conf->sec_device_type[i],
   1146 					  wpabuf_head(entry.binarray_value[i]),
   1147 					  WPS_DEV_TYPE_LEN);
   1148 			wpa_s->conf->num_sec_device_types = entry.array_len;
   1149 			wpa_s->conf->changed_parameters |=
   1150 					CFG_CHANGED_SEC_DEVICE_TYPE;
   1151 		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
   1152 			if (entry.type != DBUS_TYPE_ARRAY ||
   1153 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
   1154 			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
   1155 				goto error;
   1156 
   1157 			wpa_s->conf->changed_parameters |=
   1158 				CFG_CHANGED_VENDOR_EXTENSION;
   1159 
   1160 			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
   1161 				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
   1162 				if (i < entry.array_len) {
   1163 					wpa_s->conf->wps_vendor_ext[i] =
   1164 						entry.binarray_value[i];
   1165 					entry.binarray_value[i] = NULL;
   1166 				} else
   1167 					wpa_s->conf->wps_vendor_ext[i] = NULL;
   1168 			}
   1169 		} else if (os_strcmp(entry.key, "GOIntent") == 0 &&
   1170 			   entry.type == DBUS_TYPE_UINT32 &&
   1171 			   (entry.uint32_value <= 15))
   1172 			wpa_s->conf->p2p_go_intent = entry.uint32_value;
   1173 		else if (os_strcmp(entry.key, "PersistentReconnect") == 0 &&
   1174 			 entry.type == DBUS_TYPE_BOOLEAN)
   1175 			wpa_s->conf->persistent_reconnect = entry.bool_value;
   1176 		else if (os_strcmp(entry.key, "ListenRegClass") == 0 &&
   1177 			 entry.type == DBUS_TYPE_UINT32) {
   1178 			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
   1179 			wpa_s->conf->changed_parameters |=
   1180 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
   1181 		} else if (os_strcmp(entry.key, "ListenChannel") == 0 &&
   1182 			   entry.type == DBUS_TYPE_UINT32) {
   1183 			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
   1184 			wpa_s->conf->changed_parameters |=
   1185 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
   1186 		} else if (os_strcmp(entry.key, "OperRegClass") == 0 &&
   1187 			   entry.type == DBUS_TYPE_UINT32) {
   1188 			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
   1189 			wpa_s->conf->changed_parameters |=
   1190 				CFG_CHANGED_P2P_OPER_CHANNEL;
   1191 		} else if (os_strcmp(entry.key, "OperChannel") == 0 &&
   1192 			   entry.type == DBUS_TYPE_UINT32) {
   1193 			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
   1194 			wpa_s->conf->changed_parameters |=
   1195 				CFG_CHANGED_P2P_OPER_CHANNEL;
   1196 		} else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
   1197 			char *postfix;
   1198 
   1199 			if (entry.type != DBUS_TYPE_STRING)
   1200 				goto error;
   1201 
   1202 			postfix = os_strdup(entry.str_value);
   1203 			if (!postfix)
   1204 				goto err_no_mem_clear;
   1205 
   1206 			os_free(wpa_s->conf->p2p_ssid_postfix);
   1207 			wpa_s->conf->p2p_ssid_postfix = postfix;
   1208 
   1209 			wpa_s->conf->changed_parameters |=
   1210 					CFG_CHANGED_P2P_SSID_POSTFIX;
   1211 		} else if (os_strcmp(entry.key, "IntraBss") == 0 &&
   1212 			   entry.type == DBUS_TYPE_BOOLEAN) {
   1213 			wpa_s->conf->p2p_intra_bss = entry.bool_value;
   1214 			wpa_s->conf->changed_parameters |=
   1215 				CFG_CHANGED_P2P_INTRA_BSS;
   1216 		} else if (os_strcmp(entry.key, "IpAddrGo") == 0) {
   1217 			if (!wpas_dbus_validate_dbus_ipaddr(entry))
   1218 				goto error;
   1219 			os_memcpy(wpa_s->conf->ip_addr_go,
   1220 				  entry.bytearray_value, 4);
   1221 		} else if (os_strcmp(entry.key, "IpAddrMask") == 0) {
   1222 			if (!wpas_dbus_validate_dbus_ipaddr(entry))
   1223 				goto error;
   1224 			os_memcpy(wpa_s->conf->ip_addr_mask,
   1225 				  entry.bytearray_value, 4);
   1226 		} else if (os_strcmp(entry.key, "IpAddrStart") == 0) {
   1227 			if (!wpas_dbus_validate_dbus_ipaddr(entry))
   1228 				goto error;
   1229 			os_memcpy(wpa_s->conf->ip_addr_start,
   1230 				  entry.bytearray_value, 4);
   1231 		} else if (os_strcmp(entry.key, "IpAddrEnd") == 0) {
   1232 			if (!wpas_dbus_validate_dbus_ipaddr(entry))
   1233 				goto error;
   1234 			os_memcpy(wpa_s->conf->ip_addr_end,
   1235 				  entry.bytearray_value, 4);
   1236 		} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
   1237 			   entry.type == DBUS_TYPE_UINT32)
   1238 			wpa_s->conf->p2p_group_idle = entry.uint32_value;
   1239 		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
   1240 			 entry.type == DBUS_TYPE_UINT32)
   1241 			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
   1242 		else if (os_strcmp(entry.key, "NoGroupIface") == 0 &&
   1243 			 entry.type == DBUS_TYPE_BOOLEAN)
   1244 			wpa_s->conf->p2p_no_group_iface = entry.bool_value;
   1245 		else if (os_strcmp(entry.key, "p2p_search_delay") == 0 &&
   1246 			 entry.type == DBUS_TYPE_UINT32)
   1247 			wpa_s->conf->p2p_search_delay = entry.uint32_value;
   1248 		else
   1249 			goto error;
   1250 
   1251 		wpa_dbus_dict_entry_clear(&entry);
   1252 	}
   1253 
   1254 	if (wpa_s->conf->changed_parameters) {
   1255 		/* Some changed parameters requires to update config*/
   1256 		wpa_supplicant_update_config(wpa_s);
   1257 	}
   1258 
   1259 	return TRUE;
   1260 
   1261  error:
   1262 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
   1263 			     "invalid message format");
   1264 	wpa_dbus_dict_entry_clear(&entry);
   1265 	return FALSE;
   1266 
   1267  err_no_mem_clear:
   1268 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1269 	wpa_dbus_dict_entry_clear(&entry);
   1270 	return FALSE;
   1271 }
   1272 
   1273 
   1274 dbus_bool_t wpas_dbus_getter_p2p_peers(
   1275 	const struct wpa_dbus_property_desc *property_desc,
   1276 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1277 {
   1278 	struct wpa_supplicant *wpa_s = user_data;
   1279 	struct p2p_data *p2p = wpa_s->global->p2p;
   1280 	int next = 0, i = 0;
   1281 	int num = 0, out_of_mem = 0;
   1282 	const u8 *addr;
   1283 	const struct p2p_peer_info *peer_info = NULL;
   1284 	dbus_bool_t success = FALSE;
   1285 
   1286 	struct dl_list peer_objpath_list;
   1287 	struct peer_objpath_node {
   1288 		struct dl_list list;
   1289 		char path[WPAS_DBUS_OBJECT_PATH_MAX];
   1290 	} *node, *tmp;
   1291 
   1292 	char **peer_obj_paths = NULL;
   1293 
   1294 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error) ||
   1295 	    !wpa_s->parent->parent->dbus_new_path)
   1296 		return FALSE;
   1297 
   1298 	dl_list_init(&peer_objpath_list);
   1299 
   1300 	/* Get the first peer info */
   1301 	peer_info = p2p_get_peer_found(p2p, NULL, next);
   1302 
   1303 	/* Get next and accumulate them */
   1304 	next = 1;
   1305 	while (peer_info != NULL) {
   1306 		node = os_zalloc(sizeof(struct peer_objpath_node));
   1307 		if (!node) {
   1308 			out_of_mem = 1;
   1309 			goto error;
   1310 		}
   1311 
   1312 		addr = peer_info->p2p_device_addr;
   1313 		os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
   1314 			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
   1315 			    "/" COMPACT_MACSTR,
   1316 			    wpa_s->parent->parent->dbus_new_path,
   1317 			    MAC2STR(addr));
   1318 		dl_list_add_tail(&peer_objpath_list, &node->list);
   1319 		num++;
   1320 
   1321 		peer_info = p2p_get_peer_found(p2p, addr, next);
   1322 	}
   1323 
   1324 	/*
   1325 	 * Now construct the peer object paths in a form suitable for
   1326 	 * array_property_getter helper below.
   1327 	 */
   1328 	peer_obj_paths = os_calloc(num, sizeof(char *));
   1329 
   1330 	if (!peer_obj_paths) {
   1331 		out_of_mem = 1;
   1332 		goto error;
   1333 	}
   1334 
   1335 	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
   1336 			      struct peer_objpath_node, list)
   1337 		peer_obj_paths[i++] = node->path;
   1338 
   1339 	success = wpas_dbus_simple_array_property_getter(iter,
   1340 							 DBUS_TYPE_OBJECT_PATH,
   1341 							 peer_obj_paths, num,
   1342 							 error);
   1343 
   1344 error:
   1345 	if (peer_obj_paths)
   1346 		os_free(peer_obj_paths);
   1347 
   1348 	dl_list_for_each_safe(node, tmp, &peer_objpath_list,
   1349 			      struct peer_objpath_node, list) {
   1350 		dl_list_del(&node->list);
   1351 		os_free(node);
   1352 	}
   1353 	if (out_of_mem)
   1354 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1355 
   1356 	return success;
   1357 }
   1358 
   1359 
   1360 enum wpas_p2p_role {
   1361 	WPAS_P2P_ROLE_DEVICE,
   1362 	WPAS_P2P_ROLE_GO,
   1363 	WPAS_P2P_ROLE_CLIENT,
   1364 };
   1365 
   1366 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
   1367 {
   1368 	struct wpa_ssid *ssid = wpa_s->current_ssid;
   1369 
   1370 	if (!ssid)
   1371 		return WPAS_P2P_ROLE_DEVICE;
   1372 	if (wpa_s->wpa_state != WPA_COMPLETED)
   1373 		return WPAS_P2P_ROLE_DEVICE;
   1374 
   1375 	switch (ssid->mode) {
   1376 	case WPAS_MODE_P2P_GO:
   1377 	case WPAS_MODE_P2P_GROUP_FORMATION:
   1378 		return WPAS_P2P_ROLE_GO;
   1379 	case WPAS_MODE_INFRA:
   1380 		if (ssid->p2p_group)
   1381 			return WPAS_P2P_ROLE_CLIENT;
   1382 		return WPAS_P2P_ROLE_DEVICE;
   1383 	default:
   1384 		return WPAS_P2P_ROLE_DEVICE;
   1385 	}
   1386 }
   1387 
   1388 
   1389 dbus_bool_t wpas_dbus_getter_p2p_role(
   1390 	const struct wpa_dbus_property_desc *property_desc,
   1391 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1392 {
   1393 	struct wpa_supplicant *wpa_s = user_data;
   1394 	char *str;
   1395 
   1396 	switch (wpas_get_p2p_role(wpa_s)) {
   1397 	case WPAS_P2P_ROLE_GO:
   1398 		str = "GO";
   1399 		break;
   1400 	case WPAS_P2P_ROLE_CLIENT:
   1401 		str = "client";
   1402 		break;
   1403 	default:
   1404 		str = "device";
   1405 		break;
   1406 	}
   1407 
   1408 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
   1409 						error);
   1410 }
   1411 
   1412 
   1413 dbus_bool_t wpas_dbus_getter_p2p_group(
   1414 	const struct wpa_dbus_property_desc *property_desc,
   1415 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1416 {
   1417 	struct wpa_supplicant *wpa_s = user_data;
   1418 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
   1419 	char *dbus_groupobj_path = path_buf;
   1420 
   1421 	if (wpa_s->dbus_groupobj_path == NULL)
   1422 		os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
   1423 			    "/");
   1424 	else
   1425 		os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
   1426 			    "%s", wpa_s->dbus_groupobj_path);
   1427 
   1428 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
   1429 						&dbus_groupobj_path, error);
   1430 }
   1431 
   1432 
   1433 dbus_bool_t wpas_dbus_getter_p2p_peergo(
   1434 	const struct wpa_dbus_property_desc *property_desc,
   1435 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1436 {
   1437 	struct wpa_supplicant *wpa_s = user_data;
   1438 	char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
   1439 
   1440 	if (!wpa_s->parent->parent->dbus_new_path)
   1441 		return FALSE;
   1442 
   1443 	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
   1444 		os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
   1445 	else
   1446 		os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
   1447 			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
   1448 			    COMPACT_MACSTR,
   1449 			    wpa_s->parent->parent->dbus_new_path,
   1450 			    MAC2STR(wpa_s->go_dev_addr));
   1451 
   1452 	path = go_peer_obj_path;
   1453 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
   1454 						&path, error);
   1455 }
   1456 
   1457 
   1458 /*
   1459  * Peer object properties accessor methods
   1460  */
   1461 
   1462 dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(
   1463 	const struct wpa_dbus_property_desc *property_desc,
   1464 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1465 {
   1466 	struct peer_handler_args *peer_args = user_data;
   1467 	const struct p2p_peer_info *info;
   1468 	char *tmp;
   1469 
   1470 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
   1471 		return FALSE;
   1472 
   1473 	/* get the peer info */
   1474 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1475 				  peer_args->p2p_device_addr, 0);
   1476 	if (info == NULL) {
   1477 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1478 			       "failed to find peer");
   1479 		return FALSE;
   1480 	}
   1481 
   1482 	tmp = os_strdup(info->device_name);
   1483 	if (!tmp) {
   1484 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1485 		return FALSE;
   1486 	}
   1487 
   1488 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
   1489 					      error)) {
   1490 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1491 		os_free(tmp);
   1492 		return FALSE;
   1493 	}
   1494 
   1495 	os_free(tmp);
   1496 	return TRUE;
   1497 }
   1498 
   1499 
   1500 dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(
   1501 	const struct wpa_dbus_property_desc *property_desc,
   1502 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1503 {
   1504 	struct peer_handler_args *peer_args = user_data;
   1505 	const struct p2p_peer_info *info;
   1506 	char *tmp;
   1507 
   1508 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
   1509 		return FALSE;
   1510 
   1511 	/* get the peer info */
   1512 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1513 				  peer_args->p2p_device_addr, 0);
   1514 	if (info == NULL) {
   1515 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
   1516 		return FALSE;
   1517 	}
   1518 
   1519 	tmp = os_strdup(info->manufacturer);
   1520 	if (!tmp) {
   1521 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1522 		return FALSE;
   1523 	}
   1524 
   1525 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
   1526 					      error)) {
   1527 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1528 		os_free(tmp);
   1529 		return FALSE;
   1530 	}
   1531 
   1532 	os_free(tmp);
   1533 	return TRUE;
   1534 }
   1535 
   1536 
   1537 dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(
   1538 	const struct wpa_dbus_property_desc *property_desc,
   1539 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1540 {
   1541 	struct peer_handler_args *peer_args = user_data;
   1542 	const struct p2p_peer_info *info;
   1543 	char *tmp;
   1544 
   1545 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
   1546 		return FALSE;
   1547 
   1548 	/* get the peer info */
   1549 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1550 				  peer_args->p2p_device_addr, 0);
   1551 	if (info == NULL) {
   1552 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
   1553 		return FALSE;
   1554 	}
   1555 
   1556 	tmp = os_strdup(info->model_name);
   1557 	if (!tmp) {
   1558 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1559 		return FALSE;
   1560 	}
   1561 
   1562 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
   1563 					      error)) {
   1564 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1565 		os_free(tmp);
   1566 		return FALSE;
   1567 	}
   1568 
   1569 	os_free(tmp);
   1570 	return TRUE;
   1571 }
   1572 
   1573 
   1574 dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(
   1575 	const struct wpa_dbus_property_desc *property_desc,
   1576 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1577 {
   1578 	struct peer_handler_args *peer_args = user_data;
   1579 	const struct p2p_peer_info *info;
   1580 	char *tmp;
   1581 
   1582 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
   1583 		return FALSE;
   1584 
   1585 	/* get the peer info */
   1586 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1587 				  peer_args->p2p_device_addr, 0);
   1588 	if (info == NULL) {
   1589 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
   1590 		return FALSE;
   1591 	}
   1592 
   1593 	tmp = os_strdup(info->model_number);
   1594 	if (!tmp) {
   1595 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1596 		return FALSE;
   1597 	}
   1598 
   1599 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
   1600 					      error)) {
   1601 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1602 		os_free(tmp);
   1603 		return FALSE;
   1604 	}
   1605 
   1606 	os_free(tmp);
   1607 	return TRUE;
   1608 }
   1609 
   1610 
   1611 dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(
   1612 	const struct wpa_dbus_property_desc *property_desc,
   1613 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1614 {
   1615 	struct peer_handler_args *peer_args = user_data;
   1616 	const struct p2p_peer_info *info;
   1617 	char *tmp;
   1618 
   1619 	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
   1620 		return FALSE;
   1621 
   1622 	/* get the peer info */
   1623 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1624 				  peer_args->p2p_device_addr, 0);
   1625 	if (info == NULL) {
   1626 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
   1627 		return FALSE;
   1628 	}
   1629 
   1630 	tmp = os_strdup(info->serial_number);
   1631 	if (!tmp) {
   1632 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1633 		return FALSE;
   1634 	}
   1635 
   1636 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
   1637 					      error)) {
   1638 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1639 		os_free(tmp);
   1640 		return FALSE;
   1641 	}
   1642 
   1643 	os_free(tmp);
   1644 	return TRUE;
   1645 }
   1646 
   1647 
   1648 dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
   1649 	const struct wpa_dbus_property_desc *property_desc,
   1650 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1651 {
   1652 	struct peer_handler_args *peer_args = user_data;
   1653 	const struct p2p_peer_info *info;
   1654 
   1655 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1656 				  peer_args->p2p_device_addr, 0);
   1657 	if (info == NULL) {
   1658 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1659 			       "failed to find peer");
   1660 		return FALSE;
   1661 	}
   1662 
   1663 	if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
   1664 						    (char *)
   1665 						    info->pri_dev_type,
   1666 						    WPS_DEV_TYPE_LEN, error)) {
   1667 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1668 		return FALSE;
   1669 	}
   1670 
   1671 	return TRUE;
   1672 }
   1673 
   1674 
   1675 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(
   1676 	const struct wpa_dbus_property_desc *property_desc,
   1677 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1678 {
   1679 	struct peer_handler_args *peer_args = user_data;
   1680 	const struct p2p_peer_info *info;
   1681 
   1682 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1683 				  peer_args->p2p_device_addr, 0);
   1684 	if (info == NULL) {
   1685 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1686 			       "failed to find peer");
   1687 		return FALSE;
   1688 	}
   1689 
   1690 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
   1691 					      &info->config_methods, error)) {
   1692 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1693 		return FALSE;
   1694 	}
   1695 
   1696 	return TRUE;
   1697 }
   1698 
   1699 
   1700 dbus_bool_t wpas_dbus_getter_p2p_peer_level(
   1701 	const struct wpa_dbus_property_desc *property_desc,
   1702 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1703 {
   1704 	struct peer_handler_args *peer_args = user_data;
   1705 	const struct p2p_peer_info *info;
   1706 
   1707 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1708 				  peer_args->p2p_device_addr, 0);
   1709 	if (info == NULL) {
   1710 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1711 			       "failed to find peer");
   1712 		return FALSE;
   1713 	}
   1714 
   1715 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
   1716 					      &info->level, error)) {
   1717 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1718 		return FALSE;
   1719 	}
   1720 
   1721 	return TRUE;
   1722 }
   1723 
   1724 
   1725 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(
   1726 	const struct wpa_dbus_property_desc *property_desc,
   1727 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1728 {
   1729 	struct peer_handler_args *peer_args = user_data;
   1730 	const struct p2p_peer_info *info;
   1731 
   1732 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1733 				  peer_args->p2p_device_addr, 0);
   1734 	if (info == NULL) {
   1735 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1736 			       "failed to find peer");
   1737 		return FALSE;
   1738 	}
   1739 
   1740 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
   1741 					      &info->dev_capab, error)) {
   1742 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1743 		return FALSE;
   1744 	}
   1745 
   1746 	return TRUE;
   1747 }
   1748 
   1749 
   1750 dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(
   1751 	const struct wpa_dbus_property_desc *property_desc,
   1752 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1753 {
   1754 	struct peer_handler_args *peer_args = user_data;
   1755 	const struct p2p_peer_info *info;
   1756 
   1757 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1758 				  peer_args->p2p_device_addr, 0);
   1759 	if (info == NULL) {
   1760 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1761 			       "failed to find peer");
   1762 		return FALSE;
   1763 	}
   1764 
   1765 	if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
   1766 					      &info->group_capab, error)) {
   1767 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   1768 		return FALSE;
   1769 	}
   1770 
   1771 	return TRUE;
   1772 }
   1773 
   1774 
   1775 dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
   1776 	const struct wpa_dbus_property_desc *property_desc,
   1777 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1778 {
   1779 	struct peer_handler_args *peer_args = user_data;
   1780 	const struct p2p_peer_info *info;
   1781 	DBusMessageIter variant_iter, array_iter;
   1782 
   1783 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1784 				  peer_args->p2p_device_addr, 0);
   1785 	if (info == NULL) {
   1786 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
   1787 		return FALSE;
   1788 	}
   1789 
   1790 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
   1791 					      DBUS_TYPE_ARRAY_AS_STRING
   1792 					      DBUS_TYPE_ARRAY_AS_STRING
   1793 					      DBUS_TYPE_BYTE_AS_STRING,
   1794 					      &variant_iter) ||
   1795 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
   1796 					      DBUS_TYPE_ARRAY_AS_STRING
   1797 					      DBUS_TYPE_BYTE_AS_STRING,
   1798 					      &array_iter)) {
   1799 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1800 			       "%s: failed to construct message 1", __func__);
   1801 		return FALSE;
   1802 	}
   1803 
   1804 	if (info->wps_sec_dev_type_list_len) {
   1805 		const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
   1806 		int num_sec_device_types =
   1807 			info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
   1808 		int i;
   1809 		DBusMessageIter inner_array_iter;
   1810 
   1811 		for (i = 0; i < num_sec_device_types; i++) {
   1812 			if (!dbus_message_iter_open_container(
   1813 				    &array_iter, DBUS_TYPE_ARRAY,
   1814 				    DBUS_TYPE_BYTE_AS_STRING,
   1815 				    &inner_array_iter) ||
   1816 			    !dbus_message_iter_append_fixed_array(
   1817 				    &inner_array_iter, DBUS_TYPE_BYTE,
   1818 				    &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
   1819 			    !dbus_message_iter_close_container(
   1820 				    &array_iter, &inner_array_iter)) {
   1821 				dbus_set_error(error, DBUS_ERROR_FAILED,
   1822 					       "%s: failed to construct message 2 (%d)",
   1823 					       __func__, i);
   1824 				return FALSE;
   1825 			}
   1826 
   1827 			sec_dev_type_list += WPS_DEV_TYPE_LEN;
   1828 		}
   1829 	}
   1830 
   1831 	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
   1832 	    !dbus_message_iter_close_container(iter, &variant_iter)) {
   1833 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1834 			       "%s: failed to construct message 3", __func__);
   1835 		return FALSE;
   1836 	}
   1837 
   1838 	return TRUE;
   1839 }
   1840 
   1841 
   1842 dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(
   1843 	const struct wpa_dbus_property_desc *property_desc,
   1844 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1845 {
   1846 	struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
   1847 	unsigned int i, num = 0;
   1848 	struct peer_handler_args *peer_args = user_data;
   1849 	const struct p2p_peer_info *info;
   1850 
   1851 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1852 				  peer_args->p2p_device_addr, 0);
   1853 	if (info == NULL) {
   1854 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1855 			       "failed to find peer");
   1856 		return FALSE;
   1857 	}
   1858 
   1859 	/* Add WPS vendor extensions attribute */
   1860 	os_memset(vendor_extension, 0, sizeof(vendor_extension));
   1861 	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
   1862 		if (info->wps_vendor_ext[i] == NULL)
   1863 			continue;
   1864 		vendor_extension[num] = info->wps_vendor_ext[i];
   1865 		num++;
   1866 	}
   1867 
   1868 	if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
   1869 							  vendor_extension,
   1870 							  num, error))
   1871 		return FALSE;
   1872 
   1873 	return TRUE;
   1874 }
   1875 
   1876 
   1877 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(
   1878 	const struct wpa_dbus_property_desc *property_desc,
   1879 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1880 {
   1881 	struct peer_handler_args *peer_args = user_data;
   1882 	const struct p2p_peer_info *info;
   1883 
   1884 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1885 				  peer_args->p2p_device_addr, 0);
   1886 	if (info == NULL) {
   1887 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1888 			       "failed to find peer");
   1889 		return FALSE;
   1890 	}
   1891 
   1892 	if (info->wfd_subelems == NULL)
   1893 		return wpas_dbus_simple_array_property_getter(iter,
   1894 							      DBUS_TYPE_BYTE,
   1895 							      NULL, 0, error);
   1896 
   1897 	return wpas_dbus_simple_array_property_getter(
   1898 		iter, DBUS_TYPE_BYTE, (char *) info->wfd_subelems->buf,
   1899 		info->wfd_subelems->used, error);
   1900 }
   1901 
   1902 
   1903 dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(
   1904 	const struct wpa_dbus_property_desc *property_desc,
   1905 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1906 {
   1907 	struct peer_handler_args *peer_args = user_data;
   1908 	const struct p2p_peer_info *info;
   1909 
   1910 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1911 				  peer_args->p2p_device_addr, 0);
   1912 	if (info == NULL) {
   1913 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1914 			       "failed to find peer");
   1915 		return FALSE;
   1916 	}
   1917 
   1918 	return wpas_dbus_simple_array_property_getter(
   1919 		iter, DBUS_TYPE_BYTE, (char *) info->p2p_device_addr,
   1920 		ETH_ALEN, error);
   1921 }
   1922 
   1923 
   1924 struct peer_group_data {
   1925 	struct wpa_supplicant *wpa_s;
   1926 	const struct p2p_peer_info *info;
   1927 	char **paths;
   1928 	unsigned int nb_paths;
   1929 	int error;
   1930 };
   1931 
   1932 
   1933 static int match_group_where_peer_is_client(struct p2p_group *group,
   1934 					    void *user_data)
   1935 {
   1936 	struct peer_group_data *data = user_data;
   1937 	const struct p2p_group_config *cfg;
   1938 	struct wpa_supplicant *wpa_s_go;
   1939 	char **paths;
   1940 
   1941 	if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
   1942 		return 1;
   1943 
   1944 	cfg = p2p_group_get_config(group);
   1945 
   1946 	wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
   1947 					 cfg->ssid_len);
   1948 	if (wpa_s_go == NULL)
   1949 		return 1;
   1950 
   1951 	paths = os_realloc_array(data->paths, data->nb_paths + 1,
   1952 				 sizeof(char *));
   1953 	if (paths == NULL)
   1954 		goto out_of_memory;
   1955 
   1956 	data->paths = paths;
   1957 	data->paths[data->nb_paths] = wpa_s_go->dbus_groupobj_path;
   1958 	data->nb_paths++;
   1959 
   1960 	return 1;
   1961 
   1962 out_of_memory:
   1963 	data->error = ENOMEM;
   1964 	return 0;
   1965 }
   1966 
   1967 
   1968 dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
   1969 	const struct wpa_dbus_property_desc *property_desc,
   1970 	DBusMessageIter *iter, DBusError *error, void *user_data)
   1971 {
   1972 	struct peer_handler_args *peer_args = user_data;
   1973 	const struct p2p_peer_info *info;
   1974 	struct peer_group_data data;
   1975 	struct wpa_supplicant *wpa_s, *wpa_s_go;
   1976 	dbus_bool_t success = FALSE;
   1977 
   1978 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   1979 				  peer_args->p2p_device_addr, 0);
   1980 	if (info == NULL) {
   1981 		dbus_set_error(error, DBUS_ERROR_FAILED,
   1982 			       "failed to find peer");
   1983 		return FALSE;
   1984 	}
   1985 
   1986 	os_memset(&data, 0, sizeof(data));
   1987 
   1988 	wpa_s = peer_args->wpa_s;
   1989 	wpa_s = wpa_s->global->p2p_init_wpa_s;
   1990 	if (!wpa_s)
   1991 		return no_p2p_mgmt_interface(error);
   1992 
   1993 	wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
   1994 	if (wpa_s_go) {
   1995 		data.paths = os_calloc(1, sizeof(char *));
   1996 		if (data.paths == NULL)
   1997 			goto out_of_memory;
   1998 		data.paths[0] = wpa_s_go->dbus_groupobj_path;
   1999 		data.nb_paths = 1;
   2000 	}
   2001 
   2002 	data.wpa_s = peer_args->wpa_s;
   2003 	data.info = info;
   2004 
   2005 	p2p_loop_on_all_groups(peer_args->wpa_s->global->p2p,
   2006 			       match_group_where_peer_is_client, &data);
   2007 	if (data.error)
   2008 		goto out_of_memory;
   2009 
   2010 	if (data.paths == NULL) {
   2011 		return wpas_dbus_simple_array_property_getter(
   2012 			iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
   2013 	}
   2014 
   2015 	success = wpas_dbus_simple_array_property_getter(iter,
   2016 							 DBUS_TYPE_OBJECT_PATH,
   2017 							 data.paths,
   2018 							 data.nb_paths, error);
   2019 	goto out;
   2020 
   2021 out_of_memory:
   2022 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   2023 out:
   2024 	os_free(data.paths);
   2025 	return success;
   2026 }
   2027 
   2028 dbus_bool_t wpas_dbus_getter_p2p_peer_vsie(
   2029 	const struct wpa_dbus_property_desc *property_desc,
   2030 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2031 {
   2032 	struct peer_handler_args *peer_args = user_data;
   2033 	const struct p2p_peer_info *info;
   2034 
   2035 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
   2036 				  peer_args->p2p_device_addr, 0);
   2037 	if (!info) {
   2038 		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
   2039 		return FALSE;
   2040 	}
   2041 
   2042 	if (!info->vendor_elems)
   2043 		return wpas_dbus_simple_array_property_getter(iter,
   2044 							      DBUS_TYPE_BYTE,
   2045 							      NULL, 0, error);
   2046 
   2047 	return wpas_dbus_simple_array_property_getter(
   2048 		iter, DBUS_TYPE_BYTE, (char *) info->vendor_elems->buf,
   2049 		info->vendor_elems->used, error);
   2050 }
   2051 
   2052 
   2053 /**
   2054  * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
   2055  * @iter: Pointer to incoming dbus message iter
   2056  * @error: Location to store error on failure
   2057  * @user_data: Function specific data
   2058  * Returns: TRUE on success, FALSE on failure
   2059  *
   2060  * Getter for "PersistentGroups" property.
   2061  */
   2062 dbus_bool_t wpas_dbus_getter_persistent_groups(
   2063 	const struct wpa_dbus_property_desc *property_desc,
   2064 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2065 {
   2066 	struct wpa_supplicant *wpa_s = user_data;
   2067 	struct wpa_ssid *ssid;
   2068 	char **paths;
   2069 	unsigned int i = 0, num = 0;
   2070 	dbus_bool_t success = FALSE;
   2071 
   2072 	wpa_s = wpa_s->global->p2p_init_wpa_s;
   2073 	if (!wpa_s)
   2074 		return no_p2p_mgmt_interface(error);
   2075 
   2076 	if (!wpa_s->parent->dbus_new_path)
   2077 		return FALSE;
   2078 
   2079 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
   2080 		if (network_is_persistent_group(ssid))
   2081 			num++;
   2082 
   2083 	paths = os_calloc(num, sizeof(char *));
   2084 	if (!paths) {
   2085 		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   2086 		return FALSE;
   2087 	}
   2088 
   2089 	/* Loop through configured networks and append object path of each */
   2090 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
   2091 		if (!network_is_persistent_group(ssid))
   2092 			continue;
   2093 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
   2094 		if (paths[i] == NULL) {
   2095 			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
   2096 					     "no memory");
   2097 			goto out;
   2098 		}
   2099 		/* Construct the object path for this network. */
   2100 		os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
   2101 			    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
   2102 			    wpa_s->parent->dbus_new_path, ssid->id);
   2103 	}
   2104 
   2105 	success = wpas_dbus_simple_array_property_getter(iter,
   2106 							 DBUS_TYPE_OBJECT_PATH,
   2107 							 paths, num, error);
   2108 
   2109 out:
   2110 	while (i)
   2111 		os_free(paths[--i]);
   2112 	os_free(paths);
   2113 	return success;
   2114 }
   2115 
   2116 
   2117 /**
   2118  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
   2119  *	group
   2120  * @iter: Pointer to incoming dbus message iter
   2121  * @error: Location to store error on failure
   2122  * @user_data: Function specific data
   2123  * Returns: TRUE on success, FALSE on failure
   2124  *
   2125  * Getter for "Properties" property of a persistent group.
   2126  */
   2127 dbus_bool_t wpas_dbus_getter_persistent_group_properties(
   2128 	const struct wpa_dbus_property_desc *property_desc,
   2129 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2130 {
   2131 	struct network_handler_args *net = user_data;
   2132 
   2133 	/* Leveraging the fact that persistent group object is still
   2134 	 * represented in same manner as network within.
   2135 	 */
   2136 	return wpas_dbus_getter_network_properties(property_desc, iter, error, net);
   2137 }
   2138 
   2139 
   2140 /**
   2141  * wpas_dbus_setter_persistent_group_properties - Set options for a persistent
   2142  *	group
   2143  * @iter: Pointer to incoming dbus message iter
   2144  * @error: Location to store error on failure
   2145  * @user_data: Function specific data
   2146  * Returns: TRUE on success, FALSE on failure
   2147  *
   2148  * Setter for "Properties" property of a persistent group.
   2149  */
   2150 dbus_bool_t wpas_dbus_setter_persistent_group_properties(
   2151 	const struct wpa_dbus_property_desc *property_desc,
   2152 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2153 {
   2154 	struct network_handler_args *net = user_data;
   2155 	struct wpa_ssid *ssid = net->ssid;
   2156 	DBusMessageIter	variant_iter;
   2157 
   2158 	/*
   2159 	 * Leveraging the fact that persistent group object is still
   2160 	 * represented in same manner as network within.
   2161 	 */
   2162 	dbus_message_iter_recurse(iter, &variant_iter);
   2163 	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
   2164 }
   2165 
   2166 
   2167 /**
   2168  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
   2169  *	persistent_group
   2170  * @message: Pointer to incoming dbus message
   2171  * @wpa_s: wpa_supplicant structure for a network interface
   2172  * Returns: A dbus message containing the object path of the new
   2173  * persistent group
   2174  *
   2175  * Handler function for "AddPersistentGroup" method call of a P2P Device
   2176  * interface.
   2177  */
   2178 DBusMessage * wpas_dbus_handler_add_persistent_group(
   2179 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   2180 {
   2181 	DBusMessage *reply = NULL;
   2182 	DBusMessageIter	iter;
   2183 	struct wpa_ssid *ssid = NULL;
   2184 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
   2185 	DBusError error;
   2186 
   2187 	dbus_message_iter_init(message, &iter);
   2188 
   2189 	wpa_s = wpa_s->global->p2p_init_wpa_s;
   2190 	if (!wpa_s) {
   2191 		reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
   2192 		goto err;
   2193 	}
   2194 
   2195 	if (wpa_s->parent->dbus_new_path)
   2196 		ssid = wpa_config_add_network(wpa_s->conf);
   2197 	if (ssid == NULL) {
   2198 		wpa_printf(MSG_ERROR,
   2199 			   "dbus: %s: Cannot add new persistent group",
   2200 			   __func__);
   2201 		reply = wpas_dbus_error_unknown_error(
   2202 			message,
   2203 			"wpa_supplicant could not add a persistent group on this interface.");
   2204 		goto err;
   2205 	}
   2206 
   2207 	/* Mark the ssid as being a persistent group before the notification */
   2208 	ssid->disabled = 2;
   2209 	ssid->p2p_persistent_group = 1;
   2210 	wpas_notify_persistent_group_added(wpa_s, ssid);
   2211 
   2212 	wpa_config_set_network_defaults(ssid);
   2213 
   2214 	dbus_error_init(&error);
   2215 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
   2216 		wpa_printf(MSG_DEBUG,
   2217 			   "dbus: %s: Control interface could not set persistent group properties",
   2218 			   __func__);
   2219 		reply = wpas_dbus_reply_new_from_error(
   2220 			message, &error, DBUS_ERROR_INVALID_ARGS,
   2221 			"Failed to set network properties");
   2222 		dbus_error_free(&error);
   2223 		goto err;
   2224 	}
   2225 
   2226 	/* Construct the object path for this network. */
   2227 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
   2228 		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
   2229 		    wpa_s->parent->dbus_new_path, ssid->id);
   2230 
   2231 	reply = dbus_message_new_method_return(message);
   2232 	if (reply == NULL) {
   2233 		reply = wpas_dbus_error_no_memory(message);
   2234 		goto err;
   2235 	}
   2236 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
   2237 				      DBUS_TYPE_INVALID)) {
   2238 		dbus_message_unref(reply);
   2239 		reply = wpas_dbus_error_no_memory(message);
   2240 		goto err;
   2241 	}
   2242 
   2243 	return reply;
   2244 
   2245 err:
   2246 	if (ssid) {
   2247 		wpas_notify_persistent_group_removed(wpa_s, ssid);
   2248 		wpa_config_remove_network(wpa_s->conf, ssid->id);
   2249 	}
   2250 	return reply;
   2251 }
   2252 
   2253 
   2254 /**
   2255  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
   2256  *	group
   2257  * @message: Pointer to incoming dbus message
   2258  * @wpa_s: wpa_supplicant structure for a network interface
   2259  * Returns: NULL on success or dbus error on failure
   2260  *
   2261  * Handler function for "RemovePersistentGroup" method call of a P2P Device
   2262  * interface.
   2263  */
   2264 DBusMessage * wpas_dbus_handler_remove_persistent_group(
   2265 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   2266 {
   2267 	DBusMessage *reply = NULL;
   2268 	const char *op;
   2269 	char *iface = NULL, *persistent_group_id;
   2270 	int id;
   2271 	struct wpa_ssid *ssid;
   2272 
   2273 	dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
   2274 			      DBUS_TYPE_INVALID);
   2275 
   2276 	wpa_s = wpa_s->global->p2p_init_wpa_s;
   2277 	if (!wpa_s) {
   2278 		reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
   2279 		goto out;
   2280 	}
   2281 
   2282 	/*
   2283 	 * Extract the network ID and ensure the network is actually a child of
   2284 	 * this interface.
   2285 	 */
   2286 	iface = wpas_dbus_new_decompose_object_path(
   2287 		op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
   2288 		&persistent_group_id);
   2289 	if (iface == NULL || persistent_group_id == NULL ||
   2290 	    !wpa_s->parent->dbus_new_path ||
   2291 	    os_strcmp(iface, wpa_s->parent->dbus_new_path) != 0) {
   2292 		reply = wpas_dbus_error_invalid_args(message, op);
   2293 		goto out;
   2294 	}
   2295 
   2296 	id = strtoul(persistent_group_id, NULL, 10);
   2297 	if (errno == EINVAL) {
   2298 		reply = wpas_dbus_error_invalid_args(message, op);
   2299 		goto out;
   2300 	}
   2301 
   2302 	ssid = wpa_config_get_network(wpa_s->conf, id);
   2303 	if (ssid == NULL) {
   2304 		reply = wpas_dbus_error_persistent_group_unknown(message);
   2305 		goto out;
   2306 	}
   2307 
   2308 	wpas_notify_persistent_group_removed(wpa_s, ssid);
   2309 
   2310 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
   2311 		wpa_printf(MSG_ERROR,
   2312 			   "dbus: %s: error occurred when removing persistent group %d",
   2313 			   __func__, id);
   2314 		reply = wpas_dbus_error_unknown_error(
   2315 			message,
   2316 			"error removing the specified persistent group on this interface.");
   2317 		goto out;
   2318 	}
   2319 
   2320 out:
   2321 	os_free(iface);
   2322 	return reply;
   2323 }
   2324 
   2325 
   2326 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
   2327 				    struct wpa_ssid *ssid)
   2328 {
   2329 	wpas_notify_persistent_group_removed(wpa_s, ssid);
   2330 
   2331 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
   2332 		wpa_printf(MSG_ERROR,
   2333 			   "dbus: %s: error occurred when removing persistent group %d",
   2334 			   __func__, ssid->id);
   2335 		return;
   2336 	}
   2337 }
   2338 
   2339 
   2340 /**
   2341  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
   2342  * persistent groups
   2343  * @message: Pointer to incoming dbus message
   2344  * @wpa_s: wpa_supplicant structure for a network interface
   2345  * Returns: NULL on success or dbus error on failure
   2346  *
   2347  * Handler function for "RemoveAllPersistentGroups" method call of a
   2348  * P2P Device interface.
   2349  */
   2350 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
   2351 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   2352 {
   2353 	struct wpa_ssid *ssid, *next;
   2354 	struct wpa_config *config;
   2355 
   2356 	wpa_s = wpa_s->global->p2p_init_wpa_s;
   2357 	if (!wpa_s)
   2358 		return wpas_dbus_error_no_p2p_mgmt_iface(message);
   2359 
   2360 	config = wpa_s->conf;
   2361 	ssid = config->ssid;
   2362 	while (ssid) {
   2363 		next = ssid->next;
   2364 		if (network_is_persistent_group(ssid))
   2365 			remove_persistent_group(wpa_s, ssid);
   2366 		ssid = next;
   2367 	}
   2368 	return NULL;
   2369 }
   2370 
   2371 
   2372 /*
   2373  * Group object properties accessor methods
   2374  */
   2375 
   2376 dbus_bool_t wpas_dbus_getter_p2p_group_members(
   2377 	const struct wpa_dbus_property_desc *property_desc,
   2378 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2379 {
   2380 	struct wpa_supplicant *wpa_s = user_data;
   2381 	struct wpa_ssid *ssid;
   2382 	unsigned int num_members;
   2383 	char **paths;
   2384 	unsigned int i;
   2385 	void *next = NULL;
   2386 	const u8 *addr;
   2387 	dbus_bool_t success = FALSE;
   2388 
   2389 	if (!wpa_s->parent->parent->dbus_new_path)
   2390 		return FALSE;
   2391 
   2392 	/* Verify correct role for this property */
   2393 	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
   2394 		return wpas_dbus_simple_array_property_getter(
   2395 			iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
   2396 	}
   2397 
   2398 	ssid = wpa_s->conf->ssid;
   2399 	/* At present WPAS P2P_GO mode only applicable for p2p_go */
   2400 	if (ssid->mode != WPAS_MODE_P2P_GO &&
   2401 	    ssid->mode != WPAS_MODE_AP &&
   2402 	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
   2403 		return FALSE;
   2404 
   2405 	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
   2406 
   2407 	paths = os_calloc(num_members, sizeof(char *));
   2408 	if (!paths)
   2409 		goto out_of_memory;
   2410 
   2411 	i = 0;
   2412 	while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
   2413 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
   2414 		if (!paths[i])
   2415 			goto out_of_memory;
   2416 		os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
   2417 			    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
   2418 			    "/" COMPACT_MACSTR,
   2419 			    wpa_s->parent->parent->dbus_new_path,
   2420 			    MAC2STR(addr));
   2421 		i++;
   2422 	}
   2423 
   2424 	success = wpas_dbus_simple_array_property_getter(iter,
   2425 							 DBUS_TYPE_OBJECT_PATH,
   2426 							 paths, num_members,
   2427 							 error);
   2428 
   2429 	for (i = 0; i < num_members; i++)
   2430 		os_free(paths[i]);
   2431 	os_free(paths);
   2432 	return success;
   2433 
   2434 out_of_memory:
   2435 	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
   2436 	if (paths) {
   2437 		for (i = 0; i < num_members; i++)
   2438 			os_free(paths[i]);
   2439 		os_free(paths);
   2440 	}
   2441 	return FALSE;
   2442 }
   2443 
   2444 
   2445 dbus_bool_t wpas_dbus_getter_p2p_group_ssid(
   2446 	const struct wpa_dbus_property_desc *property_desc,
   2447 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2448 {
   2449 	struct wpa_supplicant *wpa_s = user_data;
   2450 
   2451 	if (wpa_s->current_ssid == NULL)
   2452 		return FALSE;
   2453 	return wpas_dbus_simple_array_property_getter(
   2454 		iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
   2455 		wpa_s->current_ssid->ssid_len, error);
   2456 }
   2457 
   2458 
   2459 dbus_bool_t wpas_dbus_getter_p2p_group_bssid(
   2460 	const struct wpa_dbus_property_desc *property_desc,
   2461 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2462 {
   2463 	struct wpa_supplicant *wpa_s = user_data;
   2464 	u8 role = wpas_get_p2p_role(wpa_s);
   2465 	u8 *p_bssid;
   2466 
   2467 	if (role == WPAS_P2P_ROLE_CLIENT) {
   2468 		if (!wpa_s->current_bss)
   2469 			return FALSE;
   2470 		p_bssid = wpa_s->current_bss->bssid;
   2471 	} else {
   2472 		if (wpa_s->ap_iface == NULL)
   2473 			return FALSE;
   2474 		p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
   2475 	}
   2476 
   2477 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
   2478 						      p_bssid, ETH_ALEN,
   2479 						      error);
   2480 }
   2481 
   2482 
   2483 dbus_bool_t wpas_dbus_getter_p2p_group_frequency(
   2484 	const struct wpa_dbus_property_desc *property_desc,
   2485 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2486 {
   2487 	struct wpa_supplicant *wpa_s = user_data;
   2488 	u16 op_freq;
   2489 	u8 role = wpas_get_p2p_role(wpa_s);
   2490 
   2491 	if (role == WPAS_P2P_ROLE_CLIENT) {
   2492 		if (!wpa_s->current_bss)
   2493 			return FALSE;
   2494 		op_freq = wpa_s->current_bss->freq;
   2495 	} else {
   2496 		if (wpa_s->ap_iface == NULL)
   2497 			return FALSE;
   2498 		op_freq = wpa_s->ap_iface->freq;
   2499 	}
   2500 
   2501 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
   2502 						&op_freq, error);
   2503 }
   2504 
   2505 
   2506 dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(
   2507 	const struct wpa_dbus_property_desc *property_desc,
   2508 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2509 {
   2510 	struct wpa_supplicant *wpa_s = user_data;
   2511 	struct wpa_ssid *ssid = wpa_s->current_ssid;
   2512 
   2513 	if (ssid == NULL)
   2514 		return FALSE;
   2515 
   2516 	return wpas_dbus_string_property_getter(iter, ssid->passphrase, error);
   2517 }
   2518 
   2519 
   2520 dbus_bool_t wpas_dbus_getter_p2p_group_psk(
   2521 	const struct wpa_dbus_property_desc *property_desc,
   2522 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2523 {
   2524 	struct wpa_supplicant *wpa_s = user_data;
   2525 	u8 *p_psk = NULL;
   2526 	u8 psk_len = 0;
   2527 	struct wpa_ssid *ssid = wpa_s->current_ssid;
   2528 
   2529 	if (ssid == NULL)
   2530 		return FALSE;
   2531 
   2532 	if (ssid->psk_set) {
   2533 		p_psk = ssid->psk;
   2534 		psk_len = sizeof(ssid->psk);
   2535 	}
   2536 
   2537 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
   2538 						      p_psk, psk_len, error);
   2539 }
   2540 
   2541 
   2542 dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(
   2543 	const struct wpa_dbus_property_desc *property_desc,
   2544 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2545 {
   2546 	struct wpa_supplicant *wpa_s = user_data;
   2547 	struct hostapd_data *hapd;
   2548 	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
   2549 	unsigned int i, num_vendor_ext = 0;
   2550 
   2551 	os_memset(vendor_ext, 0, sizeof(vendor_ext));
   2552 
   2553 	/* Verify correct role for this property */
   2554 	if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
   2555 		if (wpa_s->ap_iface == NULL)
   2556 			return FALSE;
   2557 		hapd = wpa_s->ap_iface->bss[0];
   2558 
   2559 		/* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
   2560 		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
   2561 			if (hapd->conf->wps_vendor_ext[i] == NULL)
   2562 				continue;
   2563 			vendor_ext[num_vendor_ext++] =
   2564 				hapd->conf->wps_vendor_ext[i];
   2565 		}
   2566 	}
   2567 
   2568 	/* Return vendor extensions or no data */
   2569 	return wpas_dbus_simple_array_array_property_getter(iter,
   2570 							    DBUS_TYPE_BYTE,
   2571 							    vendor_ext,
   2572 							    num_vendor_ext,
   2573 							    error);
   2574 }
   2575 
   2576 
   2577 dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(
   2578 	const struct wpa_dbus_property_desc *property_desc,
   2579 	DBusMessageIter *iter, DBusError *error, void *user_data)
   2580 {
   2581 	struct wpa_supplicant *wpa_s = user_data;
   2582 	DBusMessageIter variant_iter, iter_dict, array_iter, sub;
   2583 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
   2584 	unsigned int i;
   2585 	struct hostapd_data *hapd = NULL;
   2586 
   2587 	if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO &&
   2588 	    wpa_s->ap_iface != NULL)
   2589 		hapd = wpa_s->ap_iface->bss[0];
   2590 	else
   2591 		return FALSE;
   2592 
   2593 	dbus_message_iter_recurse(iter, &variant_iter);
   2594 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
   2595 		return FALSE;
   2596 
   2597 	/*
   2598 	 * This is supposed to be array of bytearrays (aay), but the earlier
   2599 	 * implementation used a dict with "WPSVendorExtensions" as the key in
   2600 	 * this setter function which does not match the format used by the
   2601 	 * getter function. For backwards compatibility, allow both formats to
   2602 	 * be used in the setter.
   2603 	 */
   2604 	if (dbus_message_iter_get_element_type(&variant_iter) ==
   2605 	    DBUS_TYPE_ARRAY) {
   2606 		/* This is the proper format matching the getter */
   2607 		struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
   2608 
   2609 		dbus_message_iter_recurse(&variant_iter, &array_iter);
   2610 
   2611 		if (dbus_message_iter_get_arg_type(&array_iter) !=
   2612 		    DBUS_TYPE_ARRAY ||
   2613 		    dbus_message_iter_get_element_type(&array_iter) !=
   2614 		    DBUS_TYPE_BYTE) {
   2615 			wpa_printf(MSG_DEBUG,
   2616 				   "dbus: Not an array of array of bytes");
   2617 			return FALSE;
   2618 		}
   2619 
   2620 		i = 0;
   2621 		os_memset(vals, 0, sizeof(vals));
   2622 
   2623 		while (dbus_message_iter_get_arg_type(&array_iter) ==
   2624 		       DBUS_TYPE_ARRAY) {
   2625 			char *val;
   2626 			int len;
   2627 
   2628 			if (i == MAX_WPS_VENDOR_EXTENSIONS) {
   2629 				wpa_printf(MSG_DEBUG,
   2630 					   "dbus: Too many WPSVendorExtensions values");
   2631 				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
   2632 				break;
   2633 			}
   2634 
   2635 			dbus_message_iter_recurse(&array_iter, &sub);
   2636 			dbus_message_iter_get_fixed_array(&sub, &val, &len);
   2637 			wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
   2638 				    val, len);
   2639 			vals[i] = wpabuf_alloc_copy(val, len);
   2640 			if (vals[i] == NULL) {
   2641 				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
   2642 				break;
   2643 			}
   2644 			i++;
   2645 			dbus_message_iter_next(&array_iter);
   2646 		}
   2647 
   2648 		if (i > MAX_WPS_VENDOR_EXTENSIONS) {
   2649 			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
   2650 				wpabuf_free(vals[i]);
   2651 			return FALSE;
   2652 		}
   2653 
   2654 		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
   2655 			wpabuf_free(hapd->conf->wps_vendor_ext[i]);
   2656 			hapd->conf->wps_vendor_ext[i] = vals[i];
   2657 		}
   2658 
   2659 		hostapd_update_wps(hapd);
   2660 
   2661 		return TRUE;
   2662 	}
   2663 
   2664 	if (dbus_message_iter_get_element_type(&variant_iter) !=
   2665 	    DBUS_TYPE_DICT_ENTRY)
   2666 		return FALSE;
   2667 
   2668 	wpa_printf(MSG_DEBUG,
   2669 		   "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
   2670 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
   2671 		return FALSE;
   2672 
   2673 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   2674 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
   2675 			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
   2676 					     "invalid message format");
   2677 			return FALSE;
   2678 		}
   2679 
   2680 		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
   2681 			if (entry.type != DBUS_TYPE_ARRAY ||
   2682 			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
   2683 			    entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
   2684 				goto error;
   2685 
   2686 			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
   2687 				wpabuf_free(hapd->conf->wps_vendor_ext[i]);
   2688 				if (i < entry.array_len) {
   2689 					hapd->conf->wps_vendor_ext[i] =
   2690 						entry.binarray_value[i];
   2691 					entry.binarray_value[i] = NULL;
   2692 				} else
   2693 					hapd->conf->wps_vendor_ext[i] = NULL;
   2694 			}
   2695 
   2696 			hostapd_update_wps(hapd);
   2697 		} else
   2698 			goto error;
   2699 
   2700 		wpa_dbus_dict_entry_clear(&entry);
   2701 	}
   2702 
   2703 	return TRUE;
   2704 
   2705 error:
   2706 	wpa_dbus_dict_entry_clear(&entry);
   2707 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
   2708 			     "invalid message format");
   2709 	return FALSE;
   2710 }
   2711 
   2712 
   2713 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
   2714 						struct wpa_supplicant *wpa_s)
   2715 {
   2716 	DBusMessageIter iter_dict;
   2717 	DBusMessage *reply = NULL;
   2718 	DBusMessageIter iter;
   2719 	struct wpa_dbus_dict_entry entry;
   2720 	int upnp = 0;
   2721 	int bonjour = 0;
   2722 	char *service = NULL;
   2723 	struct wpabuf *query = NULL;
   2724 	struct wpabuf *resp = NULL;
   2725 	u8 version = 0;
   2726 
   2727 	dbus_message_iter_init(message, &iter);
   2728 
   2729 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
   2730 		goto error;
   2731 
   2732 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   2733 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   2734 			goto error;
   2735 
   2736 		if (os_strcmp(entry.key, "service_type") == 0 &&
   2737 		    entry.type == DBUS_TYPE_STRING) {
   2738 			if (os_strcmp(entry.str_value, "upnp") == 0)
   2739 				upnp = 1;
   2740 			else if (os_strcmp(entry.str_value, "bonjour") == 0)
   2741 				bonjour = 1;
   2742 			else
   2743 				goto error_clear;
   2744 		} else if (os_strcmp(entry.key, "version") == 0 &&
   2745 			   entry.type == DBUS_TYPE_INT32) {
   2746 			version = entry.uint32_value;
   2747 		} else if (os_strcmp(entry.key, "service") == 0 &&
   2748 			   entry.type == DBUS_TYPE_STRING) {
   2749 			os_free(service);
   2750 			service = os_strdup(entry.str_value);
   2751 		} else if (os_strcmp(entry.key, "query") == 0) {
   2752 			if (entry.type != DBUS_TYPE_ARRAY ||
   2753 			    entry.array_type != DBUS_TYPE_BYTE)
   2754 				goto error_clear;
   2755 			query = wpabuf_alloc_copy(
   2756 				entry.bytearray_value,
   2757 				entry.array_len);
   2758 		} else if (os_strcmp(entry.key, "response") == 0) {
   2759 			if (entry.type != DBUS_TYPE_ARRAY ||
   2760 			    entry.array_type != DBUS_TYPE_BYTE)
   2761 				goto error_clear;
   2762 			resp = wpabuf_alloc_copy(entry.bytearray_value,
   2763 						 entry.array_len);
   2764 		}
   2765 		wpa_dbus_dict_entry_clear(&entry);
   2766 	}
   2767 
   2768 	if (upnp == 1) {
   2769 		if (version <= 0 || service == NULL)
   2770 			goto error;
   2771 
   2772 		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
   2773 			goto error;
   2774 
   2775 	} else if (bonjour == 1) {
   2776 		if (query == NULL || resp == NULL)
   2777 			goto error;
   2778 
   2779 		if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
   2780 			goto error;
   2781 	} else
   2782 		goto error;
   2783 
   2784 out:
   2785 	os_free(service);
   2786 	wpabuf_free(query);
   2787 	wpabuf_free(resp);
   2788 
   2789 	return reply;
   2790 error_clear:
   2791 	wpa_dbus_dict_entry_clear(&entry);
   2792 error:
   2793 	reply = wpas_dbus_error_invalid_args(message, NULL);
   2794 	goto out;
   2795 }
   2796 
   2797 
   2798 DBusMessage * wpas_dbus_handler_p2p_delete_service(
   2799 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   2800 {
   2801 	DBusMessageIter iter_dict;
   2802 	DBusMessage *reply = NULL;
   2803 	DBusMessageIter iter;
   2804 	struct wpa_dbus_dict_entry entry;
   2805 	int upnp = 0;
   2806 	int bonjour = 0;
   2807 	int ret = 0;
   2808 	char *service = NULL;
   2809 	struct wpabuf *query = NULL;
   2810 	u8 version = 0;
   2811 
   2812 	dbus_message_iter_init(message, &iter);
   2813 
   2814 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
   2815 		goto error;
   2816 
   2817 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   2818 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   2819 			goto error;
   2820 
   2821 		if (os_strcmp(entry.key, "service_type") == 0 &&
   2822 		    entry.type == DBUS_TYPE_STRING) {
   2823 			if (os_strcmp(entry.str_value, "upnp") == 0)
   2824 				upnp = 1;
   2825 			else if (os_strcmp(entry.str_value, "bonjour") == 0)
   2826 				bonjour = 1;
   2827 			else
   2828 				goto error_clear;
   2829 		} else if (os_strcmp(entry.key, "version") == 0 &&
   2830 			   entry.type == DBUS_TYPE_INT32) {
   2831 			version = entry.uint32_value;
   2832 		} else if (os_strcmp(entry.key, "service") == 0 &&
   2833 			   entry.type == DBUS_TYPE_STRING) {
   2834 			os_free(service);
   2835 			service = os_strdup(entry.str_value);
   2836 		} else if (os_strcmp(entry.key, "query") == 0) {
   2837 			if (entry.type != DBUS_TYPE_ARRAY ||
   2838 			    entry.array_type != DBUS_TYPE_BYTE)
   2839 				goto error_clear;
   2840 			wpabuf_free(query);
   2841 			query = wpabuf_alloc_copy(entry.bytearray_value,
   2842 						  entry.array_len);
   2843 		} else {
   2844 			goto error_clear;
   2845 		}
   2846 
   2847 		wpa_dbus_dict_entry_clear(&entry);
   2848 	}
   2849 	if (upnp == 1) {
   2850 		if (version <= 0 || service == NULL)
   2851 			goto error;
   2852 
   2853 		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
   2854 		if (ret != 0)
   2855 			goto error;
   2856 	} else if (bonjour == 1) {
   2857 		if (query == NULL)
   2858 			goto error;
   2859 
   2860 		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
   2861 		if (ret != 0)
   2862 			goto error;
   2863 	} else
   2864 		goto error;
   2865 
   2866 	wpabuf_free(query);
   2867 	os_free(service);
   2868 	return reply;
   2869 error_clear:
   2870 	wpa_dbus_dict_entry_clear(&entry);
   2871 error:
   2872 	wpabuf_free(query);
   2873 	os_free(service);
   2874 	return wpas_dbus_error_invalid_args(message, NULL);
   2875 }
   2876 
   2877 
   2878 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
   2879 						  struct wpa_supplicant *wpa_s)
   2880 {
   2881 	wpas_p2p_service_flush(wpa_s);
   2882 	return NULL;
   2883 }
   2884 
   2885 
   2886 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
   2887 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   2888 {
   2889 	DBusMessageIter iter_dict;
   2890 	DBusMessage *reply = NULL;
   2891 	DBusMessageIter iter;
   2892 	struct wpa_dbus_dict_entry entry;
   2893 	int upnp = 0;
   2894 	char *service = NULL;
   2895 	char *peer_object_path = NULL;
   2896 	struct wpabuf *tlv = NULL;
   2897 	u8 version = 0;
   2898 	u64 ref = 0;
   2899 	u8 addr_buf[ETH_ALEN], *addr;
   2900 
   2901 	dbus_message_iter_init(message, &iter);
   2902 
   2903 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
   2904 		goto error;
   2905 
   2906 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   2907 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   2908 			goto error;
   2909 		if (os_strcmp(entry.key, "peer_object") == 0 &&
   2910 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
   2911 			peer_object_path = os_strdup(entry.str_value);
   2912 		} else if (os_strcmp(entry.key, "service_type") == 0 &&
   2913 			   entry.type == DBUS_TYPE_STRING) {
   2914 			if (os_strcmp(entry.str_value, "upnp") == 0)
   2915 				upnp = 1;
   2916 			else
   2917 				goto error_clear;
   2918 		} else if (os_strcmp(entry.key, "version") == 0 &&
   2919 			   entry.type == DBUS_TYPE_INT32) {
   2920 			version = entry.uint32_value;
   2921 		} else if (os_strcmp(entry.key, "service") == 0 &&
   2922 			   entry.type == DBUS_TYPE_STRING) {
   2923 			service = os_strdup(entry.str_value);
   2924 		} else if (os_strcmp(entry.key, "tlv") == 0) {
   2925 			if (entry.type != DBUS_TYPE_ARRAY ||
   2926 			    entry.array_type != DBUS_TYPE_BYTE)
   2927 				goto error_clear;
   2928 			wpabuf_free(tlv);
   2929 			tlv = wpabuf_alloc_copy(entry.bytearray_value,
   2930 						entry.array_len);
   2931 		} else
   2932 			goto error_clear;
   2933 
   2934 		wpa_dbus_dict_entry_clear(&entry);
   2935 	}
   2936 
   2937 	if (!peer_object_path) {
   2938 		addr = NULL;
   2939 	} else {
   2940 		if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
   2941 		    !p2p_peer_known(wpa_s->global->p2p, addr_buf))
   2942 			goto error;
   2943 
   2944 		addr = addr_buf;
   2945 	}
   2946 
   2947 	if (upnp == 1) {
   2948 		if (version <= 0 || service == NULL)
   2949 			goto error;
   2950 
   2951 		ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
   2952 	} else {
   2953 		if (tlv == NULL)
   2954 			goto error;
   2955 		ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
   2956 	}
   2957 
   2958 	if (ref != 0) {
   2959 		reply = dbus_message_new_method_return(message);
   2960 		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
   2961 					 &ref, DBUS_TYPE_INVALID);
   2962 	} else {
   2963 		reply = wpas_dbus_error_unknown_error(
   2964 			message, "Unable to send SD request");
   2965 	}
   2966 out:
   2967 	wpabuf_free(tlv);
   2968 	os_free(service);
   2969 	os_free(peer_object_path);
   2970 	return reply;
   2971 error_clear:
   2972 	wpa_dbus_dict_entry_clear(&entry);
   2973 error:
   2974 	reply = wpas_dbus_error_invalid_args(message, NULL);
   2975 	goto out;
   2976 }
   2977 
   2978 
   2979 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
   2980 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   2981 {
   2982 	DBusMessageIter iter_dict;
   2983 	DBusMessage *reply = NULL;
   2984 	DBusMessageIter iter;
   2985 	struct wpa_dbus_dict_entry entry;
   2986 	char *peer_object_path = NULL;
   2987 	struct wpabuf *tlv = NULL;
   2988 	int freq = 0;
   2989 	int dlg_tok = 0;
   2990 	u8 addr[ETH_ALEN];
   2991 
   2992 	dbus_message_iter_init(message, &iter);
   2993 
   2994 	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
   2995 		goto error;
   2996 
   2997 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
   2998 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
   2999 			goto error;
   3000 
   3001 		if (os_strcmp(entry.key, "peer_object") == 0 &&
   3002 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
   3003 			peer_object_path = os_strdup(entry.str_value);
   3004 		} else if (os_strcmp(entry.key, "frequency") == 0 &&
   3005 			   entry.type == DBUS_TYPE_INT32) {
   3006 			freq = entry.uint32_value;
   3007 		} else if (os_strcmp(entry.key, "dialog_token") == 0 &&
   3008 			   (entry.type == DBUS_TYPE_UINT32 ||
   3009 			    entry.type == DBUS_TYPE_INT32)) {
   3010 			dlg_tok = entry.uint32_value;
   3011 		} else if (os_strcmp(entry.key, "tlvs") == 0) {
   3012 			if (entry.type != DBUS_TYPE_ARRAY ||
   3013 			    entry.array_type != DBUS_TYPE_BYTE)
   3014 				goto error_clear;
   3015 			wpabuf_free(tlv);
   3016 			tlv = wpabuf_alloc_copy(entry.bytearray_value,
   3017 						entry.array_len);
   3018 		} else
   3019 			goto error_clear;
   3020 
   3021 		wpa_dbus_dict_entry_clear(&entry);
   3022 	}
   3023 	if (parse_peer_object_path(peer_object_path, addr) < 0 ||
   3024 	    !p2p_peer_known(wpa_s->global->p2p, addr) ||
   3025 	    tlv == NULL)
   3026 		goto error;
   3027 
   3028 	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
   3029 out:
   3030 	wpabuf_free(tlv);
   3031 	os_free(peer_object_path);
   3032 	return reply;
   3033 error_clear:
   3034 	wpa_dbus_dict_entry_clear(&entry);
   3035 error:
   3036 	reply = wpas_dbus_error_invalid_args(message, NULL);
   3037 	goto out;
   3038 }
   3039 
   3040 
   3041 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
   3042 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   3043 {
   3044 	DBusMessageIter iter;
   3045 	u64 req = 0;
   3046 
   3047 	dbus_message_iter_init(message, &iter);
   3048 	dbus_message_iter_get_basic(&iter, &req);
   3049 
   3050 	if (req == 0)
   3051 		goto error;
   3052 
   3053 	if (wpas_p2p_sd_cancel_request(wpa_s, req) < 0)
   3054 		goto error;
   3055 
   3056 	return NULL;
   3057 error:
   3058 	return wpas_dbus_error_invalid_args(message, NULL);
   3059 }
   3060 
   3061 
   3062 DBusMessage * wpas_dbus_handler_p2p_service_update(
   3063 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   3064 {
   3065 	wpas_p2p_sd_service_update(wpa_s);
   3066 	return NULL;
   3067 }
   3068 
   3069 
   3070 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
   3071 	DBusMessage *message, struct wpa_supplicant *wpa_s)
   3072 {
   3073 	DBusMessageIter iter;
   3074 	int ext = 0;
   3075 
   3076 	dbus_message_iter_init(message, &iter);
   3077 	dbus_message_iter_get_basic(&iter, &ext);
   3078 
   3079 	wpa_s->p2p_sd_over_ctrl_iface = ext;
   3080 
   3081 	return NULL;
   3082 
   3083 }
   3084 
   3085 
   3086 #ifdef CONFIG_WIFI_DISPLAY
   3087 
   3088 dbus_bool_t wpas_dbus_getter_global_wfd_ies(
   3089 	const struct wpa_dbus_property_desc *property_desc,
   3090 	DBusMessageIter *iter, DBusError *error, void *user_data)
   3091 {
   3092 	struct wpa_global *global = user_data;
   3093 	struct wpabuf *ie;
   3094 	dbus_bool_t ret;
   3095 
   3096 	ie = wifi_display_get_wfd_ie(global);
   3097 	if (ie == NULL)
   3098 		return wpas_dbus_simple_array_property_getter(iter,
   3099 							      DBUS_TYPE_BYTE,
   3100 							      NULL, 0, error);
   3101 
   3102 	ret = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
   3103 						     wpabuf_head(ie),
   3104 						     wpabuf_len(ie), error);
   3105 	wpabuf_free(ie);
   3106 
   3107 	return ret;
   3108 }
   3109 
   3110 
   3111 dbus_bool_t wpas_dbus_setter_global_wfd_ies(
   3112 	const struct wpa_dbus_property_desc *property_desc,
   3113 	DBusMessageIter *iter, DBusError *error, void *user_data)
   3114 {
   3115 	struct wpa_global *global = user_data;
   3116 	DBusMessageIter variant, array;
   3117 	struct wpabuf *ie = NULL;
   3118 	const u8 *data;
   3119 	int len;
   3120 
   3121 	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
   3122 		goto err;
   3123 
   3124 	dbus_message_iter_recurse(iter, &variant);
   3125 	if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
   3126 		goto err;
   3127 
   3128 	dbus_message_iter_recurse(&variant, &array);
   3129 	dbus_message_iter_get_fixed_array(&array, &data, &len);
   3130 	if (len == 0) {
   3131 		wifi_display_enable(global, 0);
   3132 		wifi_display_deinit(global);
   3133 
   3134 		return TRUE;
   3135 	}
   3136 
   3137 	ie = wpabuf_alloc(len);
   3138 	if (ie == NULL)
   3139 		goto err;
   3140 
   3141 	wpabuf_put_data(ie, data, len);
   3142 	if (wifi_display_subelem_set_from_ies(global, ie) != 0)
   3143 		goto err;
   3144 
   3145 	if (global->wifi_display == 0)
   3146 		wifi_display_enable(global, 1);
   3147 
   3148 	wpabuf_free(ie);
   3149 
   3150 	return TRUE;
   3151 err:
   3152 	wpabuf_free(ie);
   3153 
   3154 	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
   3155 			     "invalid message format");
   3156 	return FALSE;
   3157 }
   3158 
   3159 #endif /* CONFIG_WIFI_DISPLAY */
   3160