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