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