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