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