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