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