7c59bed7cc30cb82e52504390134d6e21627aa3f
[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 || net_id_str == 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 || net_id_str == 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             !wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
818                                          wpa_s->conf->p2p_go_intent) ||
819             !wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
820                                        wpa_s->conf->persistent_reconnect) ||
821             !wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
822                                          wpa_s->conf->p2p_listen_reg_class) ||
823             !wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
824                                          wpa_s->conf->p2p_listen_channel) ||
825             !wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
826                                          wpa_s->conf->p2p_oper_reg_class) ||
827             !wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
828                                          wpa_s->conf->p2p_oper_channel) ||
829             (wpa_s->conf->p2p_ssid_postfix &&
830              !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
831                                           wpa_s->conf->p2p_ssid_postfix)) ||
832             !wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
833                                        wpa_s->conf->p2p_intra_bss) ||
834             !wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
835                                          wpa_s->conf->p2p_group_idle) ||
836             !wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
837                                          wpa_s->conf->disassoc_low_ack) ||
838             !wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
839                                        wpa_s->conf->p2p_no_group_iface) ||
840             !wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
841                                          wpa_s->conf->p2p_search_delay) ||
842             !wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
843             !dbus_message_iter_close_container(iter, &variant_iter))
844                 goto err_no_mem;
845
846         return TRUE;
847
848 err_no_mem:
849         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
850         return FALSE;
851 }
852
853
854 dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter,
855                                                DBusError *error,
856                                                void *user_data)
857 {
858         struct wpa_supplicant *wpa_s = user_data;
859         DBusMessageIter variant_iter, iter_dict;
860         struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
861         unsigned int i;
862
863         if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
864                 return FALSE;
865
866         if (wpa_s->p2p_dev)
867                 wpa_s = wpa_s->p2p_dev;
868
869         dbus_message_iter_recurse(iter, &variant_iter);
870         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
871                 return FALSE;
872
873         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
874                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
875                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
876                                              "invalid message format");
877                         return FALSE;
878                 }
879
880                 if (os_strcmp(entry.key, "DeviceName") == 0) {
881                         char *devname;
882
883                         if (entry.type != DBUS_TYPE_STRING)
884                                 goto error;
885
886                         devname = os_strdup(entry.str_value);
887                         if (devname == NULL)
888                                 goto err_no_mem_clear;
889
890                         os_free(wpa_s->conf->device_name);
891                         wpa_s->conf->device_name = devname;
892
893                         wpa_s->conf->changed_parameters |=
894                                 CFG_CHANGED_DEVICE_NAME;
895                 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
896                         if (entry.type != DBUS_TYPE_ARRAY ||
897                             entry.array_type != DBUS_TYPE_BYTE ||
898                             entry.array_len != WPS_DEV_TYPE_LEN)
899                                 goto error;
900
901                         os_memcpy(wpa_s->conf->device_type,
902                                   entry.bytearray_value,
903                                   WPS_DEV_TYPE_LEN);
904                         wpa_s->conf->changed_parameters |=
905                                 CFG_CHANGED_DEVICE_TYPE;
906                 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
907                         if (entry.type != DBUS_TYPE_ARRAY ||
908                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
909                             entry.array_len > MAX_SEC_DEVICE_TYPES)
910                                 goto error;
911
912                         for (i = 0; i < entry.array_len; i++)
913                                 if (wpabuf_len(entry.binarray_value[i]) !=
914                                     WPS_DEV_TYPE_LEN)
915                                         goto err_no_mem_clear;
916                         for (i = 0; i < entry.array_len; i++)
917                                 os_memcpy(wpa_s->conf->sec_device_type[i],
918                                           wpabuf_head(entry.binarray_value[i]),
919                                           WPS_DEV_TYPE_LEN);
920                         wpa_s->conf->num_sec_device_types = entry.array_len;
921                         wpa_s->conf->changed_parameters |=
922                                         CFG_CHANGED_SEC_DEVICE_TYPE;
923                 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
924                         if ((entry.type != DBUS_TYPE_ARRAY) ||
925                             (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
926                             (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
927                                 goto error;
928
929                         wpa_s->conf->changed_parameters |=
930                                 CFG_CHANGED_VENDOR_EXTENSION;
931
932                         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
933                                 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
934                                 if (i < entry.array_len) {
935                                         wpa_s->conf->wps_vendor_ext[i] =
936                                                 entry.binarray_value[i];
937                                         entry.binarray_value[i] = NULL;
938                                 } else
939                                         wpa_s->conf->wps_vendor_ext[i] = NULL;
940                         }
941                 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
942                            (entry.type == DBUS_TYPE_UINT32) &&
943                            (entry.uint32_value <= 15))
944                         wpa_s->conf->p2p_go_intent = entry.uint32_value;
945                 else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
946                          (entry.type == DBUS_TYPE_BOOLEAN))
947                         wpa_s->conf->persistent_reconnect = entry.bool_value;
948                 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
949                          (entry.type == DBUS_TYPE_UINT32)) {
950                         wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
951                         wpa_s->conf->changed_parameters |=
952                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
953                 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
954                            (entry.type == DBUS_TYPE_UINT32)) {
955                         wpa_s->conf->p2p_listen_channel = entry.uint32_value;
956                         wpa_s->conf->changed_parameters |=
957                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
958                 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
959                            (entry.type == DBUS_TYPE_UINT32)) {
960                         wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
961                         wpa_s->conf->changed_parameters |=
962                                 CFG_CHANGED_P2P_OPER_CHANNEL;
963                 } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
964                            (entry.type == DBUS_TYPE_UINT32)) {
965                         wpa_s->conf->p2p_oper_channel = entry.uint32_value;
966                         wpa_s->conf->changed_parameters |=
967                                 CFG_CHANGED_P2P_OPER_CHANNEL;
968                 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
969                         char *postfix;
970
971                         if (entry.type != DBUS_TYPE_STRING)
972                                 goto error;
973
974                         postfix = os_strdup(entry.str_value);
975                         if (!postfix)
976                                 goto err_no_mem_clear;
977
978                         os_free(wpa_s->conf->p2p_ssid_postfix);
979                         wpa_s->conf->p2p_ssid_postfix = postfix;
980
981                         wpa_s->conf->changed_parameters |=
982                                         CFG_CHANGED_P2P_SSID_POSTFIX;
983                 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
984                            (entry.type == DBUS_TYPE_BOOLEAN)) {
985                         wpa_s->conf->p2p_intra_bss = entry.bool_value;
986                         wpa_s->conf->changed_parameters |=
987                                 CFG_CHANGED_P2P_INTRA_BSS;
988                 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
989                            (entry.type == DBUS_TYPE_UINT32))
990                         wpa_s->conf->p2p_group_idle = entry.uint32_value;
991                 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
992                          entry.type == DBUS_TYPE_UINT32)
993                         wpa_s->conf->disassoc_low_ack = entry.uint32_value;
994                 else if (os_strcmp(entry.key, "NoGroupIface") == 0 &&
995                          entry.type == DBUS_TYPE_BOOLEAN)
996                         wpa_s->conf->p2p_no_group_iface = entry.bool_value;
997                 else if (os_strcmp(entry.key, "p2p_search_delay") == 0 &&
998                          entry.type == DBUS_TYPE_UINT32)
999                         wpa_s->conf->p2p_search_delay = entry.uint32_value;
1000                 else
1001                         goto error;
1002
1003                 wpa_dbus_dict_entry_clear(&entry);
1004         }
1005
1006         if (wpa_s->conf->changed_parameters) {
1007                 /* Some changed parameters requires to update config*/
1008                 wpa_supplicant_update_config(wpa_s);
1009         }
1010
1011         return TRUE;
1012
1013  error:
1014         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1015                              "invalid message format");
1016         wpa_dbus_dict_entry_clear(&entry);
1017         return FALSE;
1018
1019  err_no_mem_clear:
1020         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1021         wpa_dbus_dict_entry_clear(&entry);
1022         return FALSE;
1023 }
1024
1025
1026 dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
1027                                        void *user_data)
1028 {
1029         struct wpa_supplicant *wpa_s = user_data;
1030         struct p2p_data *p2p = wpa_s->global->p2p;
1031         int next = 0, i = 0;
1032         int num = 0, out_of_mem = 0;
1033         const u8 *addr;
1034         const struct p2p_peer_info *peer_info = NULL;
1035         dbus_bool_t success = FALSE;
1036
1037         struct dl_list peer_objpath_list;
1038         struct peer_objpath_node {
1039                 struct dl_list list;
1040                 char path[WPAS_DBUS_OBJECT_PATH_MAX];
1041         } *node, *tmp;
1042
1043         char **peer_obj_paths = NULL;
1044
1045         if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
1046                 return FALSE;
1047
1048         dl_list_init(&peer_objpath_list);
1049
1050         /* Get the first peer info */
1051         peer_info = p2p_get_peer_found(p2p, NULL, next);
1052
1053         /* Get next and accumulate them */
1054         next = 1;
1055         while (peer_info != NULL) {
1056                 node = os_zalloc(sizeof(struct peer_objpath_node));
1057                 if (!node) {
1058                         out_of_mem = 1;
1059                         goto error;
1060                 }
1061
1062                 addr = peer_info->p2p_device_addr;
1063                 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
1064                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1065                             "/" COMPACT_MACSTR,
1066                             wpa_s->dbus_new_path, MAC2STR(addr));
1067                 dl_list_add_tail(&peer_objpath_list, &node->list);
1068                 num++;
1069
1070                 peer_info = p2p_get_peer_found(p2p, addr, next);
1071         }
1072
1073         /*
1074          * Now construct the peer object paths in a form suitable for
1075          * array_property_getter helper below.
1076          */
1077         peer_obj_paths = os_calloc(num, sizeof(char *));
1078
1079         if (!peer_obj_paths) {
1080                 out_of_mem = 1;
1081                 goto error;
1082         }
1083
1084         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1085                               struct peer_objpath_node, list)
1086                 peer_obj_paths[i++] = node->path;
1087
1088         success = wpas_dbus_simple_array_property_getter(iter,
1089                                                          DBUS_TYPE_OBJECT_PATH,
1090                                                          peer_obj_paths, num,
1091                                                          error);
1092
1093 error:
1094         if (peer_obj_paths)
1095                 os_free(peer_obj_paths);
1096
1097         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1098                               struct peer_objpath_node, list) {
1099                 dl_list_del(&node->list);
1100                 os_free(node);
1101         }
1102         if (out_of_mem)
1103                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1104
1105         return success;
1106 }
1107
1108
1109 enum wpas_p2p_role {
1110         WPAS_P2P_ROLE_DEVICE,
1111         WPAS_P2P_ROLE_GO,
1112         WPAS_P2P_ROLE_CLIENT,
1113 };
1114
1115 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1116 {
1117         struct wpa_ssid *ssid = wpa_s->current_ssid;
1118
1119         if (!ssid)
1120                 return WPAS_P2P_ROLE_DEVICE;
1121         if (wpa_s->wpa_state != WPA_COMPLETED)
1122                 return WPAS_P2P_ROLE_DEVICE;
1123
1124         switch (ssid->mode) {
1125         case WPAS_MODE_P2P_GO:
1126         case WPAS_MODE_P2P_GROUP_FORMATION:
1127                 return WPAS_P2P_ROLE_GO;
1128         case WPAS_MODE_INFRA:
1129                 if (ssid->p2p_group)
1130                         return WPAS_P2P_ROLE_CLIENT;
1131                 return WPAS_P2P_ROLE_DEVICE;
1132         default:
1133                 return WPAS_P2P_ROLE_DEVICE;
1134         }
1135 }
1136
1137
1138 dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
1139                                       void *user_data)
1140 {
1141         struct wpa_supplicant *wpa_s = user_data;
1142         char *str;
1143
1144         switch (wpas_get_p2p_role(wpa_s)) {
1145         case WPAS_P2P_ROLE_GO:
1146                 str = "GO";
1147                 break;
1148         case WPAS_P2P_ROLE_CLIENT:
1149                 str = "client";
1150                 break;
1151         default:
1152                 str = "device";
1153                 break;
1154         }
1155
1156         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
1157                                                 error);
1158 }
1159
1160
1161 dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
1162                                        void *user_data)
1163 {
1164         struct wpa_supplicant *wpa_s = user_data;
1165         char path_buf[WPAS_DBUS_OBJECT_PATH_MAX];
1166         char *dbus_groupobj_path = path_buf;
1167
1168         if (wpa_s->dbus_groupobj_path == NULL)
1169                 os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1170                             "/");
1171         else
1172                 os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1173                             "%s", wpa_s->dbus_groupobj_path);
1174
1175         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1176                                                 &dbus_groupobj_path, error);
1177 }
1178
1179
1180 dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
1181                                         DBusError *error, void *user_data)
1182 {
1183         struct wpa_supplicant *wpa_s = user_data;
1184         char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1185
1186         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1187                 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
1188         else
1189                 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1190                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
1191                             COMPACT_MACSTR,
1192                             wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1193
1194         path = go_peer_obj_path;
1195         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1196                                                 &path, error);
1197 }
1198
1199
1200 /*
1201  * Peer object properties accessor methods
1202  */
1203
1204 dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
1205                                                   DBusError *error,
1206                                                   void *user_data)
1207 {
1208         struct peer_handler_args *peer_args = user_data;
1209         const struct p2p_peer_info *info;
1210         char *tmp;
1211
1212         if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1213                 return FALSE;
1214
1215         /* get the peer info */
1216         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1217                                   peer_args->p2p_device_addr, 0);
1218         if (info == NULL) {
1219                 dbus_set_error(error, DBUS_ERROR_FAILED,
1220                                "failed to find peer");
1221                 return FALSE;
1222         }
1223
1224         tmp = os_strdup(info->device_name);
1225         if (!tmp) {
1226                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1227                 return FALSE;
1228         }
1229
1230         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp,
1231                                               error)) {
1232                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1233                 os_free(tmp);
1234                 return FALSE;
1235         }
1236
1237         os_free(tmp);
1238         return TRUE;
1239 }
1240
1241
1242 dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
1243         DBusMessageIter *iter, DBusError *error, void *user_data)
1244 {
1245         struct peer_handler_args *peer_args = user_data;
1246         const struct p2p_peer_info *info;
1247
1248         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1249                                   peer_args->p2p_device_addr, 0);
1250         if (info == NULL) {
1251                 dbus_set_error(error, DBUS_ERROR_FAILED,
1252                                "failed to find peer");
1253                 return FALSE;
1254         }
1255
1256         if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
1257                                                     (char *)
1258                                                     info->pri_dev_type,
1259                                                     WPS_DEV_TYPE_LEN, error)) {
1260                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1261                 return FALSE;
1262         }
1263
1264         return TRUE;
1265 }
1266
1267
1268 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
1269                                                     DBusError *error,
1270                                                     void *user_data)
1271 {
1272         struct peer_handler_args *peer_args = user_data;
1273         const struct p2p_peer_info *info;
1274
1275         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1276                                   peer_args->p2p_device_addr, 0);
1277         if (info == NULL) {
1278                 dbus_set_error(error, DBUS_ERROR_FAILED,
1279                                "failed to find peer");
1280                 return FALSE;
1281         }
1282
1283         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
1284                                               &info->config_methods, error)) {
1285                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1286                 return FALSE;
1287         }
1288
1289         return TRUE;
1290 }
1291
1292
1293 dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
1294                                             DBusError *error,
1295                                             void *user_data)
1296 {
1297         struct peer_handler_args *peer_args = user_data;
1298         const struct p2p_peer_info *info;
1299
1300         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1301                                   peer_args->p2p_device_addr, 0);
1302         if (info == NULL) {
1303                 dbus_set_error(error, DBUS_ERROR_FAILED,
1304                                "failed to find peer");
1305                 return FALSE;
1306         }
1307
1308         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
1309                                               &info->level, error)) {
1310                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1311                 return FALSE;
1312         }
1313
1314         return TRUE;
1315 }
1316
1317
1318 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
1319                                                         DBusError *error,
1320                                                         void *user_data)
1321 {
1322         struct peer_handler_args *peer_args = user_data;
1323         const struct p2p_peer_info *info;
1324
1325         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1326                                   peer_args->p2p_device_addr, 0);
1327         if (info == NULL) {
1328                 dbus_set_error(error, DBUS_ERROR_FAILED,
1329                                "failed to find peer");
1330                 return FALSE;
1331         }
1332
1333         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
1334                                               &info->dev_capab, error)) {
1335                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1336                 return FALSE;
1337         }
1338
1339         return TRUE;
1340 }
1341
1342
1343 dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
1344                                                        DBusError *error,
1345                                                        void *user_data)
1346 {
1347         struct peer_handler_args *peer_args = user_data;
1348         const struct p2p_peer_info *info;
1349
1350         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1351                                   peer_args->p2p_device_addr, 0);
1352         if (info == NULL) {
1353                 dbus_set_error(error, DBUS_ERROR_FAILED,
1354                                "failed to find peer");
1355                 return FALSE;
1356         }
1357
1358         if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE,
1359                                               &info->group_capab, error)) {
1360                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1361                 return FALSE;
1362         }
1363
1364         return TRUE;
1365 }
1366
1367
1368 dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
1369         DBusMessageIter *iter, DBusError *error, void *user_data)
1370 {
1371         struct peer_handler_args *peer_args = user_data;
1372         const struct p2p_peer_info *info;
1373         DBusMessageIter variant_iter, array_iter;
1374
1375         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1376                                   peer_args->p2p_device_addr, 0);
1377         if (info == NULL) {
1378                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1379                 return FALSE;
1380         }
1381
1382         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1383                                               DBUS_TYPE_ARRAY_AS_STRING
1384                                               DBUS_TYPE_ARRAY_AS_STRING
1385                                               DBUS_TYPE_BYTE_AS_STRING,
1386                                               &variant_iter) ||
1387             !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
1388                                               DBUS_TYPE_ARRAY_AS_STRING
1389                                               DBUS_TYPE_BYTE_AS_STRING,
1390                                               &array_iter)) {
1391                 dbus_set_error(error, DBUS_ERROR_FAILED,
1392                                "%s: failed to construct message 1", __func__);
1393                 return FALSE;
1394         }
1395
1396         if (info->wps_sec_dev_type_list_len) {
1397                 const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
1398                 int num_sec_device_types =
1399                         info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
1400                 int i;
1401                 DBusMessageIter inner_array_iter;
1402
1403                 for (i = 0; i < num_sec_device_types; i++) {
1404                         if (!dbus_message_iter_open_container(
1405                                     &array_iter, DBUS_TYPE_ARRAY,
1406                                     DBUS_TYPE_BYTE_AS_STRING,
1407                                     &inner_array_iter) ||
1408                             !dbus_message_iter_append_fixed_array(
1409                                     &inner_array_iter, DBUS_TYPE_BYTE,
1410                                     &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
1411                             !dbus_message_iter_close_container(
1412                                     &array_iter, &inner_array_iter)) {
1413                                 dbus_set_error(error, DBUS_ERROR_FAILED,
1414                                                "%s: failed to construct message 2 (%d)",
1415                                                __func__, i);
1416                                 return FALSE;
1417                         }
1418
1419                         sec_dev_type_list += WPS_DEV_TYPE_LEN;
1420                 }
1421         }
1422
1423         if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
1424             !dbus_message_iter_close_container(iter, &variant_iter)) {
1425                 dbus_set_error(error, DBUS_ERROR_FAILED,
1426                                "%s: failed to construct message 3", __func__);
1427                 return FALSE;
1428         }
1429
1430         return TRUE;
1431 }
1432
1433
1434 dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
1435                                                        DBusError *error,
1436                                                        void *user_data)
1437 {
1438         struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1439         unsigned int i, num = 0;
1440         struct peer_handler_args *peer_args = user_data;
1441         const struct p2p_peer_info *info;
1442
1443         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1444                                   peer_args->p2p_device_addr, 0);
1445         if (info == NULL) {
1446                 dbus_set_error(error, DBUS_ERROR_FAILED,
1447                                "failed to find peer");
1448                 return FALSE;
1449         }
1450
1451         /* Add WPS vendor extensions attribute */
1452         os_memset(vendor_extension, 0, sizeof(vendor_extension));
1453         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1454                 if (info->wps_vendor_ext[i] == NULL)
1455                         continue;
1456                 vendor_extension[num] = info->wps_vendor_ext[i];
1457                 num++;
1458         }
1459
1460         if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
1461                                                           vendor_extension,
1462                                                           num, error))
1463                 return FALSE;
1464
1465         return TRUE;
1466 }
1467
1468
1469 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
1470                                           DBusError *error, void *user_data)
1471 {
1472         struct peer_handler_args *peer_args = user_data;
1473         const struct p2p_peer_info *info;
1474
1475         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1476                                   peer_args->p2p_device_addr, 0);
1477         if (info == NULL) {
1478                 dbus_set_error(error, DBUS_ERROR_FAILED,
1479                                "failed to find peer");
1480                 return FALSE;
1481         }
1482
1483         if (info->wfd_subelems == NULL)
1484                 return wpas_dbus_simple_array_property_getter(iter,
1485                                                               DBUS_TYPE_BYTE,
1486                                                               NULL, 0, error);
1487
1488         return wpas_dbus_simple_array_property_getter(
1489                 iter, DBUS_TYPE_BYTE, (char *) info->wfd_subelems->buf,
1490                 info->wfd_subelems->used, error);
1491 }
1492
1493
1494 dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
1495                                                      DBusError *error,
1496                                                      void *user_data)
1497 {
1498         struct peer_handler_args *peer_args = user_data;
1499         const struct p2p_peer_info *info;
1500
1501         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1502                                   peer_args->p2p_device_addr, 0);
1503         if (info == NULL) {
1504                 dbus_set_error(error, DBUS_ERROR_FAILED,
1505                                "failed to find peer");
1506                 return FALSE;
1507         }
1508
1509         return wpas_dbus_simple_array_property_getter(
1510                 iter, DBUS_TYPE_BYTE, (char *) info->p2p_device_addr,
1511                 ETH_ALEN, error);
1512 }
1513
1514
1515 struct peer_group_data {
1516         struct wpa_supplicant *wpa_s;
1517         const struct p2p_peer_info *info;
1518         char **paths;
1519         unsigned int nb_paths;
1520         int error;
1521 };
1522
1523
1524 static int match_group_where_peer_is_client(struct p2p_group *group,
1525                                             void *user_data)
1526 {
1527         struct peer_group_data *data = user_data;
1528         const struct p2p_group_config *cfg;
1529         struct wpa_supplicant *wpa_s_go;
1530         char **paths;
1531
1532         if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
1533                 return 1;
1534
1535         cfg = p2p_group_get_config(group);
1536
1537         wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
1538                                          cfg->ssid_len);
1539         if (wpa_s_go == NULL)
1540                 return 1;
1541
1542         paths = os_realloc_array(data->paths, data->nb_paths + 1,
1543                                  sizeof(char *));
1544         if (paths == NULL)
1545                 goto out_of_memory;
1546
1547         data->paths = paths;
1548         data->paths[data->nb_paths] = wpa_s_go->dbus_groupobj_path;
1549         data->nb_paths++;
1550
1551         return 1;
1552
1553 out_of_memory:
1554         data->error = ENOMEM;
1555         return 0;
1556 }
1557
1558
1559 dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
1560                                              DBusError *error,
1561                                              void *user_data)
1562 {
1563         struct peer_handler_args *peer_args = user_data;
1564         const struct p2p_peer_info *info;
1565         struct peer_group_data data;
1566         struct wpa_supplicant *wpa_s, *wpa_s_go;
1567         dbus_bool_t success = FALSE;
1568
1569         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1570                                   peer_args->p2p_device_addr, 0);
1571         if (info == NULL) {
1572                 dbus_set_error(error, DBUS_ERROR_FAILED,
1573                                "failed to find peer");
1574                 return FALSE;
1575         }
1576
1577         os_memset(&data, 0, sizeof(data));
1578
1579         wpa_s = peer_args->wpa_s;
1580         if (wpa_s->p2p_dev)
1581                 wpa_s = wpa_s->p2p_dev;
1582
1583         wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
1584         if (wpa_s_go) {
1585                 data.paths = os_calloc(1, sizeof(char *));
1586                 if (data.paths == NULL)
1587                         goto out_of_memory;
1588                 data.paths[0] = wpa_s_go->dbus_groupobj_path;
1589                 data.nb_paths = 1;
1590         }
1591
1592         data.wpa_s = peer_args->wpa_s;
1593         data.info = info;
1594
1595         p2p_loop_on_all_groups(peer_args->wpa_s->global->p2p,
1596                                match_group_where_peer_is_client, &data);
1597         if (data.error)
1598                 goto out_of_memory;
1599
1600         if (data.paths == NULL) {
1601                 return wpas_dbus_simple_array_property_getter(
1602                         iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
1603         }
1604
1605         success = wpas_dbus_simple_array_property_getter(iter,
1606                                                          DBUS_TYPE_OBJECT_PATH,
1607                                                          data.paths,
1608                                                          data.nb_paths, error);
1609         goto out;
1610
1611 out_of_memory:
1612         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1613 out:
1614         os_free(data.paths);
1615         return success;
1616 }
1617
1618
1619 /**
1620  * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
1621  * @iter: Pointer to incoming dbus message iter
1622  * @error: Location to store error on failure
1623  * @user_data: Function specific data
1624  * Returns: TRUE on success, FALSE on failure
1625  *
1626  * Getter for "PersistentGroups" property.
1627  */
1628 dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
1629                                                DBusError *error,
1630                                                void *user_data)
1631 {
1632         struct wpa_supplicant *wpa_s = user_data;
1633         struct wpa_ssid *ssid;
1634         char **paths;
1635         unsigned int i = 0, num = 0;
1636         dbus_bool_t success = FALSE;
1637
1638         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1639                 if (network_is_persistent_group(ssid))
1640                         num++;
1641
1642         paths = os_calloc(num, sizeof(char *));
1643         if (!paths) {
1644                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1645                 return FALSE;
1646         }
1647
1648         /* Loop through configured networks and append object path of each */
1649         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1650                 if (!network_is_persistent_group(ssid))
1651                         continue;
1652                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1653                 if (paths[i] == NULL) {
1654                         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
1655                                              "no memory");
1656                         goto out;
1657                 }
1658                 /* Construct the object path for this network. */
1659                 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1660                             "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1661                             wpa_s->dbus_new_path, ssid->id);
1662         }
1663
1664         success = wpas_dbus_simple_array_property_getter(iter,
1665                                                          DBUS_TYPE_OBJECT_PATH,
1666                                                          paths, num, error);
1667
1668 out:
1669         while (i)
1670                 os_free(paths[--i]);
1671         os_free(paths);
1672         return success;
1673 }
1674
1675
1676 /**
1677  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1678  *      group
1679  * @iter: Pointer to incoming dbus message iter
1680  * @error: Location to store error on failure
1681  * @user_data: Function specific data
1682  * Returns: TRUE on success, FALSE on failure
1683  *
1684  * Getter for "Properties" property of a persistent group.
1685  */
1686 dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
1687                                                          DBusError *error,
1688                                                          void *user_data)
1689 {
1690         struct network_handler_args *net = user_data;
1691
1692         /* Leveraging the fact that persistent group object is still
1693          * represented in same manner as network within.
1694          */
1695         return wpas_dbus_getter_network_properties(iter, error, net);
1696 }
1697
1698
1699 /**
1700  * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1701  *      group
1702  * @iter: Pointer to incoming dbus message iter
1703  * @error: Location to store error on failure
1704  * @user_data: Function specific data
1705  * Returns: TRUE on success, FALSE on failure
1706  *
1707  * Setter for "Properties" property of a persistent group.
1708  */
1709 dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
1710                                                          DBusError *error,
1711                                                          void *user_data)
1712 {
1713         struct network_handler_args *net = user_data;
1714         struct wpa_ssid *ssid = net->ssid;
1715         DBusMessageIter variant_iter;
1716
1717         /*
1718          * Leveraging the fact that persistent group object is still
1719          * represented in same manner as network within.
1720          */
1721         dbus_message_iter_recurse(iter, &variant_iter);
1722         return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
1723 }
1724
1725
1726 /**
1727  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1728  *      persistent_group
1729  * @message: Pointer to incoming dbus message
1730  * @wpa_s: wpa_supplicant structure for a network interface
1731  * Returns: A dbus message containing the object path of the new
1732  * persistent group
1733  *
1734  * Handler function for "AddPersistentGroup" method call of a P2P Device
1735  * interface.
1736  */
1737 DBusMessage * wpas_dbus_handler_add_persistent_group(
1738         DBusMessage *message, struct wpa_supplicant *wpa_s)
1739 {
1740         DBusMessage *reply = NULL;
1741         DBusMessageIter iter;
1742         struct wpa_ssid *ssid = NULL;
1743         char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1744         DBusError error;
1745
1746         dbus_message_iter_init(message, &iter);
1747
1748         ssid = wpa_config_add_network(wpa_s->conf);
1749         if (ssid == NULL) {
1750                 wpa_printf(MSG_ERROR, "dbus: %s: "
1751                            "Cannot add new persistent group", __func__);
1752                 reply = wpas_dbus_error_unknown_error(
1753                         message,
1754                         "wpa_supplicant could not add "
1755                         "a persistent group on this interface.");
1756                 goto err;
1757         }
1758
1759         /* Mark the ssid as being a persistent group before the notification */
1760         ssid->disabled = 2;
1761         ssid->p2p_persistent_group = 1;
1762         wpas_notify_persistent_group_added(wpa_s, ssid);
1763
1764         wpa_config_set_network_defaults(ssid);
1765
1766         dbus_error_init(&error);
1767         if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1768                 wpa_printf(MSG_DEBUG, "dbus: %s: "
1769                            "Control interface could not set persistent group "
1770                            "properties", __func__);
1771                 reply = wpas_dbus_reply_new_from_error(message, &error,
1772                                                        DBUS_ERROR_INVALID_ARGS,
1773                                                        "Failed to set network "
1774                                                        "properties");
1775                 dbus_error_free(&error);
1776                 goto err;
1777         }
1778
1779         /* Construct the object path for this network. */
1780         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1781                     "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1782                     wpa_s->dbus_new_path, ssid->id);
1783
1784         reply = dbus_message_new_method_return(message);
1785         if (reply == NULL) {
1786                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1787                                                NULL);
1788                 goto err;
1789         }
1790         if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1791                                       DBUS_TYPE_INVALID)) {
1792                 dbus_message_unref(reply);
1793                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1794                                                NULL);
1795                 goto err;
1796         }
1797
1798         return reply;
1799
1800 err:
1801         if (ssid) {
1802                 wpas_notify_persistent_group_removed(wpa_s, ssid);
1803                 wpa_config_remove_network(wpa_s->conf, ssid->id);
1804         }
1805         return reply;
1806 }
1807
1808
1809 /**
1810  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1811  *      group
1812  * @message: Pointer to incoming dbus message
1813  * @wpa_s: wpa_supplicant structure for a network interface
1814  * Returns: NULL on success or dbus error on failure
1815  *
1816  * Handler function for "RemovePersistentGroup" method call of a P2P Device
1817  * interface.
1818  */
1819 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1820         DBusMessage *message, struct wpa_supplicant *wpa_s)
1821 {
1822         DBusMessage *reply = NULL;
1823         const char *op;
1824         char *iface = NULL, *persistent_group_id;
1825         int id;
1826         struct wpa_ssid *ssid;
1827
1828         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1829                               DBUS_TYPE_INVALID);
1830
1831         /*
1832          * Extract the network ID and ensure the network is actually a child of
1833          * this interface.
1834          */
1835         iface = wpas_dbus_new_decompose_object_path(
1836                 op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
1837                 &persistent_group_id);
1838         if (iface == NULL || persistent_group_id == NULL ||
1839             os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1840                 reply = wpas_dbus_error_invalid_args(message, op);
1841                 goto out;
1842         }
1843
1844         id = strtoul(persistent_group_id, NULL, 10);
1845         if (errno == EINVAL) {
1846                 reply = wpas_dbus_error_invalid_args(message, op);
1847                 goto out;
1848         }
1849
1850         ssid = wpa_config_get_network(wpa_s->conf, id);
1851         if (ssid == NULL) {
1852                 reply = wpas_dbus_error_persistent_group_unknown(message);
1853                 goto out;
1854         }
1855
1856         wpas_notify_persistent_group_removed(wpa_s, ssid);
1857
1858         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1859                 wpa_printf(MSG_ERROR, "dbus: %s: "
1860                            "error occurred when removing persistent group %d",
1861                            __func__, id);
1862                 reply = wpas_dbus_error_unknown_error(
1863                         message,
1864                         "error removing the specified persistent group on "
1865                         "this interface.");
1866                 goto out;
1867         }
1868
1869 out:
1870         os_free(iface);
1871         return reply;
1872 }
1873
1874
1875 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1876                                     struct wpa_ssid *ssid)
1877 {
1878         wpas_notify_persistent_group_removed(wpa_s, ssid);
1879
1880         if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1881                 wpa_printf(MSG_ERROR, "dbus: %s: "
1882                            "error occurred when removing persistent group %d",
1883                            __func__, ssid->id);
1884                 return;
1885         }
1886 }
1887
1888
1889 /**
1890  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1891  * persistent groups
1892  * @message: Pointer to incoming dbus message
1893  * @wpa_s: wpa_supplicant structure for a network interface
1894  * Returns: NULL on success or dbus error on failure
1895  *
1896  * Handler function for "RemoveAllPersistentGroups" method call of a
1897  * P2P Device interface.
1898  */
1899 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1900         DBusMessage *message, struct wpa_supplicant *wpa_s)
1901 {
1902         struct wpa_ssid *ssid, *next;
1903         struct wpa_config *config;
1904
1905         config = wpa_s->conf;
1906         ssid = config->ssid;
1907         while (ssid) {
1908                 next = ssid->next;
1909                 if (network_is_persistent_group(ssid))
1910                         remove_persistent_group(wpa_s, ssid);
1911                 ssid = next;
1912         }
1913         return NULL;
1914 }
1915
1916
1917 /*
1918  * Group object properties accessor methods
1919  */
1920
1921 dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
1922                                                DBusError *error,
1923                                                void *user_data)
1924 {
1925         struct wpa_supplicant *wpa_s = user_data;
1926         struct wpa_ssid *ssid;
1927         unsigned int num_members;
1928         char **paths;
1929         unsigned int i;
1930         void *next = NULL;
1931         const u8 *addr;
1932         dbus_bool_t success = FALSE;
1933
1934         /* Verify correct role for this property */
1935         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
1936                 return wpas_dbus_simple_array_property_getter(
1937                         iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
1938         }
1939
1940         ssid = wpa_s->conf->ssid;
1941         /* At present WPAS P2P_GO mode only applicable for p2p_go */
1942         if (ssid->mode != WPAS_MODE_P2P_GO &&
1943             ssid->mode != WPAS_MODE_AP &&
1944             ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1945                 return FALSE;
1946
1947         num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1948
1949         paths = os_calloc(num_members, sizeof(char *));
1950         if (!paths)
1951                 goto out_of_memory;
1952
1953         i = 0;
1954         while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1955                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1956                 if (!paths[i])
1957                         goto out_of_memory;
1958                 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1959                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1960                             "/" COMPACT_MACSTR,
1961                             wpa_s->parent->dbus_new_path, MAC2STR(addr));
1962                 i++;
1963         }
1964
1965         success = wpas_dbus_simple_array_property_getter(iter,
1966                                                          DBUS_TYPE_OBJECT_PATH,
1967                                                          paths, num_members,
1968                                                          error);
1969
1970         for (i = 0; i < num_members; i++)
1971                 os_free(paths[i]);
1972         os_free(paths);
1973         return success;
1974
1975 out_of_memory:
1976         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1977         if (paths) {
1978                 for (i = 0; i < num_members; i++)
1979                         os_free(paths[i]);
1980                 os_free(paths);
1981         }
1982         return FALSE;
1983 }
1984
1985
1986 dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
1987                                             DBusError *error, void *user_data)
1988 {
1989         struct wpa_supplicant *wpa_s = user_data;
1990         if (wpa_s->current_ssid == NULL)
1991                 return FALSE;
1992         return wpas_dbus_simple_array_property_getter(
1993                 iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
1994                 wpa_s->current_ssid->ssid_len, error);
1995 }
1996
1997
1998 dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
1999                                              DBusError *error,
2000                                              void *user_data)
2001 {
2002         struct wpa_supplicant *wpa_s = user_data;
2003         u8 role = wpas_get_p2p_role(wpa_s);
2004         u8 *p_bssid;
2005
2006         if (role == WPAS_P2P_ROLE_CLIENT) {
2007                 if (wpa_s->current_ssid == NULL)
2008                         return FALSE;
2009                 p_bssid = wpa_s->current_ssid->bssid;
2010         } else {
2011                 if (wpa_s->ap_iface == NULL)
2012                         return FALSE;
2013                 p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
2014         }
2015
2016         return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2017                                                       p_bssid, ETH_ALEN,
2018                                                       error);
2019 }
2020
2021
2022 dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
2023                                                  DBusError *error,
2024                                                  void *user_data)
2025 {
2026         struct wpa_supplicant *wpa_s = user_data;
2027         u16 op_freq;
2028         u8 role = wpas_get_p2p_role(wpa_s);
2029
2030         if (role == WPAS_P2P_ROLE_CLIENT) {
2031                 if (wpa_s->go_params == NULL)
2032                         return FALSE;
2033                 op_freq = wpa_s->go_params->freq;
2034         } else {
2035                 if (wpa_s->ap_iface == NULL)
2036                         return FALSE;
2037                 op_freq = wpa_s->ap_iface->freq;
2038         }
2039
2040         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
2041                                                 &op_freq, error);
2042 }
2043
2044
2045 dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
2046                                                   DBusError *error,
2047                                                   void *user_data)
2048 {
2049         struct wpa_supplicant *wpa_s = user_data;
2050         u8 role = wpas_get_p2p_role(wpa_s);
2051         char *p_pass = NULL;
2052
2053         /* Verify correct role for this property */
2054         if (role == WPAS_P2P_ROLE_GO) {
2055                 if (wpa_s->current_ssid == NULL)
2056                         return FALSE;
2057                 p_pass = wpa_s->current_ssid->passphrase;
2058         } else
2059                 p_pass = "";
2060
2061         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2062                                                 &p_pass, error);
2063
2064 }
2065
2066
2067 dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
2068                                            DBusError *error, void *user_data)
2069 {
2070         struct wpa_supplicant *wpa_s = user_data;
2071         u8 role = wpas_get_p2p_role(wpa_s);
2072         u8 *p_psk = NULL;
2073         u8 psk_len = 0;
2074
2075         /* Verify correct role for this property */
2076         if (role == WPAS_P2P_ROLE_CLIENT) {
2077                 if (wpa_s->current_ssid == NULL)
2078                         return FALSE;
2079                 p_psk = wpa_s->current_ssid->psk;
2080                 psk_len = 32;
2081         }
2082
2083         return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2084                                                       &p_psk, psk_len, error);
2085 }
2086
2087
2088 dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
2089                                                   DBusError *error,
2090                                                   void *user_data)
2091 {
2092         struct wpa_supplicant *wpa_s = user_data;
2093         struct hostapd_data *hapd;
2094         struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
2095         unsigned int i, num_vendor_ext = 0;
2096
2097         os_memset(vendor_ext, 0, sizeof(vendor_ext));
2098
2099         /* Verify correct role for this property */
2100         if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
2101                 if (wpa_s->ap_iface == NULL)
2102                         return FALSE;
2103                 hapd = wpa_s->ap_iface->bss[0];
2104
2105                 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
2106                 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2107                         if (hapd->conf->wps_vendor_ext[i] == NULL)
2108                                 continue;
2109                         vendor_ext[num_vendor_ext++] =
2110                                 hapd->conf->wps_vendor_ext[i];
2111                 }
2112         }
2113
2114         /* Return vendor extensions or no data */
2115         return wpas_dbus_simple_array_array_property_getter(iter,
2116                                                             DBUS_TYPE_BYTE,
2117                                                             vendor_ext,
2118                                                             num_vendor_ext,
2119                                                             error);
2120 }
2121
2122
2123 dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
2124                                                   DBusError *error,
2125                                                   void *user_data)
2126 {
2127         struct wpa_supplicant *wpa_s = user_data;
2128         DBusMessageIter variant_iter, iter_dict, array_iter, sub;
2129         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
2130         unsigned int i;
2131         struct hostapd_data *hapd = NULL;
2132
2133         if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO &&
2134             wpa_s->ap_iface != NULL)
2135                 hapd = wpa_s->ap_iface->bss[0];
2136         else
2137                 return FALSE;
2138
2139         dbus_message_iter_recurse(iter, &variant_iter);
2140         if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
2141                 return FALSE;
2142
2143         /*
2144          * This is supposed to be array of bytearrays (aay), but the earlier
2145          * implementation used a dict with "WPSVendorExtensions" as the key in
2146          * this setter function which does not match the format used by the
2147          * getter function. For backwards compatibility, allow both formats to
2148          * be used in the setter.
2149          */
2150         if (dbus_message_iter_get_element_type(&variant_iter) ==
2151             DBUS_TYPE_ARRAY) {
2152                 /* This is the proper format matching the getter */
2153                 struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
2154
2155                 dbus_message_iter_recurse(&variant_iter, &array_iter);
2156
2157                 if (dbus_message_iter_get_arg_type(&array_iter) !=
2158                     DBUS_TYPE_ARRAY ||
2159                     dbus_message_iter_get_element_type(&array_iter) !=
2160                     DBUS_TYPE_BYTE) {
2161                         wpa_printf(MSG_DEBUG,
2162                                    "dbus: Not an array of array of bytes");
2163                         return FALSE;
2164                 }
2165
2166                 i = 0;
2167                 os_memset(vals, 0, sizeof(vals));
2168
2169                 while (dbus_message_iter_get_arg_type(&array_iter) ==
2170                        DBUS_TYPE_ARRAY) {
2171                         char *val;
2172                         int len;
2173
2174                         if (i == MAX_WPS_VENDOR_EXTENSIONS) {
2175                                 wpa_printf(MSG_DEBUG,
2176                                            "dbus: Too many WPSVendorExtensions values");
2177                                 i = MAX_WPS_VENDOR_EXTENSIONS + 1;
2178                                 break;
2179                         }
2180
2181                         dbus_message_iter_recurse(&array_iter, &sub);
2182                         dbus_message_iter_get_fixed_array(&sub, &val, &len);
2183                         wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
2184                                     val, len);
2185                         vals[i] = wpabuf_alloc_copy(val, len);
2186                         if (vals[i] == NULL) {
2187                                 i = MAX_WPS_VENDOR_EXTENSIONS + 1;
2188                                 break;
2189                         }
2190                         i++;
2191                         dbus_message_iter_next(&array_iter);
2192                 }
2193
2194                 if (i > MAX_WPS_VENDOR_EXTENSIONS) {
2195                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
2196                                 wpabuf_free(vals[i]);
2197                         return FALSE;
2198                 }
2199
2200                 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2201                         wpabuf_free(hapd->conf->wps_vendor_ext[i]);
2202                         hapd->conf->wps_vendor_ext[i] = vals[i];
2203                 }
2204
2205                 hostapd_update_wps(hapd);
2206
2207                 return TRUE;
2208         }
2209
2210         if (dbus_message_iter_get_element_type(&variant_iter) !=
2211             DBUS_TYPE_DICT_ENTRY)
2212                 return FALSE;
2213
2214         wpa_printf(MSG_DEBUG,
2215                    "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
2216         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
2217                 return FALSE;
2218
2219         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2220                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
2221                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2222                                              "invalid message format");
2223                         return FALSE;
2224                 }
2225
2226                 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
2227                         if (entry.type != DBUS_TYPE_ARRAY ||
2228                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
2229                             entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
2230                                 goto error;
2231
2232                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2233                                 wpabuf_free(hapd->conf->wps_vendor_ext[i]);
2234                                 if (i < entry.array_len) {
2235                                         hapd->conf->wps_vendor_ext[i] =
2236                                                 entry.binarray_value[i];
2237                                         entry.binarray_value[i] = NULL;
2238                                 } else
2239                                         hapd->conf->wps_vendor_ext[i] = NULL;
2240                         }
2241
2242                         hostapd_update_wps(hapd);
2243                 } else
2244                         goto error;
2245
2246                 wpa_dbus_dict_entry_clear(&entry);
2247         }
2248
2249         return TRUE;
2250
2251 error:
2252         wpa_dbus_dict_entry_clear(&entry);
2253         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2254                              "invalid message format");
2255         return FALSE;
2256 }
2257
2258
2259 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
2260                                                 struct wpa_supplicant *wpa_s)
2261 {
2262         DBusMessageIter iter_dict;
2263         DBusMessage *reply = NULL;
2264         DBusMessageIter iter;
2265         struct wpa_dbus_dict_entry entry;
2266         int upnp = 0;
2267         int bonjour = 0;
2268         char *service = NULL;
2269         struct wpabuf *query = NULL;
2270         struct wpabuf *resp = NULL;
2271         u8 version = 0;
2272
2273         dbus_message_iter_init(message, &iter);
2274
2275         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2276                 goto error;
2277
2278         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2279                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2280                         goto error;
2281
2282                 if (!os_strcmp(entry.key, "service_type") &&
2283                     (entry.type == DBUS_TYPE_STRING)) {
2284                         if (!os_strcmp(entry.str_value, "upnp"))
2285                                 upnp = 1;
2286                         else if (!os_strcmp(entry.str_value, "bonjour"))
2287                                 bonjour = 1;
2288                         else
2289                                 goto error_clear;
2290                 } else if (!os_strcmp(entry.key, "version") &&
2291                            entry.type == DBUS_TYPE_INT32) {
2292                         version = entry.uint32_value;
2293                 } else if (!os_strcmp(entry.key, "service") &&
2294                              (entry.type == DBUS_TYPE_STRING)) {
2295                         os_free(service);
2296                         service = os_strdup(entry.str_value);
2297                 } else if (!os_strcmp(entry.key, "query")) {
2298                         if ((entry.type != DBUS_TYPE_ARRAY) ||
2299                             (entry.array_type != DBUS_TYPE_BYTE))
2300                                 goto error_clear;
2301                         query = wpabuf_alloc_copy(
2302                                 entry.bytearray_value,
2303                                 entry.array_len);
2304                 } else if (!os_strcmp(entry.key, "response")) {
2305                         if ((entry.type != DBUS_TYPE_ARRAY) ||
2306                             (entry.array_type != DBUS_TYPE_BYTE))
2307                                 goto error_clear;
2308                         resp = wpabuf_alloc_copy(entry.bytearray_value,
2309                                                  entry.array_len);
2310                 }
2311                 wpa_dbus_dict_entry_clear(&entry);
2312         }
2313
2314         if (upnp == 1) {
2315                 if (version <= 0 || service == NULL)
2316                         goto error;
2317
2318                 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
2319                         goto error;
2320
2321         } else if (bonjour == 1) {
2322                 if (query == NULL || resp == NULL)
2323                         goto error;
2324
2325                 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
2326                         goto error;
2327                 query = NULL;
2328                 resp = NULL;
2329         } else
2330                 goto error;
2331
2332         os_free(service);
2333         return reply;
2334 error_clear:
2335         wpa_dbus_dict_entry_clear(&entry);
2336 error:
2337         os_free(service);
2338         wpabuf_free(query);
2339         wpabuf_free(resp);
2340         return wpas_dbus_error_invalid_args(message, NULL);
2341 }
2342
2343
2344 DBusMessage * wpas_dbus_handler_p2p_delete_service(
2345         DBusMessage *message, struct wpa_supplicant *wpa_s)
2346 {
2347         DBusMessageIter iter_dict;
2348         DBusMessage *reply = NULL;
2349         DBusMessageIter iter;
2350         struct wpa_dbus_dict_entry entry;
2351         int upnp = 0;
2352         int bonjour = 0;
2353         int ret = 0;
2354         char *service = NULL;
2355         struct wpabuf *query = NULL;
2356         u8 version = 0;
2357
2358         dbus_message_iter_init(message, &iter);
2359
2360         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2361                 goto error;
2362
2363         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2364                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2365                         goto error;
2366
2367                 if (!os_strcmp(entry.key, "service_type") &&
2368                     (entry.type == DBUS_TYPE_STRING)) {
2369                         if (!os_strcmp(entry.str_value, "upnp"))
2370                                 upnp = 1;
2371                         else if (!os_strcmp(entry.str_value, "bonjour"))
2372                                 bonjour = 1;
2373                         else
2374                                 goto error_clear;
2375                         wpa_dbus_dict_entry_clear(&entry);
2376                 }
2377         }
2378         if (upnp == 1) {
2379                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2380                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2381                                 goto error;
2382                         if (!os_strcmp(entry.key, "version") &&
2383                             entry.type == DBUS_TYPE_INT32)
2384                                 version = entry.uint32_value;
2385                         else if (!os_strcmp(entry.key, "service") &&
2386                                  entry.type == DBUS_TYPE_STRING) {
2387                                 os_free(service);
2388                                 service = os_strdup(entry.str_value);
2389                         } else
2390                                 goto error_clear;
2391
2392                         wpa_dbus_dict_entry_clear(&entry);
2393                 }
2394
2395                 if (version <= 0 || service == NULL)
2396                         goto error;
2397
2398                 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
2399                 if (ret != 0)
2400                         goto error;
2401         } else if (bonjour == 1) {
2402                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2403                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2404                                 goto error;
2405
2406                         if (!os_strcmp(entry.key, "query")) {
2407                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
2408                                     (entry.array_type != DBUS_TYPE_BYTE))
2409                                         goto error_clear;
2410                                 wpabuf_free(query);
2411                                 query = wpabuf_alloc_copy(
2412                                         entry.bytearray_value,
2413                                         entry.array_len);
2414                         } else
2415                                 goto error_clear;
2416
2417                         wpa_dbus_dict_entry_clear(&entry);
2418                 }
2419
2420                 if (query == NULL)
2421                         goto error;
2422
2423                 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
2424                 if (ret != 0)
2425                         goto error;
2426         } else
2427                 goto error;
2428
2429         wpabuf_free(query);
2430         os_free(service);
2431         return reply;
2432 error_clear:
2433         wpa_dbus_dict_entry_clear(&entry);
2434 error:
2435         wpabuf_free(query);
2436         os_free(service);
2437         return wpas_dbus_error_invalid_args(message, NULL);
2438 }
2439
2440
2441 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
2442                                                   struct wpa_supplicant *wpa_s)
2443 {
2444         wpas_p2p_service_flush(wpa_s);
2445         return NULL;
2446 }
2447
2448
2449 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
2450         DBusMessage *message, struct wpa_supplicant *wpa_s)
2451 {
2452         DBusMessageIter iter_dict;
2453         DBusMessage *reply = NULL;
2454         DBusMessageIter iter;
2455         struct wpa_dbus_dict_entry entry;
2456         int upnp = 0;
2457         char *service = NULL;
2458         char *peer_object_path = NULL;
2459         struct wpabuf *tlv = NULL;
2460         u8 version = 0;
2461         u64 ref = 0;
2462         u8 addr_buf[ETH_ALEN], *addr;
2463
2464         dbus_message_iter_init(message, &iter);
2465
2466         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2467                 goto error;
2468
2469         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2470                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2471                         goto error;
2472                 if (!os_strcmp(entry.key, "peer_object") &&
2473                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2474                         peer_object_path = os_strdup(entry.str_value);
2475                 } else if (!os_strcmp(entry.key, "service_type") &&
2476                            entry.type == DBUS_TYPE_STRING) {
2477                         if (!os_strcmp(entry.str_value, "upnp"))
2478                                 upnp = 1;
2479                         else
2480                                 goto error_clear;
2481                 } else if (!os_strcmp(entry.key, "version") &&
2482                            entry.type == DBUS_TYPE_INT32) {
2483                         version = entry.uint32_value;
2484                 } else if (!os_strcmp(entry.key, "service") &&
2485                            entry.type == DBUS_TYPE_STRING) {
2486                         service = os_strdup(entry.str_value);
2487                 } else if (!os_strcmp(entry.key, "tlv")) {
2488                         if (entry.type != DBUS_TYPE_ARRAY ||
2489                             entry.array_type != DBUS_TYPE_BYTE)
2490                                 goto error_clear;
2491                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2492                                                 entry.array_len);
2493                 } else
2494                         goto error_clear;
2495
2496                 wpa_dbus_dict_entry_clear(&entry);
2497         }
2498
2499         if (!peer_object_path) {
2500                 addr = NULL;
2501         } else {
2502                 if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
2503                     !p2p_peer_known(wpa_s->global->p2p, addr_buf))
2504                         goto error;
2505
2506                 addr = addr_buf;
2507         }
2508
2509         if (upnp == 1) {
2510                 if (version <= 0 || service == NULL)
2511                         goto error;
2512
2513                 ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
2514         } else {
2515                 if (tlv == NULL)
2516                         goto error;
2517                 ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
2518                 wpabuf_free(tlv);
2519         }
2520
2521         if (ref != 0) {
2522                 reply = dbus_message_new_method_return(message);
2523                 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2524                                          &ref, DBUS_TYPE_INVALID);
2525         } else {
2526                 reply = wpas_dbus_error_unknown_error(
2527                         message, "Unable to send SD request");
2528         }
2529 out:
2530         os_free(service);
2531         os_free(peer_object_path);
2532         return reply;
2533 error_clear:
2534         wpa_dbus_dict_entry_clear(&entry);
2535 error:
2536         if (tlv)
2537                 wpabuf_free(tlv);
2538         reply = wpas_dbus_error_invalid_args(message, NULL);
2539         goto out;
2540 }
2541
2542
2543 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2544         DBusMessage *message, struct wpa_supplicant *wpa_s)
2545 {
2546         DBusMessageIter iter_dict;
2547         DBusMessage *reply = NULL;
2548         DBusMessageIter iter;
2549         struct wpa_dbus_dict_entry entry;
2550         char *peer_object_path = NULL;
2551         struct wpabuf *tlv = NULL;
2552         int freq = 0;
2553         int dlg_tok = 0;
2554         u8 addr[ETH_ALEN];
2555
2556         dbus_message_iter_init(message, &iter);
2557
2558         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2559                 goto error;
2560
2561         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2562                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2563                         goto error;
2564
2565                 if (!os_strcmp(entry.key, "peer_object") &&
2566                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2567                         peer_object_path = os_strdup(entry.str_value);
2568                 } else if (!os_strcmp(entry.key, "frequency") &&
2569                            entry.type == DBUS_TYPE_INT32) {
2570                         freq = entry.uint32_value;
2571                 } else if (!os_strcmp(entry.key, "dialog_token") &&
2572                            (entry.type == DBUS_TYPE_UINT32 ||
2573                             entry.type == DBUS_TYPE_INT32)) {
2574                         dlg_tok = entry.uint32_value;
2575                 } else if (!os_strcmp(entry.key, "tlvs")) {
2576                         if (entry.type != DBUS_TYPE_ARRAY ||
2577                             entry.array_type != DBUS_TYPE_BYTE)
2578                                 goto error_clear;
2579                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2580                                                 entry.array_len);
2581                 } else
2582                         goto error_clear;
2583
2584                 wpa_dbus_dict_entry_clear(&entry);
2585         }
2586         if (parse_peer_object_path(peer_object_path, addr) < 0 ||
2587             !p2p_peer_known(wpa_s->global->p2p, addr) ||
2588             tlv == NULL)
2589                 goto error;
2590
2591         wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2592         wpabuf_free(tlv);
2593 out:
2594         os_free(peer_object_path);
2595         return reply;
2596 error_clear:
2597         wpa_dbus_dict_entry_clear(&entry);
2598 error:
2599         reply = wpas_dbus_error_invalid_args(message, NULL);
2600         goto out;
2601 }
2602
2603
2604 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2605         DBusMessage *message, struct wpa_supplicant *wpa_s)
2606 {
2607         DBusMessageIter iter;
2608         u64 req = 0;
2609
2610         dbus_message_iter_init(message, &iter);
2611         dbus_message_iter_get_basic(&iter, &req);
2612
2613         if (req == 0)
2614                 goto error;
2615
2616         if (wpas_p2p_sd_cancel_request(wpa_s, req) < 0)
2617                 goto error;
2618
2619         return NULL;
2620 error:
2621         return wpas_dbus_error_invalid_args(message, NULL);
2622 }
2623
2624
2625 DBusMessage * wpas_dbus_handler_p2p_service_update(
2626         DBusMessage *message, struct wpa_supplicant *wpa_s)
2627 {
2628         wpas_p2p_sd_service_update(wpa_s);
2629         return NULL;
2630 }
2631
2632
2633 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2634         DBusMessage *message, struct wpa_supplicant *wpa_s)
2635 {
2636         DBusMessageIter iter;
2637         int ext = 0;
2638
2639         dbus_message_iter_init(message, &iter);
2640         dbus_message_iter_get_basic(&iter, &ext);
2641
2642         wpa_s->p2p_sd_over_ctrl_iface = ext;
2643
2644         return NULL;
2645
2646 }
2647
2648
2649 #ifdef CONFIG_WIFI_DISPLAY
2650
2651 dbus_bool_t wpas_dbus_getter_global_wfd_ies(DBusMessageIter *iter,
2652                                             DBusError *error, void *user_data)
2653 {
2654         struct wpa_global *global = user_data;
2655         struct wpabuf *ie;
2656         dbus_bool_t ret;
2657
2658         ie = wifi_display_get_wfd_ie(global);
2659         if (ie == NULL)
2660                 return wpas_dbus_simple_array_property_getter(iter,
2661                                                               DBUS_TYPE_BYTE,
2662                                                               NULL, 0, error);
2663
2664         ret = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2665                                                      wpabuf_head(ie),
2666                                                      wpabuf_len(ie), error);
2667         wpabuf_free(ie);
2668
2669         return ret;
2670 }
2671
2672
2673 dbus_bool_t wpas_dbus_setter_global_wfd_ies(DBusMessageIter *iter,
2674                                             DBusError *error, void *user_data)
2675 {
2676         struct wpa_global *global = user_data;
2677         DBusMessageIter variant, array;
2678         struct wpabuf *ie = NULL;
2679         const u8 *data;
2680         int len;
2681
2682         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
2683                 goto err;
2684
2685         dbus_message_iter_recurse(iter, &variant);
2686         if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
2687                 goto err;
2688
2689         dbus_message_iter_recurse(&variant, &array);
2690         dbus_message_iter_get_fixed_array(&array, &data, &len);
2691         if (len == 0) {
2692                 wifi_display_enable(global, 0);
2693                 wifi_display_deinit(global);
2694
2695                 return TRUE;
2696         }
2697
2698         ie = wpabuf_alloc(len);
2699         if (ie == NULL)
2700                 goto err;
2701
2702         wpabuf_put_data(ie, data, len);
2703         if (wifi_display_subelem_set_from_ies(global, ie) != 0)
2704                 goto err;
2705
2706         if (global->wifi_display == 0)
2707                 wifi_display_enable(global, 1);
2708
2709         wpabuf_free(ie);
2710
2711         return TRUE;
2712 err:
2713         wpabuf_free(ie);
2714
2715         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2716                              "invalid message format");
2717         return FALSE;
2718 }
2719
2720 #endif /* CONFIG_WIFI_DISPLAY */