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