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