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