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