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