Updated to hostap_2_6
[mech_eap.git] / libeap / 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, NULL, 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                             os_strlen(entry.str_value) > WPS_DEV_NAME_MAX_LEN)
950                                 goto error;
951
952                         devname = os_strdup(entry.str_value);
953                         if (devname == NULL)
954                                 goto err_no_mem_clear;
955
956                         os_free(wpa_s->conf->device_name);
957                         wpa_s->conf->device_name = devname;
958
959                         wpa_s->conf->changed_parameters |=
960                                 CFG_CHANGED_DEVICE_NAME;
961                 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
962                         if (entry.type != DBUS_TYPE_ARRAY ||
963                             entry.array_type != DBUS_TYPE_BYTE ||
964                             entry.array_len != WPS_DEV_TYPE_LEN)
965                                 goto error;
966
967                         os_memcpy(wpa_s->conf->device_type,
968                                   entry.bytearray_value,
969                                   WPS_DEV_TYPE_LEN);
970                         wpa_s->conf->changed_parameters |=
971                                 CFG_CHANGED_DEVICE_TYPE;
972                 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
973                         if (entry.type != DBUS_TYPE_ARRAY ||
974                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
975                             entry.array_len > MAX_SEC_DEVICE_TYPES)
976                                 goto error;
977
978                         for (i = 0; i < entry.array_len; i++)
979                                 if (wpabuf_len(entry.binarray_value[i]) !=
980                                     WPS_DEV_TYPE_LEN)
981                                         goto err_no_mem_clear;
982                         for (i = 0; i < entry.array_len; i++)
983                                 os_memcpy(wpa_s->conf->sec_device_type[i],
984                                           wpabuf_head(entry.binarray_value[i]),
985                                           WPS_DEV_TYPE_LEN);
986                         wpa_s->conf->num_sec_device_types = entry.array_len;
987                         wpa_s->conf->changed_parameters |=
988                                         CFG_CHANGED_SEC_DEVICE_TYPE;
989                 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
990                         if (entry.type != DBUS_TYPE_ARRAY ||
991                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
992                             (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
993                                 goto error;
994
995                         wpa_s->conf->changed_parameters |=
996                                 CFG_CHANGED_VENDOR_EXTENSION;
997
998                         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
999                                 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
1000                                 if (i < entry.array_len) {
1001                                         wpa_s->conf->wps_vendor_ext[i] =
1002                                                 entry.binarray_value[i];
1003                                         entry.binarray_value[i] = NULL;
1004                                 } else
1005                                         wpa_s->conf->wps_vendor_ext[i] = NULL;
1006                         }
1007                 } else if (os_strcmp(entry.key, "GOIntent") == 0 &&
1008                            entry.type == DBUS_TYPE_UINT32 &&
1009                            (entry.uint32_value <= 15))
1010                         wpa_s->conf->p2p_go_intent = entry.uint32_value;
1011                 else if (os_strcmp(entry.key, "PersistentReconnect") == 0 &&
1012                          entry.type == DBUS_TYPE_BOOLEAN)
1013                         wpa_s->conf->persistent_reconnect = entry.bool_value;
1014                 else if (os_strcmp(entry.key, "ListenRegClass") == 0 &&
1015                          entry.type == DBUS_TYPE_UINT32) {
1016                         wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
1017                         wpa_s->conf->changed_parameters |=
1018                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
1019                 } else if (os_strcmp(entry.key, "ListenChannel") == 0 &&
1020                            entry.type == DBUS_TYPE_UINT32) {
1021                         wpa_s->conf->p2p_listen_channel = entry.uint32_value;
1022                         wpa_s->conf->changed_parameters |=
1023                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
1024                 } else if (os_strcmp(entry.key, "OperRegClass") == 0 &&
1025                            entry.type == DBUS_TYPE_UINT32) {
1026                         wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
1027                         wpa_s->conf->changed_parameters |=
1028                                 CFG_CHANGED_P2P_OPER_CHANNEL;
1029                 } else if (os_strcmp(entry.key, "OperChannel") == 0 &&
1030                            entry.type == DBUS_TYPE_UINT32) {
1031                         wpa_s->conf->p2p_oper_channel = entry.uint32_value;
1032                         wpa_s->conf->changed_parameters |=
1033                                 CFG_CHANGED_P2P_OPER_CHANNEL;
1034                 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
1035                         char *postfix;
1036
1037                         if (entry.type != DBUS_TYPE_STRING)
1038                                 goto error;
1039
1040                         postfix = os_strdup(entry.str_value);
1041                         if (!postfix)
1042                                 goto err_no_mem_clear;
1043
1044                         os_free(wpa_s->conf->p2p_ssid_postfix);
1045                         wpa_s->conf->p2p_ssid_postfix = postfix;
1046
1047                         wpa_s->conf->changed_parameters |=
1048                                         CFG_CHANGED_P2P_SSID_POSTFIX;
1049                 } else if (os_strcmp(entry.key, "IntraBss") == 0 &&
1050                            entry.type == DBUS_TYPE_BOOLEAN) {
1051                         wpa_s->conf->p2p_intra_bss = entry.bool_value;
1052                         wpa_s->conf->changed_parameters |=
1053                                 CFG_CHANGED_P2P_INTRA_BSS;
1054                 } else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
1055                            entry.type == DBUS_TYPE_UINT32)
1056                         wpa_s->conf->p2p_group_idle = entry.uint32_value;
1057                 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
1058                          entry.type == DBUS_TYPE_UINT32)
1059                         wpa_s->conf->disassoc_low_ack = entry.uint32_value;
1060                 else if (os_strcmp(entry.key, "NoGroupIface") == 0 &&
1061                          entry.type == DBUS_TYPE_BOOLEAN)
1062                         wpa_s->conf->p2p_no_group_iface = entry.bool_value;
1063                 else if (os_strcmp(entry.key, "p2p_search_delay") == 0 &&
1064                          entry.type == DBUS_TYPE_UINT32)
1065                         wpa_s->conf->p2p_search_delay = entry.uint32_value;
1066                 else
1067                         goto error;
1068
1069                 wpa_dbus_dict_entry_clear(&entry);
1070         }
1071
1072         if (wpa_s->conf->changed_parameters) {
1073                 /* Some changed parameters requires to update config*/
1074                 wpa_supplicant_update_config(wpa_s);
1075         }
1076
1077         return TRUE;
1078
1079  error:
1080         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1081                              "invalid message format");
1082         wpa_dbus_dict_entry_clear(&entry);
1083         return FALSE;
1084
1085  err_no_mem_clear:
1086         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1087         wpa_dbus_dict_entry_clear(&entry);
1088         return FALSE;
1089 }
1090
1091
1092 dbus_bool_t wpas_dbus_getter_p2p_peers(
1093         const struct wpa_dbus_property_desc *property_desc,
1094         DBusMessageIter *iter, DBusError *error, void *user_data)
1095 {
1096         struct wpa_supplicant *wpa_s = user_data;
1097         struct p2p_data *p2p = wpa_s->global->p2p;
1098         int next = 0, i = 0;
1099         int num = 0, out_of_mem = 0;
1100         const u8 *addr;
1101         const struct p2p_peer_info *peer_info = NULL;
1102         dbus_bool_t success = FALSE;
1103
1104         struct dl_list peer_objpath_list;
1105         struct peer_objpath_node {
1106                 struct dl_list list;
1107                 char path[WPAS_DBUS_OBJECT_PATH_MAX];
1108         } *node, *tmp;
1109
1110         char **peer_obj_paths = NULL;
1111
1112         if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error) ||
1113             !wpa_s->parent->parent->dbus_new_path)
1114                 return FALSE;
1115
1116         dl_list_init(&peer_objpath_list);
1117
1118         /* Get the first peer info */
1119         peer_info = p2p_get_peer_found(p2p, NULL, next);
1120
1121         /* Get next and accumulate them */
1122         next = 1;
1123         while (peer_info != NULL) {
1124                 node = os_zalloc(sizeof(struct peer_objpath_node));
1125                 if (!node) {
1126                         out_of_mem = 1;
1127                         goto error;
1128                 }
1129
1130                 addr = peer_info->p2p_device_addr;
1131                 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
1132                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1133                             "/" COMPACT_MACSTR,
1134                             wpa_s->parent->parent->dbus_new_path,
1135                             MAC2STR(addr));
1136                 dl_list_add_tail(&peer_objpath_list, &node->list);
1137                 num++;
1138
1139                 peer_info = p2p_get_peer_found(p2p, addr, next);
1140         }
1141
1142         /*
1143          * Now construct the peer object paths in a form suitable for
1144          * array_property_getter helper below.
1145          */
1146         peer_obj_paths = os_calloc(num, sizeof(char *));
1147
1148         if (!peer_obj_paths) {
1149                 out_of_mem = 1;
1150                 goto error;
1151         }
1152
1153         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1154                               struct peer_objpath_node, list)
1155                 peer_obj_paths[i++] = node->path;
1156
1157         success = wpas_dbus_simple_array_property_getter(iter,
1158                                                          DBUS_TYPE_OBJECT_PATH,
1159                                                          peer_obj_paths, num,
1160                                                          error);
1161
1162 error:
1163         if (peer_obj_paths)
1164                 os_free(peer_obj_paths);
1165
1166         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1167                               struct peer_objpath_node, list) {
1168                 dl_list_del(&node->list);
1169                 os_free(node);
1170         }
1171         if (out_of_mem)
1172                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1173
1174         return success;
1175 }
1176
1177
1178 enum wpas_p2p_role {
1179         WPAS_P2P_ROLE_DEVICE,
1180         WPAS_P2P_ROLE_GO,
1181         WPAS_P2P_ROLE_CLIENT,
1182 };
1183
1184 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1185 {
1186         struct wpa_ssid *ssid = wpa_s->current_ssid;
1187
1188         if (!ssid)
1189                 return WPAS_P2P_ROLE_DEVICE;
1190         if (wpa_s->wpa_state != WPA_COMPLETED)
1191                 return WPAS_P2P_ROLE_DEVICE;
1192
1193         switch (ssid->mode) {
1194         case WPAS_MODE_P2P_GO:
1195         case WPAS_MODE_P2P_GROUP_FORMATION:
1196                 return WPAS_P2P_ROLE_GO;
1197         case WPAS_MODE_INFRA:
1198                 if (ssid->p2p_group)
1199                         return WPAS_P2P_ROLE_CLIENT;
1200                 return WPAS_P2P_ROLE_DEVICE;
1201         default:
1202                 return WPAS_P2P_ROLE_DEVICE;
1203         }
1204 }
1205
1206
1207 dbus_bool_t wpas_dbus_getter_p2p_role(
1208         const struct wpa_dbus_property_desc *property_desc,
1209         DBusMessageIter *iter, DBusError *error, void *user_data)
1210 {
1211         struct wpa_supplicant *wpa_s = user_data;
1212         char *str;
1213
1214         switch (wpas_get_p2p_role(wpa_s)) {
1215         case WPAS_P2P_ROLE_GO:
1216                 str = "GO";
1217                 break;
1218         case WPAS_P2P_ROLE_CLIENT:
1219                 str = "client";
1220                 break;
1221         default:
1222                 str = "device";
1223                 break;
1224         }
1225
1226         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
1227                                                 error);
1228 }
1229
1230
1231 dbus_bool_t wpas_dbus_getter_p2p_group(
1232         const struct wpa_dbus_property_desc *property_desc,
1233         DBusMessageIter *iter, DBusError *error, void *user_data)
1234 {
1235         struct wpa_supplicant *wpa_s = user_data;
1236         char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
1237         char *dbus_groupobj_path = path_buf;
1238
1239         if (wpa_s->dbus_groupobj_path == NULL)
1240                 os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1241                             "/");
1242         else
1243                 os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1244                             "%s", wpa_s->dbus_groupobj_path);
1245
1246         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1247                                                 &dbus_groupobj_path, error);
1248 }
1249
1250
1251 dbus_bool_t wpas_dbus_getter_p2p_peergo(
1252         const struct wpa_dbus_property_desc *property_desc,
1253         DBusMessageIter *iter, DBusError *error, void *user_data)
1254 {
1255         struct wpa_supplicant *wpa_s = user_data;
1256         char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1257
1258         if (!wpa_s->parent->parent->dbus_new_path)
1259                 return FALSE;
1260
1261         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1262                 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
1263         else
1264                 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1265                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1266                             COMPACT_MACSTR,
1267                             wpa_s->parent->parent->dbus_new_path,
1268                             MAC2STR(wpa_s->go_dev_addr));
1269
1270         path = go_peer_obj_path;
1271         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1272                                                 &path, error);
1273 }
1274
1275
1276 /*
1277  * Peer object properties accessor methods
1278  */
1279
1280 dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(
1281         const struct wpa_dbus_property_desc *property_desc,
1282         DBusMessageIter *iter, DBusError *error, void *user_data)
1283 {
1284         struct peer_handler_args *peer_args = user_data;
1285         const struct p2p_peer_info *info;
1286         char *tmp;
1287
1288         if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1289                 return FALSE;
1290
1291         /* get the peer info */
1292         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1293                                   peer_args->p2p_device_addr, 0);
1294         if (info == NULL) {
1295                 dbus_set_error(error, DBUS_ERROR_FAILED,
1296                                "failed to find peer");
1297                 return FALSE;
1298         }
1299
1300         tmp = os_strdup(info->device_name);
1301         if (!tmp) {
1302                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1303                 return FALSE;
1304         }
1305
1306         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1307                                               error)) {
1308                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1309                 os_free(tmp);
1310                 return FALSE;
1311         }
1312
1313         os_free(tmp);
1314         return TRUE;
1315 }
1316
1317
1318 dbus_bool_t wpas_dbus_getter_p2p_peer_manufacturer(
1319         const struct wpa_dbus_property_desc *property_desc,
1320         DBusMessageIter *iter, DBusError *error, void *user_data)
1321 {
1322         struct peer_handler_args *peer_args = user_data;
1323         const struct p2p_peer_info *info;
1324         char *tmp;
1325
1326         if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1327                 return FALSE;
1328
1329         /* get the peer info */
1330         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1331                                   peer_args->p2p_device_addr, 0);
1332         if (info == NULL) {
1333                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1334                 return FALSE;
1335         }
1336
1337         tmp = os_strdup(info->manufacturer);
1338         if (!tmp) {
1339                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1340                 return FALSE;
1341         }
1342
1343         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1344                                               error)) {
1345                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1346                 os_free(tmp);
1347                 return FALSE;
1348         }
1349
1350         os_free(tmp);
1351         return TRUE;
1352 }
1353
1354
1355 dbus_bool_t wpas_dbus_getter_p2p_peer_modelname(
1356         const struct wpa_dbus_property_desc *property_desc,
1357         DBusMessageIter *iter, DBusError *error, void *user_data)
1358 {
1359         struct peer_handler_args *peer_args = user_data;
1360         const struct p2p_peer_info *info;
1361         char *tmp;
1362
1363         if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1364                 return FALSE;
1365
1366         /* get the peer info */
1367         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1368                                   peer_args->p2p_device_addr, 0);
1369         if (info == NULL) {
1370                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1371                 return FALSE;
1372         }
1373
1374         tmp = os_strdup(info->model_name);
1375         if (!tmp) {
1376                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1377                 return FALSE;
1378         }
1379
1380         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1381                                               error)) {
1382                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1383                 os_free(tmp);
1384                 return FALSE;
1385         }
1386
1387         os_free(tmp);
1388         return TRUE;
1389 }
1390
1391
1392 dbus_bool_t wpas_dbus_getter_p2p_peer_modelnumber(
1393         const struct wpa_dbus_property_desc *property_desc,
1394         DBusMessageIter *iter, DBusError *error, void *user_data)
1395 {
1396         struct peer_handler_args *peer_args = user_data;
1397         const struct p2p_peer_info *info;
1398         char *tmp;
1399
1400         if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1401                 return FALSE;
1402
1403         /* get the peer info */
1404         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1405                                   peer_args->p2p_device_addr, 0);
1406         if (info == NULL) {
1407                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1408                 return FALSE;
1409         }
1410
1411         tmp = os_strdup(info->model_number);
1412         if (!tmp) {
1413                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1414                 return FALSE;
1415         }
1416
1417         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1418                                               error)) {
1419                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1420                 os_free(tmp);
1421                 return FALSE;
1422         }
1423
1424         os_free(tmp);
1425         return TRUE;
1426 }
1427
1428
1429 dbus_bool_t wpas_dbus_getter_p2p_peer_serialnumber(
1430         const struct wpa_dbus_property_desc *property_desc,
1431         DBusMessageIter *iter, DBusError *error, void *user_data)
1432 {
1433         struct peer_handler_args *peer_args = user_data;
1434         const struct p2p_peer_info *info;
1435         char *tmp;
1436
1437         if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1438                 return FALSE;
1439
1440         /* get the peer info */
1441         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1442                                   peer_args->p2p_device_addr, 0);
1443         if (info == NULL) {
1444                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1445                 return FALSE;
1446         }
1447
1448         tmp = os_strdup(info->serial_number);
1449         if (!tmp) {
1450                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1451                 return FALSE;
1452         }
1453
1454         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1455                                               error)) {
1456                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1457                 os_free(tmp);
1458                 return FALSE;
1459         }
1460
1461         os_free(tmp);
1462         return TRUE;
1463 }
1464
1465
1466 dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
1467         const struct wpa_dbus_property_desc *property_desc,
1468         DBusMessageIter *iter, DBusError *error, void *user_data)
1469 {
1470         struct peer_handler_args *peer_args = user_data;
1471         const struct p2p_peer_info *info;
1472
1473         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1474                                   peer_args->p2p_device_addr, 0);
1475         if (info == NULL) {
1476                 dbus_set_error(error, DBUS_ERROR_FAILED,
1477                                "failed to find peer");
1478                 return FALSE;
1479         }
1480
1481         if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
1482                                                     (char *)
1483                                                     info->pri_dev_type,
1484                                                     WPS_DEV_TYPE_LEN, error)) {
1485                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1486                 return FALSE;
1487         }
1488
1489         return TRUE;
1490 }
1491
1492
1493 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(
1494         const struct wpa_dbus_property_desc *property_desc,
1495         DBusMessageIter *iter, DBusError *error, void *user_data)
1496 {
1497         struct peer_handler_args *peer_args = user_data;
1498         const struct p2p_peer_info *info;
1499
1500         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1501                                   peer_args->p2p_device_addr, 0);
1502         if (info == NULL) {
1503                 dbus_set_error(error, DBUS_ERROR_FAILED,
1504                                "failed to find peer");
1505                 return FALSE;
1506         }
1507
1508         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
1509                                               &info->config_methods, error)) {
1510                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1511                 return FALSE;
1512         }
1513
1514         return TRUE;
1515 }
1516
1517
1518 dbus_bool_t wpas_dbus_getter_p2p_peer_level(
1519         const struct wpa_dbus_property_desc *property_desc,
1520         DBusMessageIter *iter, DBusError *error, void *user_data)
1521 {
1522         struct peer_handler_args *peer_args = user_data;
1523         const struct p2p_peer_info *info;
1524
1525         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1526                                   peer_args->p2p_device_addr, 0);
1527         if (info == NULL) {
1528                 dbus_set_error(error, DBUS_ERROR_FAILED,
1529                                "failed to find peer");
1530                 return FALSE;
1531         }
1532
1533         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
1534                                               &info->level, error)) {
1535                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1536                 return FALSE;
1537         }
1538
1539         return TRUE;
1540 }
1541
1542
1543 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(
1544         const struct wpa_dbus_property_desc *property_desc,
1545         DBusMessageIter *iter, DBusError *error, void *user_data)
1546 {
1547         struct peer_handler_args *peer_args = user_data;
1548         const struct p2p_peer_info *info;
1549
1550         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1551                                   peer_args->p2p_device_addr, 0);
1552         if (info == NULL) {
1553                 dbus_set_error(error, DBUS_ERROR_FAILED,
1554                                "failed to find peer");
1555                 return FALSE;
1556         }
1557
1558         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
1559                                               &info->dev_capab, error)) {
1560                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1561                 return FALSE;
1562         }
1563
1564         return TRUE;
1565 }
1566
1567
1568 dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(
1569         const struct wpa_dbus_property_desc *property_desc,
1570         DBusMessageIter *iter, DBusError *error, void *user_data)
1571 {
1572         struct peer_handler_args *peer_args = user_data;
1573         const struct p2p_peer_info *info;
1574
1575         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1576                                   peer_args->p2p_device_addr, 0);
1577         if (info == NULL) {
1578                 dbus_set_error(error, DBUS_ERROR_FAILED,
1579                                "failed to find peer");
1580                 return FALSE;
1581         }
1582
1583         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
1584                                               &info->group_capab, error)) {
1585                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1586                 return FALSE;
1587         }
1588
1589         return TRUE;
1590 }
1591
1592
1593 dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
1594         const struct wpa_dbus_property_desc *property_desc,
1595         DBusMessageIter *iter, DBusError *error, void *user_data)
1596 {
1597         struct peer_handler_args *peer_args = user_data;
1598         const struct p2p_peer_info *info;
1599         DBusMessageIter variant_iter, array_iter;
1600
1601         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1602                                   peer_args->p2p_device_addr, 0);
1603         if (info == NULL) {
1604                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1605                 return FALSE;
1606         }
1607
1608         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1609                                               DBUS_TYPE_ARRAY_AS_STRING
1610                                               DBUS_TYPE_ARRAY_AS_STRING
1611                                               DBUS_TYPE_BYTE_AS_STRING,
1612                                               &variant_iter) ||
1613             !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
1614                                               DBUS_TYPE_ARRAY_AS_STRING
1615                                               DBUS_TYPE_BYTE_AS_STRING,
1616                                               &array_iter)) {
1617                 dbus_set_error(error, DBUS_ERROR_FAILED,
1618                                "%s: failed to construct message 1", __func__);
1619                 return FALSE;
1620         }
1621
1622         if (info->wps_sec_dev_type_list_len) {
1623                 const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
1624                 int num_sec_device_types =
1625                         info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
1626                 int i;
1627                 DBusMessageIter inner_array_iter;
1628
1629                 for (i = 0; i < num_sec_device_types; i++) {
1630                         if (!dbus_message_iter_open_container(
1631                                     &array_iter, DBUS_TYPE_ARRAY,
1632                                     DBUS_TYPE_BYTE_AS_STRING,
1633                                     &inner_array_iter) ||
1634                             !dbus_message_iter_append_fixed_array(
1635                                     &inner_array_iter, DBUS_TYPE_BYTE,
1636                                     &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
1637                             !dbus_message_iter_close_container(
1638                                     &array_iter, &inner_array_iter)) {
1639                                 dbus_set_error(error, DBUS_ERROR_FAILED,
1640                                                "%s: failed to construct message 2 (%d)",
1641                                                __func__, i);
1642                                 return FALSE;
1643                         }
1644
1645                         sec_dev_type_list += WPS_DEV_TYPE_LEN;
1646                 }
1647         }
1648
1649         if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
1650             !dbus_message_iter_close_container(iter, &variant_iter)) {
1651                 dbus_set_error(error, DBUS_ERROR_FAILED,
1652                                "%s: failed to construct message 3", __func__);
1653                 return FALSE;
1654         }
1655
1656         return TRUE;
1657 }
1658
1659
1660 dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(
1661         const struct wpa_dbus_property_desc *property_desc,
1662         DBusMessageIter *iter, DBusError *error, void *user_data)
1663 {
1664         struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1665         unsigned int i, num = 0;
1666         struct peer_handler_args *peer_args = user_data;
1667         const struct p2p_peer_info *info;
1668
1669         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1670                                   peer_args->p2p_device_addr, 0);
1671         if (info == NULL) {
1672                 dbus_set_error(error, DBUS_ERROR_FAILED,
1673                                "failed to find peer");
1674                 return FALSE;
1675         }
1676
1677         /* Add WPS vendor extensions attribute */
1678         os_memset(vendor_extension, 0, sizeof(vendor_extension));
1679         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1680                 if (info->wps_vendor_ext[i] == NULL)
1681                         continue;
1682                 vendor_extension[num] = info->wps_vendor_ext[i];
1683                 num++;
1684         }
1685
1686         if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
1687                                                           vendor_extension,
1688                                                           num, error))
1689                 return FALSE;
1690
1691         return TRUE;
1692 }
1693
1694
1695 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(
1696         const struct wpa_dbus_property_desc *property_desc,
1697         DBusMessageIter *iter, DBusError *error, void *user_data)
1698 {
1699         struct peer_handler_args *peer_args = user_data;
1700         const struct p2p_peer_info *info;
1701
1702         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1703                                   peer_args->p2p_device_addr, 0);
1704         if (info == NULL) {
1705                 dbus_set_error(error, DBUS_ERROR_FAILED,
1706                                "failed to find peer");
1707                 return FALSE;
1708         }
1709
1710         if (info->wfd_subelems == NULL)
1711                 return wpas_dbus_simple_array_property_getter(iter,
1712                                                               DBUS_TYPE_BYTE,
1713                                                               NULL, 0, error);
1714
1715         return wpas_dbus_simple_array_property_getter(
1716                 iter, DBUS_TYPE_BYTE, (char *) info->wfd_subelems->buf,
1717                 info->wfd_subelems->used, error);
1718 }
1719
1720
1721 dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(
1722         const struct wpa_dbus_property_desc *property_desc,
1723         DBusMessageIter *iter, DBusError *error, void *user_data)
1724 {
1725         struct peer_handler_args *peer_args = user_data;
1726         const struct p2p_peer_info *info;
1727
1728         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1729                                   peer_args->p2p_device_addr, 0);
1730         if (info == NULL) {
1731                 dbus_set_error(error, DBUS_ERROR_FAILED,
1732                                "failed to find peer");
1733                 return FALSE;
1734         }
1735
1736         return wpas_dbus_simple_array_property_getter(
1737                 iter, DBUS_TYPE_BYTE, (char *) info->p2p_device_addr,
1738                 ETH_ALEN, error);
1739 }
1740
1741
1742 struct peer_group_data {
1743         struct wpa_supplicant *wpa_s;
1744         const struct p2p_peer_info *info;
1745         char **paths;
1746         unsigned int nb_paths;
1747         int error;
1748 };
1749
1750
1751 static int match_group_where_peer_is_client(struct p2p_group *group,
1752                                             void *user_data)
1753 {
1754         struct peer_group_data *data = user_data;
1755         const struct p2p_group_config *cfg;
1756         struct wpa_supplicant *wpa_s_go;
1757         char **paths;
1758
1759         if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
1760                 return 1;
1761
1762         cfg = p2p_group_get_config(group);
1763
1764         wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
1765                                          cfg->ssid_len);
1766         if (wpa_s_go == NULL)
1767                 return 1;
1768
1769         paths = os_realloc_array(data->paths, data->nb_paths + 1,
1770                                  sizeof(char *));
1771         if (paths == NULL)
1772                 goto out_of_memory;
1773
1774         data->paths = paths;
1775         data->paths[data->nb_paths] = wpa_s_go->dbus_groupobj_path;
1776         data->nb_paths++;
1777
1778         return 1;
1779
1780 out_of_memory:
1781         data->error = ENOMEM;
1782         return 0;
1783 }
1784
1785
1786 dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
1787         const struct wpa_dbus_property_desc *property_desc,
1788         DBusMessageIter *iter, DBusError *error, void *user_data)
1789 {
1790         struct peer_handler_args *peer_args = user_data;
1791         const struct p2p_peer_info *info;
1792         struct peer_group_data data;
1793         struct wpa_supplicant *wpa_s, *wpa_s_go;
1794         dbus_bool_t success = FALSE;
1795
1796         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1797                                   peer_args->p2p_device_addr, 0);
1798         if (info == NULL) {
1799                 dbus_set_error(error, DBUS_ERROR_FAILED,
1800                                "failed to find peer");
1801                 return FALSE;
1802         }
1803
1804         os_memset(&data, 0, sizeof(data));
1805
1806         wpa_s = peer_args->wpa_s;
1807         wpa_s = wpa_s->global->p2p_init_wpa_s;
1808
1809         wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
1810         if (wpa_s_go) {
1811                 data.paths = os_calloc(1, sizeof(char *));
1812                 if (data.paths == NULL)
1813                         goto out_of_memory;
1814                 data.paths[0] = wpa_s_go->dbus_groupobj_path;
1815                 data.nb_paths = 1;
1816         }
1817
1818         data.wpa_s = peer_args->wpa_s;
1819         data.info = info;
1820
1821         p2p_loop_on_all_groups(peer_args->wpa_s->global->p2p,
1822                                match_group_where_peer_is_client, &data);
1823         if (data.error)
1824                 goto out_of_memory;
1825
1826         if (data.paths == NULL) {
1827                 return wpas_dbus_simple_array_property_getter(
1828                         iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
1829         }
1830
1831         success = wpas_dbus_simple_array_property_getter(iter,
1832                                                          DBUS_TYPE_OBJECT_PATH,
1833                                                          data.paths,
1834                                                          data.nb_paths, error);
1835         goto out;
1836
1837 out_of_memory:
1838         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1839 out:
1840         os_free(data.paths);
1841         return success;
1842 }
1843
1844
1845 /**
1846  * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
1847  * @iter: Pointer to incoming dbus message iter
1848  * @error: Location to store error on failure
1849  * @user_data: Function specific data
1850  * Returns: TRUE on success, FALSE on failure
1851  *
1852  * Getter for "PersistentGroups" property.
1853  */
1854 dbus_bool_t wpas_dbus_getter_persistent_groups(
1855         const struct wpa_dbus_property_desc *property_desc,
1856         DBusMessageIter *iter, DBusError *error, void *user_data)
1857 {
1858         struct wpa_supplicant *wpa_s = user_data;
1859         struct wpa_ssid *ssid;
1860         char **paths;
1861         unsigned int i = 0, num = 0;
1862         dbus_bool_t success = FALSE;
1863
1864         wpa_s = wpa_s->global->p2p_init_wpa_s;
1865         if (!wpa_s->parent->dbus_new_path)
1866                 return FALSE;
1867
1868         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1869                 if (network_is_persistent_group(ssid))
1870                         num++;
1871
1872         paths = os_calloc(num, sizeof(char *));
1873         if (!paths) {
1874                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1875                 return FALSE;
1876         }
1877
1878         /* Loop through configured networks and append object path of each */
1879         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1880                 if (!network_is_persistent_group(ssid))
1881                         continue;
1882                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1883                 if (paths[i] == NULL) {
1884                         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
1885                                              "no memory");
1886                         goto out;
1887                 }
1888                 /* Construct the object path for this network. */
1889                 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1890                             "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1891                             wpa_s->parent->dbus_new_path, ssid->id);
1892         }
1893
1894         success = wpas_dbus_simple_array_property_getter(iter,
1895                                                          DBUS_TYPE_OBJECT_PATH,
1896                                                          paths, num, error);
1897
1898 out:
1899         while (i)
1900                 os_free(paths[--i]);
1901         os_free(paths);
1902         return success;
1903 }
1904
1905
1906 /**
1907  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1908  *      group
1909  * @iter: Pointer to incoming dbus message iter
1910  * @error: Location to store error on failure
1911  * @user_data: Function specific data
1912  * Returns: TRUE on success, FALSE on failure
1913  *
1914  * Getter for "Properties" property of a persistent group.
1915  */
1916 dbus_bool_t wpas_dbus_getter_persistent_group_properties(
1917         const struct wpa_dbus_property_desc *property_desc,
1918         DBusMessageIter *iter, DBusError *error, void *user_data)
1919 {
1920         struct network_handler_args *net = user_data;
1921
1922         /* Leveraging the fact that persistent group object is still
1923          * represented in same manner as network within.
1924          */
1925         return wpas_dbus_getter_network_properties(property_desc, iter, error, net);
1926 }
1927
1928
1929 /**
1930  * wpas_dbus_setter_persistent_group_properties - Set options for a persistent
1931  *      group
1932  * @iter: Pointer to incoming dbus message iter
1933  * @error: Location to store error on failure
1934  * @user_data: Function specific data
1935  * Returns: TRUE on success, FALSE on failure
1936  *
1937  * Setter for "Properties" property of a persistent group.
1938  */
1939 dbus_bool_t wpas_dbus_setter_persistent_group_properties(
1940         const struct wpa_dbus_property_desc *property_desc,
1941         DBusMessageIter *iter, DBusError *error, void *user_data)
1942 {
1943         struct network_handler_args *net = user_data;
1944         struct wpa_ssid *ssid = net->ssid;
1945         DBusMessageIter variant_iter;
1946
1947         /*
1948          * Leveraging the fact that persistent group object is still
1949          * represented in same manner as network within.
1950          */
1951         dbus_message_iter_recurse(iter, &variant_iter);
1952         return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
1953 }
1954
1955
1956 /**
1957  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1958  *      persistent_group
1959  * @message: Pointer to incoming dbus message
1960  * @wpa_s: wpa_supplicant structure for a network interface
1961  * Returns: A dbus message containing the object path of the new
1962  * persistent group
1963  *
1964  * Handler function for "AddPersistentGroup" method call of a P2P Device
1965  * interface.
1966  */
1967 DBusMessage * wpas_dbus_handler_add_persistent_group(
1968         DBusMessage *message, struct wpa_supplicant *wpa_s)
1969 {
1970         DBusMessage *reply = NULL;
1971         DBusMessageIter iter;
1972         struct wpa_ssid *ssid = NULL;
1973         char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1974         DBusError error;
1975
1976         dbus_message_iter_init(message, &iter);
1977
1978         wpa_s = wpa_s->global->p2p_init_wpa_s;
1979         if (wpa_s->parent->dbus_new_path)
1980                 ssid = wpa_config_add_network(wpa_s->conf);
1981         if (ssid == NULL) {
1982                 wpa_printf(MSG_ERROR,
1983                            "dbus: %s: Cannot add new persistent group",
1984                            __func__);
1985                 reply = wpas_dbus_error_unknown_error(
1986                         message,
1987                         "wpa_supplicant could not add a persistent group on this interface.");
1988                 goto err;
1989         }
1990
1991         /* Mark the ssid as being a persistent group before the notification */
1992         ssid->disabled = 2;
1993         ssid->p2p_persistent_group = 1;
1994         wpas_notify_persistent_group_added(wpa_s, ssid);
1995
1996         wpa_config_set_network_defaults(ssid);
1997
1998         dbus_error_init(&error);
1999         if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
2000                 wpa_printf(MSG_DEBUG,
2001                            "dbus: %s: Control interface could not set persistent group properties",
2002                            __func__);
2003                 reply = wpas_dbus_reply_new_from_error(
2004                         message, &error, DBUS_ERROR_INVALID_ARGS,
2005                         "Failed to set network properties");
2006                 dbus_error_free(&error);
2007                 goto err;
2008         }
2009
2010         /* Construct the object path for this network. */
2011         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
2012                     "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
2013                     wpa_s->parent->dbus_new_path, ssid->id);
2014
2015         reply = dbus_message_new_method_return(message);
2016         if (reply == NULL) {
2017                 reply = wpas_dbus_error_no_memory(message);
2018                 goto err;
2019         }
2020         if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
2021                                       DBUS_TYPE_INVALID)) {
2022                 dbus_message_unref(reply);
2023                 reply = wpas_dbus_error_no_memory(message);
2024                 goto err;
2025         }
2026
2027         return reply;
2028
2029 err:
2030         if (ssid) {
2031                 wpas_notify_persistent_group_removed(wpa_s, ssid);
2032                 wpa_config_remove_network(wpa_s->conf, ssid->id);
2033         }
2034         return reply;
2035 }
2036
2037
2038 /**
2039  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
2040  *      group
2041  * @message: Pointer to incoming dbus message
2042  * @wpa_s: wpa_supplicant structure for a network interface
2043  * Returns: NULL on success or dbus error on failure
2044  *
2045  * Handler function for "RemovePersistentGroup" method call of a P2P Device
2046  * interface.
2047  */
2048 DBusMessage * wpas_dbus_handler_remove_persistent_group(
2049         DBusMessage *message, struct wpa_supplicant *wpa_s)
2050 {
2051         DBusMessage *reply = NULL;
2052         const char *op;
2053         char *iface = NULL, *persistent_group_id;
2054         int id;
2055         struct wpa_ssid *ssid;
2056
2057         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
2058                               DBUS_TYPE_INVALID);
2059
2060         wpa_s = wpa_s->global->p2p_init_wpa_s;
2061
2062         /*
2063          * Extract the network ID and ensure the network is actually a child of
2064          * this interface.
2065          */
2066         iface = wpas_dbus_new_decompose_object_path(
2067                 op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
2068                 &persistent_group_id);
2069         if (iface == NULL || persistent_group_id == NULL ||
2070             !wpa_s->parent->dbus_new_path ||
2071             os_strcmp(iface, wpa_s->parent->dbus_new_path) != 0) {
2072                 reply = wpas_dbus_error_invalid_args(message, op);
2073                 goto out;
2074         }
2075
2076         id = strtoul(persistent_group_id, NULL, 10);
2077         if (errno == EINVAL) {
2078                 reply = wpas_dbus_error_invalid_args(message, op);
2079                 goto out;
2080         }
2081
2082         ssid = wpa_config_get_network(wpa_s->conf, id);
2083         if (ssid == NULL) {
2084                 reply = wpas_dbus_error_persistent_group_unknown(message);
2085                 goto out;
2086         }
2087
2088         wpas_notify_persistent_group_removed(wpa_s, ssid);
2089
2090         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
2091                 wpa_printf(MSG_ERROR,
2092                            "dbus: %s: error occurred when removing persistent group %d",
2093                            __func__, id);
2094                 reply = wpas_dbus_error_unknown_error(
2095                         message,
2096                         "error removing the specified persistent group on this interface.");
2097                 goto out;
2098         }
2099
2100 out:
2101         os_free(iface);
2102         return reply;
2103 }
2104
2105
2106 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
2107                                     struct wpa_ssid *ssid)
2108 {
2109         wpas_notify_persistent_group_removed(wpa_s, ssid);
2110
2111         if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
2112                 wpa_printf(MSG_ERROR,
2113                            "dbus: %s: error occurred when removing persistent group %d",
2114                            __func__, ssid->id);
2115                 return;
2116         }
2117 }
2118
2119
2120 /**
2121  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
2122  * persistent groups
2123  * @message: Pointer to incoming dbus message
2124  * @wpa_s: wpa_supplicant structure for a network interface
2125  * Returns: NULL on success or dbus error on failure
2126  *
2127  * Handler function for "RemoveAllPersistentGroups" method call of a
2128  * P2P Device interface.
2129  */
2130 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
2131         DBusMessage *message, struct wpa_supplicant *wpa_s)
2132 {
2133         struct wpa_ssid *ssid, *next;
2134         struct wpa_config *config;
2135
2136         wpa_s = wpa_s->global->p2p_init_wpa_s;
2137
2138         config = wpa_s->conf;
2139         ssid = config->ssid;
2140         while (ssid) {
2141                 next = ssid->next;
2142                 if (network_is_persistent_group(ssid))
2143                         remove_persistent_group(wpa_s, ssid);
2144                 ssid = next;
2145         }
2146         return NULL;
2147 }
2148
2149
2150 /*
2151  * Group object properties accessor methods
2152  */
2153
2154 dbus_bool_t wpas_dbus_getter_p2p_group_members(
2155         const struct wpa_dbus_property_desc *property_desc,
2156         DBusMessageIter *iter, DBusError *error, void *user_data)
2157 {
2158         struct wpa_supplicant *wpa_s = user_data;
2159         struct wpa_ssid *ssid;
2160         unsigned int num_members;
2161         char **paths;
2162         unsigned int i;
2163         void *next = NULL;
2164         const u8 *addr;
2165         dbus_bool_t success = FALSE;
2166
2167         if (!wpa_s->parent->parent->dbus_new_path)
2168                 return FALSE;
2169
2170         /* Verify correct role for this property */
2171         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
2172                 return wpas_dbus_simple_array_property_getter(
2173                         iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
2174         }
2175
2176         ssid = wpa_s->conf->ssid;
2177         /* At present WPAS P2P_GO mode only applicable for p2p_go */
2178         if (ssid->mode != WPAS_MODE_P2P_GO &&
2179             ssid->mode != WPAS_MODE_AP &&
2180             ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
2181                 return FALSE;
2182
2183         num_members = p2p_get_group_num_members(wpa_s->p2p_group);
2184
2185         paths = os_calloc(num_members, sizeof(char *));
2186         if (!paths)
2187                 goto out_of_memory;
2188
2189         i = 0;
2190         while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
2191                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
2192                 if (!paths[i])
2193                         goto out_of_memory;
2194                 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
2195                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
2196                             "/" COMPACT_MACSTR,
2197                             wpa_s->parent->parent->dbus_new_path,
2198                             MAC2STR(addr));
2199                 i++;
2200         }
2201
2202         success = wpas_dbus_simple_array_property_getter(iter,
2203                                                          DBUS_TYPE_OBJECT_PATH,
2204                                                          paths, num_members,
2205                                                          error);
2206
2207         for (i = 0; i < num_members; i++)
2208                 os_free(paths[i]);
2209         os_free(paths);
2210         return success;
2211
2212 out_of_memory:
2213         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2214         if (paths) {
2215                 for (i = 0; i < num_members; i++)
2216                         os_free(paths[i]);
2217                 os_free(paths);
2218         }
2219         return FALSE;
2220 }
2221
2222
2223 dbus_bool_t wpas_dbus_getter_p2p_group_ssid(
2224         const struct wpa_dbus_property_desc *property_desc,
2225         DBusMessageIter *iter, DBusError *error, void *user_data)
2226 {
2227         struct wpa_supplicant *wpa_s = user_data;
2228
2229         if (wpa_s->current_ssid == NULL)
2230                 return FALSE;
2231         return wpas_dbus_simple_array_property_getter(
2232                 iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
2233                 wpa_s->current_ssid->ssid_len, error);
2234 }
2235
2236
2237 dbus_bool_t wpas_dbus_getter_p2p_group_bssid(
2238         const struct wpa_dbus_property_desc *property_desc,
2239         DBusMessageIter *iter, DBusError *error, void *user_data)
2240 {
2241         struct wpa_supplicant *wpa_s = user_data;
2242         u8 role = wpas_get_p2p_role(wpa_s);
2243         u8 *p_bssid;
2244
2245         if (role == WPAS_P2P_ROLE_CLIENT) {
2246                 if (wpa_s->current_ssid == NULL)
2247                         return FALSE;
2248                 p_bssid = wpa_s->current_ssid->bssid;
2249         } else {
2250                 if (wpa_s->ap_iface == NULL)
2251                         return FALSE;
2252                 p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
2253         }
2254
2255         return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2256                                                       p_bssid, ETH_ALEN,
2257                                                       error);
2258 }
2259
2260
2261 dbus_bool_t wpas_dbus_getter_p2p_group_frequency(
2262         const struct wpa_dbus_property_desc *property_desc,
2263         DBusMessageIter *iter, DBusError *error, void *user_data)
2264 {
2265         struct wpa_supplicant *wpa_s = user_data;
2266         u16 op_freq;
2267         u8 role = wpas_get_p2p_role(wpa_s);
2268
2269         if (role == WPAS_P2P_ROLE_CLIENT) {
2270                 if (wpa_s->go_params == NULL)
2271                         return FALSE;
2272                 op_freq = wpa_s->go_params->freq;
2273         } else {
2274                 if (wpa_s->ap_iface == NULL)
2275                         return FALSE;
2276                 op_freq = wpa_s->ap_iface->freq;
2277         }
2278
2279         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
2280                                                 &op_freq, error);
2281 }
2282
2283
2284 dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(
2285         const struct wpa_dbus_property_desc *property_desc,
2286         DBusMessageIter *iter, DBusError *error, void *user_data)
2287 {
2288         struct wpa_supplicant *wpa_s = user_data;
2289         char *p_pass;
2290         struct wpa_ssid *ssid = wpa_s->current_ssid;
2291
2292         if (ssid == NULL)
2293                 return FALSE;
2294
2295         p_pass = ssid->passphrase;
2296         if (!p_pass)
2297                 p_pass = "";
2298
2299         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2300                                                 &p_pass, error);
2301
2302 }
2303
2304
2305 dbus_bool_t wpas_dbus_getter_p2p_group_psk(
2306         const struct wpa_dbus_property_desc *property_desc,
2307         DBusMessageIter *iter, DBusError *error, void *user_data)
2308 {
2309         struct wpa_supplicant *wpa_s = user_data;
2310         u8 *p_psk = NULL;
2311         u8 psk_len = 0;
2312         struct wpa_ssid *ssid = wpa_s->current_ssid;
2313
2314         if (ssid == NULL)
2315                 return FALSE;
2316
2317         if (ssid->psk_set) {
2318                 p_psk = ssid->psk;
2319                 psk_len = sizeof(ssid->psk);
2320         }
2321
2322         return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2323                                                       p_psk, psk_len, error);
2324 }
2325
2326
2327 dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(
2328         const struct wpa_dbus_property_desc *property_desc,
2329         DBusMessageIter *iter, DBusError *error, void *user_data)
2330 {
2331         struct wpa_supplicant *wpa_s = user_data;
2332         struct hostapd_data *hapd;
2333         struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
2334         unsigned int i, num_vendor_ext = 0;
2335
2336         os_memset(vendor_ext, 0, sizeof(vendor_ext));
2337
2338         /* Verify correct role for this property */
2339         if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
2340                 if (wpa_s->ap_iface == NULL)
2341                         return FALSE;
2342                 hapd = wpa_s->ap_iface->bss[0];
2343
2344                 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
2345                 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2346                         if (hapd->conf->wps_vendor_ext[i] == NULL)
2347                                 continue;
2348                         vendor_ext[num_vendor_ext++] =
2349                                 hapd->conf->wps_vendor_ext[i];
2350                 }
2351         }
2352
2353         /* Return vendor extensions or no data */
2354         return wpas_dbus_simple_array_array_property_getter(iter,
2355                                                             DBUS_TYPE_BYTE,
2356                                                             vendor_ext,
2357                                                             num_vendor_ext,
2358                                                             error);
2359 }
2360
2361
2362 dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(
2363         const struct wpa_dbus_property_desc *property_desc,
2364         DBusMessageIter *iter, DBusError *error, void *user_data)
2365 {
2366         struct wpa_supplicant *wpa_s = user_data;
2367         DBusMessageIter variant_iter, iter_dict, array_iter, sub;
2368         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
2369         unsigned int i;
2370         struct hostapd_data *hapd = NULL;
2371
2372         if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO &&
2373             wpa_s->ap_iface != NULL)
2374                 hapd = wpa_s->ap_iface->bss[0];
2375         else
2376                 return FALSE;
2377
2378         dbus_message_iter_recurse(iter, &variant_iter);
2379         if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
2380                 return FALSE;
2381
2382         /*
2383          * This is supposed to be array of bytearrays (aay), but the earlier
2384          * implementation used a dict with "WPSVendorExtensions" as the key in
2385          * this setter function which does not match the format used by the
2386          * getter function. For backwards compatibility, allow both formats to
2387          * be used in the setter.
2388          */
2389         if (dbus_message_iter_get_element_type(&variant_iter) ==
2390             DBUS_TYPE_ARRAY) {
2391                 /* This is the proper format matching the getter */
2392                 struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
2393
2394                 dbus_message_iter_recurse(&variant_iter, &array_iter);
2395
2396                 if (dbus_message_iter_get_arg_type(&array_iter) !=
2397                     DBUS_TYPE_ARRAY ||
2398                     dbus_message_iter_get_element_type(&array_iter) !=
2399                     DBUS_TYPE_BYTE) {
2400                         wpa_printf(MSG_DEBUG,
2401                                    "dbus: Not an array of array of bytes");
2402                         return FALSE;
2403                 }
2404
2405                 i = 0;
2406                 os_memset(vals, 0, sizeof(vals));
2407
2408                 while (dbus_message_iter_get_arg_type(&array_iter) ==
2409                        DBUS_TYPE_ARRAY) {
2410                         char *val;
2411                         int len;
2412
2413                         if (i == MAX_WPS_VENDOR_EXTENSIONS) {
2414                                 wpa_printf(MSG_DEBUG,
2415                                            "dbus: Too many WPSVendorExtensions values");
2416                                 i = MAX_WPS_VENDOR_EXTENSIONS + 1;
2417                                 break;
2418                         }
2419
2420                         dbus_message_iter_recurse(&array_iter, &sub);
2421                         dbus_message_iter_get_fixed_array(&sub, &val, &len);
2422                         wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
2423                                     val, len);
2424                         vals[i] = wpabuf_alloc_copy(val, len);
2425                         if (vals[i] == NULL) {
2426                                 i = MAX_WPS_VENDOR_EXTENSIONS + 1;
2427                                 break;
2428                         }
2429                         i++;
2430                         dbus_message_iter_next(&array_iter);
2431                 }
2432
2433                 if (i > MAX_WPS_VENDOR_EXTENSIONS) {
2434                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
2435                                 wpabuf_free(vals[i]);
2436                         return FALSE;
2437                 }
2438
2439                 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2440                         wpabuf_free(hapd->conf->wps_vendor_ext[i]);
2441                         hapd->conf->wps_vendor_ext[i] = vals[i];
2442                 }
2443
2444                 hostapd_update_wps(hapd);
2445
2446                 return TRUE;
2447         }
2448
2449         if (dbus_message_iter_get_element_type(&variant_iter) !=
2450             DBUS_TYPE_DICT_ENTRY)
2451                 return FALSE;
2452
2453         wpa_printf(MSG_DEBUG,
2454                    "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
2455         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
2456                 return FALSE;
2457
2458         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2459                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
2460                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2461                                              "invalid message format");
2462                         return FALSE;
2463                 }
2464
2465                 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
2466                         if (entry.type != DBUS_TYPE_ARRAY ||
2467                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
2468                             entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
2469                                 goto error;
2470
2471                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2472                                 wpabuf_free(hapd->conf->wps_vendor_ext[i]);
2473                                 if (i < entry.array_len) {
2474                                         hapd->conf->wps_vendor_ext[i] =
2475                                                 entry.binarray_value[i];
2476                                         entry.binarray_value[i] = NULL;
2477                                 } else
2478                                         hapd->conf->wps_vendor_ext[i] = NULL;
2479                         }
2480
2481                         hostapd_update_wps(hapd);
2482                 } else
2483                         goto error;
2484
2485                 wpa_dbus_dict_entry_clear(&entry);
2486         }
2487
2488         return TRUE;
2489
2490 error:
2491         wpa_dbus_dict_entry_clear(&entry);
2492         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2493                              "invalid message format");
2494         return FALSE;
2495 }
2496
2497
2498 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
2499                                                 struct wpa_supplicant *wpa_s)
2500 {
2501         DBusMessageIter iter_dict;
2502         DBusMessage *reply = NULL;
2503         DBusMessageIter iter;
2504         struct wpa_dbus_dict_entry entry;
2505         int upnp = 0;
2506         int bonjour = 0;
2507         char *service = NULL;
2508         struct wpabuf *query = NULL;
2509         struct wpabuf *resp = NULL;
2510         u8 version = 0;
2511
2512         dbus_message_iter_init(message, &iter);
2513
2514         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2515                 goto error;
2516
2517         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2518                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2519                         goto error;
2520
2521                 if (os_strcmp(entry.key, "service_type") == 0 &&
2522                     entry.type == DBUS_TYPE_STRING) {
2523                         if (os_strcmp(entry.str_value, "upnp") == 0)
2524                                 upnp = 1;
2525                         else if (os_strcmp(entry.str_value, "bonjour") == 0)
2526                                 bonjour = 1;
2527                         else
2528                                 goto error_clear;
2529                 } else if (os_strcmp(entry.key, "version") == 0 &&
2530                            entry.type == DBUS_TYPE_INT32) {
2531                         version = entry.uint32_value;
2532                 } else if (os_strcmp(entry.key, "service") == 0 &&
2533                            entry.type == DBUS_TYPE_STRING) {
2534                         os_free(service);
2535                         service = os_strdup(entry.str_value);
2536                 } else if (os_strcmp(entry.key, "query") == 0) {
2537                         if (entry.type != DBUS_TYPE_ARRAY ||
2538                             entry.array_type != DBUS_TYPE_BYTE)
2539                                 goto error_clear;
2540                         query = wpabuf_alloc_copy(
2541                                 entry.bytearray_value,
2542                                 entry.array_len);
2543                 } else if (os_strcmp(entry.key, "response") == 0) {
2544                         if (entry.type != DBUS_TYPE_ARRAY ||
2545                             entry.array_type != DBUS_TYPE_BYTE)
2546                                 goto error_clear;
2547                         resp = wpabuf_alloc_copy(entry.bytearray_value,
2548                                                  entry.array_len);
2549                 }
2550                 wpa_dbus_dict_entry_clear(&entry);
2551         }
2552
2553         if (upnp == 1) {
2554                 if (version <= 0 || service == NULL)
2555                         goto error;
2556
2557                 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
2558                         goto error;
2559
2560         } else if (bonjour == 1) {
2561                 if (query == NULL || resp == NULL)
2562                         goto error;
2563
2564                 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
2565                         goto error;
2566                 query = NULL;
2567                 resp = NULL;
2568         } else
2569                 goto error;
2570
2571         os_free(service);
2572         return reply;
2573 error_clear:
2574         wpa_dbus_dict_entry_clear(&entry);
2575 error:
2576         os_free(service);
2577         wpabuf_free(query);
2578         wpabuf_free(resp);
2579         return wpas_dbus_error_invalid_args(message, NULL);
2580 }
2581
2582
2583 DBusMessage * wpas_dbus_handler_p2p_delete_service(
2584         DBusMessage *message, struct wpa_supplicant *wpa_s)
2585 {
2586         DBusMessageIter iter_dict;
2587         DBusMessage *reply = NULL;
2588         DBusMessageIter iter;
2589         struct wpa_dbus_dict_entry entry;
2590         int upnp = 0;
2591         int bonjour = 0;
2592         int ret = 0;
2593         char *service = NULL;
2594         struct wpabuf *query = NULL;
2595         u8 version = 0;
2596
2597         dbus_message_iter_init(message, &iter);
2598
2599         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2600                 goto error;
2601
2602         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2603                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2604                         goto error;
2605
2606                 if (os_strcmp(entry.key, "service_type") == 0 &&
2607                     entry.type == DBUS_TYPE_STRING) {
2608                         if (os_strcmp(entry.str_value, "upnp") == 0)
2609                                 upnp = 1;
2610                         else if (os_strcmp(entry.str_value, "bonjour") == 0)
2611                                 bonjour = 1;
2612                         else
2613                                 goto error_clear;
2614                         wpa_dbus_dict_entry_clear(&entry);
2615                 }
2616         }
2617         if (upnp == 1) {
2618                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2619                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2620                                 goto error;
2621                         if (os_strcmp(entry.key, "version") == 0 &&
2622                             entry.type == DBUS_TYPE_INT32)
2623                                 version = entry.uint32_value;
2624                         else if (os_strcmp(entry.key, "service") == 0 &&
2625                                  entry.type == DBUS_TYPE_STRING) {
2626                                 os_free(service);
2627                                 service = os_strdup(entry.str_value);
2628                         } else
2629                                 goto error_clear;
2630
2631                         wpa_dbus_dict_entry_clear(&entry);
2632                 }
2633
2634                 if (version <= 0 || service == NULL)
2635                         goto error;
2636
2637                 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
2638                 if (ret != 0)
2639                         goto error;
2640         } else if (bonjour == 1) {
2641                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2642                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2643                                 goto error;
2644
2645                         if (os_strcmp(entry.key, "query") == 0) {
2646                                 if (entry.type != DBUS_TYPE_ARRAY ||
2647                                     entry.array_type != DBUS_TYPE_BYTE)
2648                                         goto error_clear;
2649                                 wpabuf_free(query);
2650                                 query = wpabuf_alloc_copy(
2651                                         entry.bytearray_value,
2652                                         entry.array_len);
2653                         } else
2654                                 goto error_clear;
2655
2656                         wpa_dbus_dict_entry_clear(&entry);
2657                 }
2658
2659                 if (query == NULL)
2660                         goto error;
2661
2662                 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
2663                 if (ret != 0)
2664                         goto error;
2665         } else
2666                 goto error;
2667
2668         wpabuf_free(query);
2669         os_free(service);
2670         return reply;
2671 error_clear:
2672         wpa_dbus_dict_entry_clear(&entry);
2673 error:
2674         wpabuf_free(query);
2675         os_free(service);
2676         return wpas_dbus_error_invalid_args(message, NULL);
2677 }
2678
2679
2680 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
2681                                                   struct wpa_supplicant *wpa_s)
2682 {
2683         wpas_p2p_service_flush(wpa_s);
2684         return NULL;
2685 }
2686
2687
2688 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
2689         DBusMessage *message, struct wpa_supplicant *wpa_s)
2690 {
2691         DBusMessageIter iter_dict;
2692         DBusMessage *reply = NULL;
2693         DBusMessageIter iter;
2694         struct wpa_dbus_dict_entry entry;
2695         int upnp = 0;
2696         char *service = NULL;
2697         char *peer_object_path = NULL;
2698         struct wpabuf *tlv = NULL;
2699         u8 version = 0;
2700         u64 ref = 0;
2701         u8 addr_buf[ETH_ALEN], *addr;
2702
2703         dbus_message_iter_init(message, &iter);
2704
2705         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2706                 goto error;
2707
2708         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2709                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2710                         goto error;
2711                 if (os_strcmp(entry.key, "peer_object") == 0 &&
2712                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2713                         peer_object_path = os_strdup(entry.str_value);
2714                 } else if (os_strcmp(entry.key, "service_type") == 0 &&
2715                            entry.type == DBUS_TYPE_STRING) {
2716                         if (os_strcmp(entry.str_value, "upnp") == 0)
2717                                 upnp = 1;
2718                         else
2719                                 goto error_clear;
2720                 } else if (os_strcmp(entry.key, "version") == 0 &&
2721                            entry.type == DBUS_TYPE_INT32) {
2722                         version = entry.uint32_value;
2723                 } else if (os_strcmp(entry.key, "service") == 0 &&
2724                            entry.type == DBUS_TYPE_STRING) {
2725                         service = os_strdup(entry.str_value);
2726                 } else if (os_strcmp(entry.key, "tlv") == 0) {
2727                         if (entry.type != DBUS_TYPE_ARRAY ||
2728                             entry.array_type != DBUS_TYPE_BYTE)
2729                                 goto error_clear;
2730                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2731                                                 entry.array_len);
2732                 } else
2733                         goto error_clear;
2734
2735                 wpa_dbus_dict_entry_clear(&entry);
2736         }
2737
2738         if (!peer_object_path) {
2739                 addr = NULL;
2740         } else {
2741                 if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
2742                     !p2p_peer_known(wpa_s->global->p2p, addr_buf))
2743                         goto error;
2744
2745                 addr = addr_buf;
2746         }
2747
2748         if (upnp == 1) {
2749                 if (version <= 0 || service == NULL)
2750                         goto error;
2751
2752                 ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
2753         } else {
2754                 if (tlv == NULL)
2755                         goto error;
2756                 ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
2757                 wpabuf_free(tlv);
2758         }
2759
2760         if (ref != 0) {
2761                 reply = dbus_message_new_method_return(message);
2762                 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2763                                          &ref, DBUS_TYPE_INVALID);
2764         } else {
2765                 reply = wpas_dbus_error_unknown_error(
2766                         message, "Unable to send SD request");
2767         }
2768 out:
2769         os_free(service);
2770         os_free(peer_object_path);
2771         return reply;
2772 error_clear:
2773         wpa_dbus_dict_entry_clear(&entry);
2774 error:
2775         if (tlv)
2776                 wpabuf_free(tlv);
2777         reply = wpas_dbus_error_invalid_args(message, NULL);
2778         goto out;
2779 }
2780
2781
2782 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2783         DBusMessage *message, struct wpa_supplicant *wpa_s)
2784 {
2785         DBusMessageIter iter_dict;
2786         DBusMessage *reply = NULL;
2787         DBusMessageIter iter;
2788         struct wpa_dbus_dict_entry entry;
2789         char *peer_object_path = NULL;
2790         struct wpabuf *tlv = NULL;
2791         int freq = 0;
2792         int dlg_tok = 0;
2793         u8 addr[ETH_ALEN];
2794
2795         dbus_message_iter_init(message, &iter);
2796
2797         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2798                 goto error;
2799
2800         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2801                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2802                         goto error;
2803
2804                 if (os_strcmp(entry.key, "peer_object") == 0 &&
2805                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2806                         peer_object_path = os_strdup(entry.str_value);
2807                 } else if (os_strcmp(entry.key, "frequency") == 0 &&
2808                            entry.type == DBUS_TYPE_INT32) {
2809                         freq = entry.uint32_value;
2810                 } else if (os_strcmp(entry.key, "dialog_token") == 0 &&
2811                            (entry.type == DBUS_TYPE_UINT32 ||
2812                             entry.type == DBUS_TYPE_INT32)) {
2813                         dlg_tok = entry.uint32_value;
2814                 } else if (os_strcmp(entry.key, "tlvs") == 0) {
2815                         if (entry.type != DBUS_TYPE_ARRAY ||
2816                             entry.array_type != DBUS_TYPE_BYTE)
2817                                 goto error_clear;
2818                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2819                                                 entry.array_len);
2820                 } else
2821                         goto error_clear;
2822
2823                 wpa_dbus_dict_entry_clear(&entry);
2824         }
2825         if (parse_peer_object_path(peer_object_path, addr) < 0 ||
2826             !p2p_peer_known(wpa_s->global->p2p, addr) ||
2827             tlv == NULL)
2828                 goto error;
2829
2830         wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2831         wpabuf_free(tlv);
2832 out:
2833         os_free(peer_object_path);
2834         return reply;
2835 error_clear:
2836         wpa_dbus_dict_entry_clear(&entry);
2837 error:
2838         reply = wpas_dbus_error_invalid_args(message, NULL);
2839         goto out;
2840 }
2841
2842
2843 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2844         DBusMessage *message, struct wpa_supplicant *wpa_s)
2845 {
2846         DBusMessageIter iter;
2847         u64 req = 0;
2848
2849         dbus_message_iter_init(message, &iter);
2850         dbus_message_iter_get_basic(&iter, &req);
2851
2852         if (req == 0)
2853                 goto error;
2854
2855         if (wpas_p2p_sd_cancel_request(wpa_s, req) < 0)
2856                 goto error;
2857
2858         return NULL;
2859 error:
2860         return wpas_dbus_error_invalid_args(message, NULL);
2861 }
2862
2863
2864 DBusMessage * wpas_dbus_handler_p2p_service_update(
2865         DBusMessage *message, struct wpa_supplicant *wpa_s)
2866 {
2867         wpas_p2p_sd_service_update(wpa_s);
2868         return NULL;
2869 }
2870
2871
2872 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2873         DBusMessage *message, struct wpa_supplicant *wpa_s)
2874 {
2875         DBusMessageIter iter;
2876         int ext = 0;
2877
2878         dbus_message_iter_init(message, &iter);
2879         dbus_message_iter_get_basic(&iter, &ext);
2880
2881         wpa_s->p2p_sd_over_ctrl_iface = ext;
2882
2883         return NULL;
2884
2885 }
2886
2887
2888 #ifdef CONFIG_WIFI_DISPLAY
2889
2890 dbus_bool_t wpas_dbus_getter_global_wfd_ies(
2891         const struct wpa_dbus_property_desc *property_desc,
2892         DBusMessageIter *iter, DBusError *error, void *user_data)
2893 {
2894         struct wpa_global *global = user_data;
2895         struct wpabuf *ie;
2896         dbus_bool_t ret;
2897
2898         ie = wifi_display_get_wfd_ie(global);
2899         if (ie == NULL)
2900                 return wpas_dbus_simple_array_property_getter(iter,
2901                                                               DBUS_TYPE_BYTE,
2902                                                               NULL, 0, error);
2903
2904         ret = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2905                                                      wpabuf_head(ie),
2906                                                      wpabuf_len(ie), error);
2907         wpabuf_free(ie);
2908
2909         return ret;
2910 }
2911
2912
2913 dbus_bool_t wpas_dbus_setter_global_wfd_ies(
2914         const struct wpa_dbus_property_desc *property_desc,
2915         DBusMessageIter *iter, DBusError *error, void *user_data)
2916 {
2917         struct wpa_global *global = user_data;
2918         DBusMessageIter variant, array;
2919         struct wpabuf *ie = NULL;
2920         const u8 *data;
2921         int len;
2922
2923         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
2924                 goto err;
2925
2926         dbus_message_iter_recurse(iter, &variant);
2927         if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
2928                 goto err;
2929
2930         dbus_message_iter_recurse(&variant, &array);
2931         dbus_message_iter_get_fixed_array(&array, &data, &len);
2932         if (len == 0) {
2933                 wifi_display_enable(global, 0);
2934                 wifi_display_deinit(global);
2935
2936                 return TRUE;
2937         }
2938
2939         ie = wpabuf_alloc(len);
2940         if (ie == NULL)
2941                 goto err;
2942
2943         wpabuf_put_data(ie, data, len);
2944         if (wifi_display_subelem_set_from_ies(global, ie) != 0)
2945                 goto err;
2946
2947         if (global->wifi_display == 0)
2948                 wifi_display_enable(global, 1);
2949
2950         wpabuf_free(ie);
2951
2952         return TRUE;
2953 err:
2954         wpabuf_free(ie);
2955
2956         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2957                              "invalid message format");
2958         return FALSE;
2959 }
2960
2961 #endif /* CONFIG_WIFI_DISPLAY */