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