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