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