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