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