dbus: clean up new D-Bus interface getters and setters
[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, NULL))
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, NULL))
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, NULL))
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, NULL))
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, NULL))
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, NULL))
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 dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
665                                                    DBusError *error,
666                                                    void *user_data)
667 {
668         struct wpa_supplicant *wpa_s = user_data;
669         DBusMessageIter variant_iter, dict_iter;
670         DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
671                 iter_secdev_dict_array;
672         const char *dev_name;
673         int num_vendor_extensions = 0;
674         int i;
675         const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
676
677         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
678                                               "a{sv}", &variant_iter) ||
679             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
680                 goto err_no_mem;
681
682         /* DeviceName */
683         dev_name = wpa_s->conf->device_name;
684         if (dev_name &&
685             !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
686                 goto err_no_mem;
687
688         /* Primary device type */
689         if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
690                                              (char *)wpa_s->conf->device_type,
691                                              WPS_DEV_TYPE_LEN))
692                 goto err_no_mem;
693
694         /* Secondary device types */
695         if (wpa_s->conf->num_sec_device_types) {
696                 if (!wpa_dbus_dict_begin_array(&dict_iter,
697                                                "SecondaryDeviceTypes",
698                                                DBUS_TYPE_ARRAY_AS_STRING
699                                                DBUS_TYPE_BYTE_AS_STRING,
700                                                &iter_secdev_dict_entry,
701                                                &iter_secdev_dict_val,
702                                                &iter_secdev_dict_array))
703                         goto err_no_mem;
704
705                 for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
706                         wpa_dbus_dict_bin_array_add_element(
707                                 &iter_secdev_dict_array,
708                                 wpa_s->conf->sec_device_type[i],
709                                 WPS_DEV_TYPE_LEN);
710
711                 if (!wpa_dbus_dict_end_array(&dict_iter,
712                                              &iter_secdev_dict_entry,
713                                              &iter_secdev_dict_val,
714                                              &iter_secdev_dict_array))
715                         goto err_no_mem;
716         }
717
718         /* Vendor Extensions */
719         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
720                 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
721                         continue;
722                 vendor_ext[num_vendor_extensions++] =
723                         wpa_s->conf->wps_vendor_ext[i];
724         }
725
726         if (num_vendor_extensions &&
727             !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
728                                                "VendorExtension",
729                                                vendor_ext,
730                                                num_vendor_extensions))
731                 goto err_no_mem;
732
733         /* GO Intent */
734         if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
735                                          wpa_s->conf->p2p_go_intent))
736                 goto err_no_mem;
737
738         /* Persistant Reconnect */
739         if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
740                                        wpa_s->conf->persistent_reconnect))
741                 goto err_no_mem;
742
743         /* Listen Reg Class */
744         if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
745                                          wpa_s->conf->p2p_listen_reg_class))
746                 goto err_no_mem;
747
748         /* Listen Channel */
749         if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
750                                          wpa_s->conf->p2p_listen_channel))
751                 goto err_no_mem;
752
753         /* Oper Reg Class */
754         if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
755                                          wpa_s->conf->p2p_oper_reg_class))
756                 goto err_no_mem;
757
758         /* Oper Channel */
759         if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
760                                          wpa_s->conf->p2p_oper_channel))
761                 goto err_no_mem;
762
763         /* SSID Postfix */
764         if (wpa_s->conf->p2p_ssid_postfix &&
765             !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
766                                          wpa_s->conf->p2p_ssid_postfix))
767                 goto err_no_mem;
768
769         /* Intra Bss */
770         if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
771                                        wpa_s->conf->p2p_intra_bss))
772                 goto err_no_mem;
773
774         /* Group Idle */
775         if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
776                                          wpa_s->conf->p2p_group_idle))
777                 goto err_no_mem;
778
779         /* Dissasociation low ack */
780         if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
781                                          wpa_s->conf->disassoc_low_ack))
782                 goto err_no_mem;
783
784         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
785             !dbus_message_iter_close_container(iter, &variant_iter))
786                 goto err_no_mem;
787
788         return TRUE;
789
790 err_no_mem:
791         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
792         return FALSE;
793 }
794
795
796 dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
797                                                    DBusError *error,
798                                                    void *user_data)
799 {
800         struct wpa_supplicant *wpa_s = user_data;
801         DBusMessageIter variant_iter, iter_dict;
802         struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
803         unsigned int i;
804
805         dbus_message_iter_recurse(iter, &variant_iter);
806         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
807                 return FALSE;
808
809         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
810                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
811                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
812                                              "invalid message format");
813                         return FALSE;
814                 }
815
816                 if (os_strcmp(entry.key, "DeviceName") == 0) {
817                         char *devname;
818
819                         if (entry.type != DBUS_TYPE_STRING)
820                                 goto error;
821
822                         devname = os_strdup(entry.str_value);
823                         if (devname == NULL)
824                                 goto err_no_mem_clear;
825
826                         os_free(wpa_s->conf->device_name);
827                         wpa_s->conf->device_name = devname;
828
829                         wpa_s->conf->changed_parameters |=
830                                 CFG_CHANGED_DEVICE_NAME;
831                 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
832                         if (entry.type != DBUS_TYPE_ARRAY ||
833                             entry.array_type != DBUS_TYPE_BYTE ||
834                             entry.array_len != WPS_DEV_TYPE_LEN)
835                                 goto error;
836
837                         os_memcpy(wpa_s->conf->device_type,
838                                   entry.bytearray_value,
839                                   WPS_DEV_TYPE_LEN);
840                         wpa_s->conf->changed_parameters |=
841                                 CFG_CHANGED_DEVICE_TYPE;
842                 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
843                         if (entry.type != DBUS_TYPE_ARRAY ||
844                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
845                             entry.array_len > MAX_SEC_DEVICE_TYPES)
846                                 goto error;
847
848                         for (i = 0; i < entry.array_len; i++)
849                                 if (wpabuf_len(entry.binarray_value[i]) !=
850                                     WPS_DEV_TYPE_LEN)
851                                         goto err_no_mem_clear;
852                         for (i = 0; i < entry.array_len; i++)
853                                 os_memcpy(wpa_s->conf->sec_device_type[i],
854                                           wpabuf_head(entry.binarray_value[i]),
855                                           WPS_DEV_TYPE_LEN);
856                         wpa_s->conf->num_sec_device_types = entry.array_len;
857                         wpa_s->conf->changed_parameters |=
858                                         CFG_CHANGED_SEC_DEVICE_TYPE;
859                 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
860                         if ((entry.type != DBUS_TYPE_ARRAY) ||
861                             (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
862                             (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
863                                 goto error;
864
865                         wpa_s->conf->changed_parameters |=
866                                 CFG_CHANGED_VENDOR_EXTENSION;
867
868                         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
869                                 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
870                                 if (i < entry.array_len) {
871                                         wpa_s->conf->wps_vendor_ext[i] =
872                                                 entry.binarray_value[i];
873                                         entry.binarray_value[i] = NULL;
874                                 } else
875                                         wpa_s->conf->wps_vendor_ext[i] = NULL;
876                         }
877                 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
878                            (entry.type == DBUS_TYPE_UINT32) &&
879                            (entry.uint32_value <= 15))
880                         wpa_s->conf->p2p_go_intent = entry.uint32_value;
881                 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
882                          (entry.type == DBUS_TYPE_BOOLEAN))
883                         wpa_s->conf->persistent_reconnect = entry.bool_value;
884                 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
885                          (entry.type == DBUS_TYPE_UINT32)) {
886                         wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
887                         wpa_s->conf->changed_parameters |=
888                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
889                 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
890                            (entry.type == DBUS_TYPE_UINT32)) {
891                         wpa_s->conf->p2p_listen_channel = entry.uint32_value;
892                         wpa_s->conf->changed_parameters |=
893                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
894                 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
895                            (entry.type == DBUS_TYPE_UINT32)) {
896                         wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
897                         wpa_s->conf->changed_parameters |=
898                                 CFG_CHANGED_P2P_OPER_CHANNEL;
899                 } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
900                            (entry.type == DBUS_TYPE_UINT32)) {
901                         wpa_s->conf->p2p_oper_channel = entry.uint32_value;
902                         wpa_s->conf->changed_parameters |=
903                                 CFG_CHANGED_P2P_OPER_CHANNEL;
904                 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
905                         char *postfix;
906
907                         if (entry.type != DBUS_TYPE_STRING)
908                                 goto error;
909
910                         postfix = os_strdup(entry.str_value);
911                         if (!postfix)
912                                 goto err_no_mem_clear;
913
914                         os_free(wpa_s->conf->p2p_ssid_postfix);
915                         wpa_s->conf->p2p_ssid_postfix = postfix;
916
917                         wpa_s->conf->changed_parameters |=
918                                         CFG_CHANGED_P2P_SSID_POSTFIX;
919                 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
920                            (entry.type == DBUS_TYPE_BOOLEAN)) {
921                         wpa_s->conf->p2p_intra_bss = entry.bool_value;
922                         wpa_s->conf->changed_parameters |=
923                                 CFG_CHANGED_P2P_INTRA_BSS;
924                 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
925                            (entry.type == DBUS_TYPE_UINT32))
926                         wpa_s->conf->p2p_group_idle = entry.uint32_value;
927                 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
928                          entry.type == DBUS_TYPE_UINT32)
929                         wpa_s->conf->disassoc_low_ack = entry.uint32_value;
930                 else
931                         goto error;
932
933                 wpa_dbus_dict_entry_clear(&entry);
934         }
935
936         if (wpa_s->conf->changed_parameters) {
937                 /* Some changed parameters requires to update config*/
938                 wpa_supplicant_update_config(wpa_s);
939         }
940
941         return TRUE;
942
943  error:
944         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
945                              "invalid message format");
946         wpa_dbus_dict_entry_clear(&entry);
947         return FALSE;
948
949  err_no_mem_clear:
950         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
951         wpa_dbus_dict_entry_clear(&entry);
952         return FALSE;
953 }
954
955
956 dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
957                                        void *user_data)
958 {
959         struct wpa_supplicant *wpa_s = user_data;
960         struct p2p_data *p2p = wpa_s->global->p2p;
961         int next = 0, i = 0;
962         int num = 0, out_of_mem = 0;
963         const u8 *addr;
964         const struct p2p_peer_info *peer_info = NULL;
965         dbus_bool_t success = FALSE;
966
967         struct dl_list peer_objpath_list;
968         struct peer_objpath_node {
969                 struct dl_list list;
970                 char path[WPAS_DBUS_OBJECT_PATH_MAX];
971         } *node, *tmp;
972
973         char **peer_obj_paths = NULL;
974
975         dl_list_init(&peer_objpath_list);
976
977         /* Get the first peer info */
978         peer_info = p2p_get_peer_found(p2p, NULL, next);
979
980         /* Get next and accumulate them */
981         next = 1;
982         while (peer_info != NULL) {
983                 node = os_zalloc(sizeof(struct peer_objpath_node));
984                 if (!node) {
985                         out_of_mem = 1;
986                         goto error;
987                 }
988
989                 addr = peer_info->p2p_device_addr;
990                 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
991                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
992                             "/" COMPACT_MACSTR,
993                             wpa_s->dbus_new_path, MAC2STR(addr));
994                 dl_list_add_tail(&peer_objpath_list, &node->list);
995                 num++;
996
997                 peer_info = p2p_get_peer_found(p2p, addr, next);
998         }
999
1000         /*
1001          * Now construct the peer object paths in a form suitable for
1002          * array_property_getter helper below.
1003          */
1004         peer_obj_paths = os_zalloc(num * sizeof(char *));
1005
1006         if (!peer_obj_paths) {
1007                 out_of_mem = 1;
1008                 goto error;
1009         }
1010
1011         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1012                               struct peer_objpath_node, list)
1013                 peer_obj_paths[i++] = node->path;
1014
1015         success = wpas_dbus_simple_array_property_getter(iter,
1016                                                          DBUS_TYPE_OBJECT_PATH,
1017                                                          peer_obj_paths, num,
1018                                                          error);
1019
1020 error:
1021         if (peer_obj_paths)
1022                 os_free(peer_obj_paths);
1023
1024         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1025                               struct peer_objpath_node, list) {
1026                 dl_list_del(&node->list);
1027                 os_free(node);
1028         }
1029         if (out_of_mem)
1030                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1031
1032         return success;
1033 }
1034
1035
1036 enum wpas_p2p_role {
1037         WPAS_P2P_ROLE_DEVICE,
1038         WPAS_P2P_ROLE_GO,
1039         WPAS_P2P_ROLE_CLIENT,
1040 };
1041
1042 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1043 {
1044         struct wpa_ssid *ssid = wpa_s->current_ssid;
1045
1046         if (!ssid)
1047                 return WPAS_P2P_ROLE_DEVICE;
1048         if (wpa_s->wpa_state != WPA_COMPLETED)
1049                 return WPAS_P2P_ROLE_DEVICE;
1050
1051         switch (ssid->mode) {
1052         case WPAS_MODE_P2P_GO:
1053         case WPAS_MODE_P2P_GROUP_FORMATION:
1054                 return WPAS_P2P_ROLE_GO;
1055         case WPAS_MODE_INFRA:
1056                 if (ssid->p2p_group)
1057                         return WPAS_P2P_ROLE_CLIENT;
1058                 return WPAS_P2P_ROLE_DEVICE;
1059         default:
1060                 return WPAS_P2P_ROLE_DEVICE;
1061         }
1062 }
1063
1064
1065 dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
1066                                       void *user_data)
1067 {
1068         struct wpa_supplicant *wpa_s = user_data;
1069         char *str;
1070
1071         switch (wpas_get_p2p_role(wpa_s)) {
1072         case WPAS_P2P_ROLE_GO:
1073                 str = "GO";
1074                 break;
1075         case WPAS_P2P_ROLE_CLIENT:
1076                 str = "client";
1077                 break;
1078         default:
1079                 str = "device";
1080         }
1081
1082         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
1083                                                 error);
1084 }
1085
1086
1087 dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
1088                                        void *user_data)
1089 {
1090         struct wpa_supplicant *wpa_s = user_data;
1091
1092         if (wpa_s->dbus_groupobj_path == NULL)
1093                 return FALSE;
1094
1095         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1096                                                 &wpa_s->dbus_groupobj_path,
1097                                                 error);
1098 }
1099
1100
1101 dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
1102                                         DBusError *error, void *user_data)
1103 {
1104         struct wpa_supplicant *wpa_s = user_data;
1105         char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1106
1107         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1108                 return FALSE;
1109
1110         os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1111                     "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1112                     wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1113         path = go_peer_obj_path;
1114         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1115                                                 &path, error);
1116 }
1117
1118
1119 /*
1120  * Peer object properties accessor methods
1121  */
1122
1123 dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
1124         DBusError *error, void *user_data)
1125 {
1126         struct peer_handler_args *peer_args = user_data;
1127         DBusMessageIter variant_iter, dict_iter;
1128         const struct p2p_peer_info *info = NULL;
1129         char devtype[WPS_DEV_TYPE_BUFSIZE];
1130         const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1131         int i, num;
1132
1133         /* get the peer info */
1134         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1135                                   peer_args->p2p_device_addr, 0);
1136         if (info == NULL) {
1137                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1138                 return FALSE;
1139         }
1140
1141         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1142                                               "a{sv}", &variant_iter) ||
1143             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1144                 goto err_no_mem;
1145
1146         /* Fill out the dictionary */
1147         wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1148         if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1149                                          info->device_name))
1150                 goto err_no_mem;
1151         if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1152                                          devtype))
1153                 goto err_no_mem;
1154         if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1155                                          info->config_methods))
1156                 goto err_no_mem;
1157         if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1158                                         info->level))
1159                 goto err_no_mem;
1160         if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1161                                        info->dev_capab))
1162                 goto err_no_mem;
1163         if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1164                                        info->group_capab))
1165                 goto err_no_mem;
1166
1167         if (info->wps_sec_dev_type_list_len) {
1168                 char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1169                 u8 *sec_dev_type_list = NULL;
1170                 char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1171                 int num_sec_dev_types = 0;
1172
1173                 sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1174
1175                 if (sec_dev_type_list == NULL)
1176                         goto err_no_mem;
1177
1178                 os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1179                           info->wps_sec_dev_type_list_len);
1180
1181                 for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1182                        i < (int) (info->wps_sec_dev_type_list_len /
1183                                   WPS_DEV_TYPE_LEN);
1184                      i++) {
1185                         sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1186
1187                         if (!sec_dev_types[i] ||
1188                             wps_dev_type_bin2str(
1189                                     &sec_dev_type_list[i * WPS_DEV_TYPE_LEN],
1190                                     sec_dev_types[i],
1191                                     sizeof(secdevtype)) == NULL) {
1192                                 while (--i >= 0)
1193                                         os_free(sec_dev_types[i]);
1194                                 os_free(sec_dev_type_list);
1195                                 goto err_no_mem;
1196                         }
1197
1198                         num_sec_dev_types++;
1199                 }
1200
1201                 os_free(sec_dev_type_list);
1202
1203                 if (num_sec_dev_types) {
1204                         if (!wpa_dbus_dict_append_string_array(&dict_iter,
1205                                                 "SecondaryDeviceTypes",
1206                                                 (const char **)sec_dev_types,
1207                                                 num_sec_dev_types)) {
1208                                 for (i = 0; i < num_sec_dev_types; i++)
1209                                         os_free(sec_dev_types[i]);
1210                                 goto err_no_mem;
1211                         }
1212
1213                         for (i = 0; i < num_sec_dev_types; i++)
1214                                 os_free(sec_dev_types[i]);
1215                 }
1216         }
1217
1218         /* Add WPS vendor extensions attribute */
1219         for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1220                 if (info->wps_vendor_ext[i] == NULL)
1221                         continue;
1222                 vendor_extension[num] = info->wps_vendor_ext[i];
1223                 num++;
1224         }
1225
1226         if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension",
1227                                                vendor_extension, num))
1228                 goto err_no_mem;
1229
1230         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1231             !dbus_message_iter_close_container(iter, &variant_iter))
1232                 goto err_no_mem;
1233
1234         return TRUE;
1235
1236 err_no_mem:
1237         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1238         return FALSE;
1239 }
1240
1241
1242 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
1243                                           DBusError *error, void *user_data)
1244 {
1245         /* struct peer_handler_args *peer_args = user_data; */
1246
1247         dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
1248         return FALSE;
1249 }
1250
1251
1252 /**
1253  * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
1254  * @iter: Pointer to incoming dbus message iter
1255  * @error: Location to store error on failure
1256  * @user_data: Function specific data
1257  * Returns: TRUE on success, FALSE on failure
1258  *
1259  * Getter for "PersistentGroups" property.
1260  */
1261 dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
1262                                                DBusError *error,
1263                                                void *user_data)
1264 {
1265         struct wpa_supplicant *wpa_s = user_data;
1266         struct wpa_ssid *ssid;
1267         char **paths;
1268         unsigned int i = 0, num = 0;
1269         dbus_bool_t success = FALSE;
1270
1271         if (wpa_s->conf == NULL) {
1272                 wpa_printf(MSG_ERROR, "dbus: %s: "
1273                            "An error occurred getting persistent groups list",
1274                            __func__);
1275                 dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
1276                                      "occurred getting persistent groups list");
1277                 return FALSE;
1278         }
1279
1280         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1281                 if (network_is_persistent_group(ssid))
1282                         num++;
1283
1284         paths = os_zalloc(num * sizeof(char *));
1285         if (!paths) {
1286                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1287                 return FALSE;
1288         }
1289
1290         /* Loop through configured networks and append object path of each */
1291         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1292                 if (!network_is_persistent_group(ssid))
1293                         continue;
1294                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1295                 if (paths[i] == NULL) {
1296                         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
1297                                              "no memory");
1298                         goto out;
1299                 }
1300                 /* Construct the object path for this network. */
1301                 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1302                             "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1303                             wpa_s->dbus_new_path, ssid->id);
1304         }
1305
1306         success = wpas_dbus_simple_array_property_getter(iter,
1307                                                          DBUS_TYPE_OBJECT_PATH,
1308                                                          paths, num, error);
1309
1310 out:
1311         while (i)
1312                 os_free(paths[--i]);
1313         os_free(paths);
1314         return success;
1315 }
1316
1317
1318 /**
1319  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1320  *      group
1321  * @iter: Pointer to incoming dbus message iter
1322  * @error: Location to store error on failure
1323  * @user_data: Function specific data
1324  * Returns: TRUE on success, FALSE on failure
1325  *
1326  * Getter for "Properties" property of a persistent group.
1327  */
1328 dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
1329                                                          DBusError *error,
1330                                                          void *user_data)
1331 {
1332         struct network_handler_args *net = user_data;
1333
1334         /* Leveraging the fact that persistent group object is still
1335          * represented in same manner as network within.
1336          */
1337         return wpas_dbus_getter_network_properties(iter, error, net);
1338 }
1339
1340
1341 /**
1342  * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1343  *      group
1344  * @iter: Pointer to incoming dbus message iter
1345  * @error: Location to store error on failure
1346  * @user_data: Function specific data
1347  * Returns: TRUE on success, FALSE on failure
1348  *
1349  * Setter for "Properties" property of a persistent group.
1350  */
1351 dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
1352                                                          DBusError *error,
1353                                                          void *user_data)
1354 {
1355         struct network_handler_args *net = user_data;
1356         struct wpa_ssid *ssid = net->ssid;
1357         DBusMessageIter variant_iter;
1358
1359         /*
1360          * Leveraging the fact that persistent group object is still
1361          * represented in same manner as network within.
1362          */
1363         dbus_message_iter_recurse(iter, &variant_iter);
1364         return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
1365 }
1366
1367
1368 /**
1369  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1370  *      persistent_group
1371  * @message: Pointer to incoming dbus message
1372  * @wpa_s: wpa_supplicant structure for a network interface
1373  * Returns: A dbus message containing the object path of the new
1374  * persistent group
1375  *
1376  * Handler function for "AddPersistentGroup" method call of a P2P Device
1377  * interface.
1378  */
1379 DBusMessage * wpas_dbus_handler_add_persistent_group(
1380         DBusMessage *message, struct wpa_supplicant *wpa_s)
1381 {
1382         DBusMessage *reply = NULL;
1383         DBusMessageIter iter;
1384         struct wpa_ssid *ssid = NULL;
1385         char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1386         DBusError error;
1387
1388         dbus_message_iter_init(message, &iter);
1389
1390         ssid = wpa_config_add_network(wpa_s->conf);
1391         if (ssid == NULL) {
1392                 wpa_printf(MSG_ERROR, "dbus: %s: "
1393                            "Cannot add new persistent group", __func__);
1394                 reply = wpas_dbus_error_unknown_error(
1395                         message,
1396                         "wpa_supplicant could not add "
1397                         "a persistent group on this interface.");
1398                 goto err;
1399         }
1400
1401         /* Mark the ssid as being a persistent group before the notification */
1402         ssid->disabled = 2;
1403         ssid->p2p_persistent_group = 1;
1404         wpas_notify_persistent_group_added(wpa_s, ssid);
1405
1406         wpa_config_set_network_defaults(ssid);
1407
1408         dbus_error_init(&error);
1409         if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1410                 wpa_printf(MSG_DEBUG, "dbus: %s: "
1411                            "Control interface could not set persistent group "
1412                            "properties", __func__);
1413                 reply = wpas_dbus_reply_new_from_error(message, &error,
1414                                                        DBUS_ERROR_INVALID_ARGS,
1415                                                        "Failed to set network "
1416                                                        "properties");
1417                 dbus_error_free(&error);
1418                 goto err;
1419         }
1420
1421         /* Construct the object path for this network. */
1422         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1423                     "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1424                     wpa_s->dbus_new_path, ssid->id);
1425
1426         reply = dbus_message_new_method_return(message);
1427         if (reply == NULL) {
1428                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1429                                                NULL);
1430                 goto err;
1431         }
1432         if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1433                                       DBUS_TYPE_INVALID)) {
1434                 dbus_message_unref(reply);
1435                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1436                                                NULL);
1437                 goto err;
1438         }
1439
1440         return reply;
1441
1442 err:
1443         if (ssid) {
1444                 wpas_notify_persistent_group_removed(wpa_s, ssid);
1445                 wpa_config_remove_network(wpa_s->conf, ssid->id);
1446         }
1447         return reply;
1448 }
1449
1450
1451 /**
1452  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1453  *      group
1454  * @message: Pointer to incoming dbus message
1455  * @wpa_s: wpa_supplicant structure for a network interface
1456  * Returns: NULL on success or dbus error on failure
1457  *
1458  * Handler function for "RemovePersistentGroup" method call of a P2P Device
1459  * interface.
1460  */
1461 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1462         DBusMessage *message, struct wpa_supplicant *wpa_s)
1463 {
1464         DBusMessage *reply = NULL;
1465         const char *op;
1466         char *iface = NULL, *persistent_group_id = NULL;
1467         int id;
1468         struct wpa_ssid *ssid;
1469
1470         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1471                               DBUS_TYPE_INVALID);
1472
1473         /*
1474          * Extract the network ID and ensure the network is actually a child of
1475          * this interface.
1476          */
1477         iface = wpas_dbus_new_decompose_object_path(op, 1,
1478                                                     &persistent_group_id,
1479                                                     NULL);
1480         if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1481                 reply = wpas_dbus_error_invalid_args(message, op);
1482                 goto out;
1483         }
1484
1485         id = strtoul(persistent_group_id, NULL, 10);
1486         if (errno == EINVAL) {
1487                 reply = wpas_dbus_error_invalid_args(message, op);
1488                 goto out;
1489         }
1490
1491         ssid = wpa_config_get_network(wpa_s->conf, id);
1492         if (ssid == NULL) {
1493                 reply = wpas_dbus_error_persistent_group_unknown(message);
1494                 goto out;
1495         }
1496
1497         wpas_notify_persistent_group_removed(wpa_s, ssid);
1498
1499         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1500                 wpa_printf(MSG_ERROR, "dbus: %s: "
1501                            "error occurred when removing persistent group %d",
1502                            __func__, id);
1503                 reply = wpas_dbus_error_unknown_error(
1504                         message,
1505                         "error removing the specified persistent group on "
1506                         "this interface.");
1507                 goto out;
1508         }
1509
1510 out:
1511         os_free(iface);
1512         os_free(persistent_group_id);
1513         return reply;
1514 }
1515
1516
1517 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1518                                     struct wpa_ssid *ssid)
1519 {
1520         wpas_notify_persistent_group_removed(wpa_s, ssid);
1521
1522         if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1523                 wpa_printf(MSG_ERROR, "dbus: %s: "
1524                            "error occurred when removing persistent group %d",
1525                            __func__, ssid->id);
1526                 return;
1527         }
1528 }
1529
1530
1531 /**
1532  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1533  * persistent groups
1534  * @message: Pointer to incoming dbus message
1535  * @wpa_s: wpa_supplicant structure for a network interface
1536  * Returns: NULL on success or dbus error on failure
1537  *
1538  * Handler function for "RemoveAllPersistentGroups" method call of a
1539  * P2P Device interface.
1540  */
1541 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1542         DBusMessage *message, struct wpa_supplicant *wpa_s)
1543 {
1544         struct wpa_ssid *ssid, *next;
1545         struct wpa_config *config;
1546
1547         config = wpa_s->conf;
1548         ssid = config->ssid;
1549         while (ssid) {
1550                 next = ssid->next;
1551                 if (network_is_persistent_group(ssid))
1552                         remove_persistent_group(wpa_s, ssid);
1553                 ssid = next;
1554         }
1555         return NULL;
1556 }
1557
1558
1559 /*
1560  * Group object properties accessor methods
1561  */
1562
1563 dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
1564                                                DBusError *error,
1565                                                void *user_data)
1566 {
1567         struct wpa_supplicant *wpa_s = user_data;
1568         struct wpa_ssid *ssid;
1569         unsigned int num_members;
1570         char **paths;
1571         unsigned int i;
1572         void *next = NULL;
1573         const u8 *addr;
1574         dbus_bool_t success = FALSE;
1575
1576         /* Ensure we are a GO */
1577         if (wpa_s->wpa_state != WPA_COMPLETED)
1578                 return FALSE;
1579
1580         ssid = wpa_s->conf->ssid;
1581         /* At present WPAS P2P_GO mode only applicable for p2p_go */
1582         if (ssid->mode != WPAS_MODE_P2P_GO &&
1583             ssid->mode != WPAS_MODE_AP &&
1584             ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1585                 return FALSE;
1586
1587         num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1588
1589         paths = os_zalloc(num_members * sizeof(char *));
1590         if (!paths)
1591                 goto out_of_memory;
1592
1593         i = 0;
1594         while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1595                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1596                 if (!paths[i])
1597                         goto out_of_memory;
1598                 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1599                             "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1600                             "/" COMPACT_MACSTR,
1601                             wpa_s->dbus_groupobj_path, MAC2STR(addr));
1602                 i++;
1603         }
1604
1605         success = wpas_dbus_simple_array_property_getter(iter,
1606                                                          DBUS_TYPE_OBJECT_PATH,
1607                                                          paths, num_members,
1608                                                          error);
1609
1610         for (i = 0; i < num_members; i++)
1611                 os_free(paths[i]);
1612         os_free(paths);
1613         return success;
1614
1615 out_of_memory:
1616         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1617         if (paths) {
1618                 for (i = 0; i < num_members; i++)
1619                         os_free(paths[i]);
1620                 os_free(paths);
1621         }
1622         return FALSE;
1623 }
1624
1625
1626 dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
1627                                                   DBusError *error,
1628                                                   void *user_data)
1629 {
1630         struct wpa_supplicant *wpa_s = user_data;
1631         DBusMessageIter variant_iter, dict_iter;
1632         struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1633         const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1634         int num_vendor_ext = 0;
1635         int i;
1636
1637         if (!hapd) {
1638                 dbus_set_error_const(error, DBUS_ERROR_FAILED,
1639                                      "internal error");
1640                 return FALSE;
1641         }
1642
1643         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1644                                               "a{sv}", &variant_iter) ||
1645             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1646                 goto err_no_mem;
1647
1648         /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1649         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1650                 if (hapd->conf->wps_vendor_ext[i] == NULL)
1651                         continue;
1652                 vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1653         }
1654
1655         if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1656                                                "WPSVendorExtensions",
1657                                                vendor_ext, num_vendor_ext))
1658                 goto err_no_mem;
1659
1660         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1661             !dbus_message_iter_close_container(iter, &variant_iter))
1662                 goto err_no_mem;
1663
1664         return TRUE;
1665
1666 err_no_mem:
1667         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1668         return FALSE;
1669 }
1670
1671
1672 dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
1673                                                   DBusError *error,
1674                                                   void *user_data)
1675 {
1676         struct wpa_supplicant *wpa_s = user_data;
1677         DBusMessageIter variant_iter, iter_dict;
1678         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1679         unsigned int i;
1680         struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1681
1682         if (!hapd) {
1683                 dbus_set_error_const(error, DBUS_ERROR_FAILED,
1684                                      "internal error");
1685                 return FALSE;
1686         }
1687
1688         dbus_message_iter_recurse(iter, &variant_iter);
1689         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
1690                 return FALSE;
1691
1692         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1693                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1694                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1695                                              "invalid message format");
1696                         return FALSE;
1697                 }
1698
1699                 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1700                         if (entry.type != DBUS_TYPE_ARRAY ||
1701                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1702                             entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1703                                 goto error;
1704
1705                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1706                                 if (i < entry.array_len) {
1707                                         hapd->conf->wps_vendor_ext[i] =
1708                                                 entry.binarray_value[i];
1709                                         entry.binarray_value[i] = NULL;
1710                                 } else
1711                                         hapd->conf->wps_vendor_ext[i] = NULL;
1712                         }
1713
1714                         hostapd_update_wps(hapd);
1715                 } else
1716                         goto error;
1717
1718                 wpa_dbus_dict_entry_clear(&entry);
1719         }
1720
1721         return TRUE;
1722
1723 error:
1724         wpa_dbus_dict_entry_clear(&entry);
1725         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1726                              "invalid message format");
1727         return FALSE;
1728 }
1729
1730
1731 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
1732                                                 struct wpa_supplicant *wpa_s)
1733 {
1734         DBusMessageIter iter_dict;
1735         DBusMessage *reply = NULL;
1736         DBusMessageIter iter;
1737         struct wpa_dbus_dict_entry entry;
1738         int upnp = 0;
1739         int bonjour = 0;
1740         char *service = NULL;
1741         struct wpabuf *query = NULL;
1742         struct wpabuf *resp = NULL;
1743         u8 version = 0;
1744
1745         dbus_message_iter_init(message, &iter);
1746
1747         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1748                 goto error;
1749
1750         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1751                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1752                         goto error;
1753
1754                 if (!os_strcmp(entry.key, "service_type") &&
1755                     (entry.type == DBUS_TYPE_STRING)) {
1756                         if (!os_strcmp(entry.str_value, "upnp"))
1757                                 upnp = 1;
1758                         else if (!os_strcmp(entry.str_value, "bonjour"))
1759                                 bonjour = 1;
1760                         else
1761                                 goto error_clear;
1762                         wpa_dbus_dict_entry_clear(&entry);
1763                 }
1764         }
1765
1766         if (upnp == 1) {
1767                 while (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, "version") &&
1772                             entry.type == DBUS_TYPE_INT32)
1773                                 version = entry.uint32_value;
1774                         else if (!os_strcmp(entry.key, "service") &&
1775                                  entry.type == DBUS_TYPE_STRING)
1776                                 service = os_strdup(entry.str_value);
1777                         wpa_dbus_dict_entry_clear(&entry);
1778                 }
1779                 if (version <= 0 || service == NULL)
1780                         goto error;
1781
1782                 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1783                         goto error;
1784
1785                 os_free(service);
1786         } else if (bonjour == 1) {
1787                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1788                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1789                                 goto error;
1790
1791                         if (!os_strcmp(entry.key, "query")) {
1792                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1793                                     (entry.array_type != DBUS_TYPE_BYTE))
1794                                         goto error_clear;
1795                                 query = wpabuf_alloc_copy(
1796                                         entry.bytearray_value,
1797                                         entry.array_len);
1798                         } else if (!os_strcmp(entry.key, "response")) {
1799                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1800                                     (entry.array_type != DBUS_TYPE_BYTE))
1801                                         goto error_clear;
1802                                 resp = wpabuf_alloc_copy(entry.bytearray_value,
1803                                                          entry.array_len);
1804                         }
1805
1806                         wpa_dbus_dict_entry_clear(&entry);
1807                 }
1808
1809                 if (query == NULL || resp == NULL)
1810                         goto error;
1811
1812                 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1813                         wpabuf_free(query);
1814                         wpabuf_free(resp);
1815                         goto error;
1816                 }
1817         } else
1818                 goto error;
1819
1820         return reply;
1821 error_clear:
1822         wpa_dbus_dict_entry_clear(&entry);
1823 error:
1824         return wpas_dbus_error_invalid_args(message, NULL);
1825 }
1826
1827
1828 DBusMessage * wpas_dbus_handler_p2p_delete_service(
1829         DBusMessage *message, struct wpa_supplicant *wpa_s)
1830 {
1831         DBusMessageIter iter_dict;
1832         DBusMessage *reply = NULL;
1833         DBusMessageIter iter;
1834         struct wpa_dbus_dict_entry entry;
1835         int upnp = 0;
1836         int bonjour = 0;
1837         int ret = 0;
1838         char *service = NULL;
1839         struct wpabuf *query = NULL;
1840         u8 version = 0;
1841
1842         dbus_message_iter_init(message, &iter);
1843
1844         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1845                 goto error;
1846
1847         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1848                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1849                         goto error;
1850
1851                 if (!os_strcmp(entry.key, "service_type") &&
1852                     (entry.type == DBUS_TYPE_STRING)) {
1853                         if (!os_strcmp(entry.str_value, "upnp"))
1854                                 upnp = 1;
1855                         else if (!os_strcmp(entry.str_value, "bonjour"))
1856                                 bonjour = 1;
1857                         else
1858                                 goto error_clear;
1859                         wpa_dbus_dict_entry_clear(&entry);
1860                 }
1861         }
1862         if (upnp == 1) {
1863                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1864                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1865                                 goto error;
1866                         if (!os_strcmp(entry.key, "version") &&
1867                             entry.type == DBUS_TYPE_INT32)
1868                                 version = entry.uint32_value;
1869                         else if (!os_strcmp(entry.key, "service") &&
1870                                  entry.type == DBUS_TYPE_STRING)
1871                                 service = os_strdup(entry.str_value);
1872                         else
1873                                 goto error_clear;
1874
1875                         wpa_dbus_dict_entry_clear(&entry);
1876                 }
1877
1878                 if (version <= 0 || service == NULL)
1879                         goto error;
1880
1881                 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1882                 os_free(service);
1883                 if (ret != 0)
1884                         goto error;
1885         } else if (bonjour == 1) {
1886                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1887                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1888                                 goto error;
1889
1890                         if (!os_strcmp(entry.key, "query")) {
1891                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1892                                     (entry.array_type != DBUS_TYPE_BYTE))
1893                                         goto error_clear;
1894                                 query = wpabuf_alloc_copy(
1895                                         entry.bytearray_value,
1896                                         entry.array_len);
1897                         } else
1898                                 goto error_clear;
1899
1900                         wpa_dbus_dict_entry_clear(&entry);
1901                 }
1902
1903                 if (query == NULL)
1904                         goto error;
1905
1906                 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1907                 if (ret != 0)
1908                         goto error;
1909                 wpabuf_free(query);
1910         } else
1911                 goto error;
1912
1913         return reply;
1914 error_clear:
1915         wpa_dbus_dict_entry_clear(&entry);
1916 error:
1917         return wpas_dbus_error_invalid_args(message, NULL);
1918 }
1919
1920
1921 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
1922                                                   struct wpa_supplicant *wpa_s)
1923 {
1924         wpas_p2p_service_flush(wpa_s);
1925         return NULL;
1926 }
1927
1928
1929 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
1930         DBusMessage *message, struct wpa_supplicant *wpa_s)
1931 {
1932         DBusMessageIter iter_dict;
1933         DBusMessage *reply = NULL;
1934         DBusMessageIter iter;
1935         struct wpa_dbus_dict_entry entry;
1936         int upnp = 0;
1937         char *service = NULL;
1938         char *peer_object_path = NULL;
1939         struct wpabuf *tlv = NULL;
1940         u8 version = 0;
1941         u64 ref = 0;
1942         u8 addr[ETH_ALEN];
1943
1944         dbus_message_iter_init(message, &iter);
1945
1946         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1947                 goto error;
1948
1949         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1950                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1951                         goto error;
1952                 if (!os_strcmp(entry.key, "peer_object") &&
1953                     entry.type == DBUS_TYPE_OBJECT_PATH) {
1954                         peer_object_path = os_strdup(entry.str_value);
1955                 } else if (!os_strcmp(entry.key, "service_type") &&
1956                            entry.type == DBUS_TYPE_STRING) {
1957                         if (!os_strcmp(entry.str_value, "upnp"))
1958                                 upnp = 1;
1959                         else
1960                                 goto error_clear;
1961                 } else if (!os_strcmp(entry.key, "version") &&
1962                            entry.type == DBUS_TYPE_INT32) {
1963                         version = entry.uint32_value;
1964                 } else if (!os_strcmp(entry.key, "service") &&
1965                            entry.type == DBUS_TYPE_STRING) {
1966                         service = os_strdup(entry.str_value);
1967                 } else if (!os_strcmp(entry.key, "tlv")) {
1968                         if (entry.type != DBUS_TYPE_ARRAY ||
1969                             entry.array_type != DBUS_TYPE_BYTE)
1970                                 goto error_clear;
1971                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
1972                                                 entry.array_len);
1973                 } else
1974                         goto error_clear;
1975
1976                 wpa_dbus_dict_entry_clear(&entry);
1977         }
1978
1979         if (!peer_object_path ||
1980             (parse_peer_object_path(peer_object_path, addr) < 0) ||
1981             (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
1982                 goto error;
1983
1984         if (upnp == 1) {
1985                 if (version <= 0 || service == NULL)
1986                         goto error;
1987
1988                 ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, addr,
1989                                                                version,
1990                                                                service);
1991         } else {
1992                 if (tlv == NULL)
1993                         goto error;
1994                 ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
1995                 wpabuf_free(tlv);
1996         }
1997
1998         if (ref != 0) {
1999                 reply = dbus_message_new_method_return(message);
2000                 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2001                                          &ref, DBUS_TYPE_INVALID);
2002         } else {
2003                 reply = wpas_dbus_error_unknown_error(
2004                         message, "Unable to send SD request");
2005         }
2006 out:
2007         os_free(service);
2008         os_free(peer_object_path);
2009         return reply;
2010 error_clear:
2011         wpa_dbus_dict_entry_clear(&entry);
2012 error:
2013         if (tlv)
2014                 wpabuf_free(tlv);
2015         reply = wpas_dbus_error_invalid_args(message, NULL);
2016         goto out;
2017 }
2018
2019
2020 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2021         DBusMessage *message, struct wpa_supplicant *wpa_s)
2022 {
2023         DBusMessageIter iter_dict;
2024         DBusMessage *reply = NULL;
2025         DBusMessageIter iter;
2026         struct wpa_dbus_dict_entry entry;
2027         char *peer_object_path = NULL;
2028         struct wpabuf *tlv = NULL;
2029         int freq = 0;
2030         int dlg_tok = 0;
2031         u8 addr[ETH_ALEN];
2032
2033         dbus_message_iter_init(message, &iter);
2034
2035         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2036                 goto error;
2037
2038         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2039                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2040                         goto error;
2041
2042                 if (!os_strcmp(entry.key, "peer_object") &&
2043                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2044                         peer_object_path = os_strdup(entry.str_value);
2045                 } else if (!os_strcmp(entry.key, "frequency") &&
2046                            entry.type == DBUS_TYPE_INT32) {
2047                         freq = entry.uint32_value;
2048                 } else if (!os_strcmp(entry.key, "dialog_token") &&
2049                            entry.type == DBUS_TYPE_UINT32) {
2050                         dlg_tok = entry.uint32_value;
2051                 } else if (!os_strcmp(entry.key, "tlvs")) {
2052                         if (entry.type != DBUS_TYPE_ARRAY ||
2053                             entry.array_type != DBUS_TYPE_BYTE)
2054                                 goto error_clear;
2055                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2056                                                 entry.array_len);
2057                 } else
2058                         goto error_clear;
2059
2060                 wpa_dbus_dict_entry_clear(&entry);
2061         }
2062         if (!peer_object_path ||
2063             (parse_peer_object_path(peer_object_path, addr) < 0) ||
2064             (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2065                 goto error;
2066
2067         if (tlv == NULL)
2068                 goto error;
2069
2070         wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2071         wpabuf_free(tlv);
2072 out:
2073         os_free(peer_object_path);
2074         return reply;
2075 error_clear:
2076         wpa_dbus_dict_entry_clear(&entry);
2077 error:
2078         reply = wpas_dbus_error_invalid_args(message, NULL);
2079         goto out;
2080 }
2081
2082
2083 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2084         DBusMessage *message, struct wpa_supplicant *wpa_s)
2085 {
2086         DBusMessageIter iter;
2087         u64 req = 0;
2088
2089         dbus_message_iter_init(message, &iter);
2090         dbus_message_iter_get_basic(&iter, &req);
2091
2092         if (req == 0)
2093                 goto error;
2094
2095         if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long) req))
2096                 goto error;
2097
2098         return NULL;
2099 error:
2100         return wpas_dbus_error_invalid_args(message, NULL);
2101 }
2102
2103
2104 DBusMessage * wpas_dbus_handler_p2p_service_update(
2105         DBusMessage *message, struct wpa_supplicant *wpa_s)
2106 {
2107         wpas_p2p_sd_service_update(wpa_s);
2108         return NULL;
2109 }
2110
2111
2112 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2113         DBusMessage *message, struct wpa_supplicant *wpa_s)
2114 {
2115         DBusMessageIter iter;
2116         int ext = 0;
2117
2118         dbus_message_iter_init(message, &iter);
2119         dbus_message_iter_get_basic(&iter, &ext);
2120
2121         wpa_s->p2p_sd_over_ctrl_iface = ext;
2122
2123         return NULL;
2124
2125 }