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