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