dbus: Clean up array-array-type property 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         unsigned int i, num = 0;
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         os_memset(vendor_extension, 0, sizeof(vendor_extension));
1472         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1473                 if (info->wps_vendor_ext[i] == NULL)
1474                         continue;
1475                 vendor_extension[num] = info->wps_vendor_ext[i];
1476                 num++;
1477         }
1478
1479         if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE,
1480                                                           vendor_extension,
1481                                                           num, error))
1482                 return FALSE;
1483
1484         return TRUE;
1485 }
1486
1487
1488 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
1489                                           DBusError *error, void *user_data)
1490 {
1491         struct peer_handler_args *peer_args = user_data;
1492         const struct p2p_peer_info *info;
1493
1494         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1495                                   peer_args->p2p_device_addr, 0);
1496         if (info == NULL) {
1497                 dbus_set_error(error, DBUS_ERROR_FAILED,
1498                                "failed to find peer");
1499                 return FALSE;
1500         }
1501
1502         if (info->wfd_subelems == NULL)
1503                 return wpas_dbus_simple_array_property_getter(iter,
1504                                                               DBUS_TYPE_BYTE,
1505                                                               NULL, 0, error);
1506
1507         return wpas_dbus_simple_array_property_getter(
1508                 iter, DBUS_TYPE_BYTE, (char *) info->wfd_subelems->buf,
1509                 info->wfd_subelems->used, error);
1510 }
1511
1512
1513 dbus_bool_t wpas_dbus_getter_p2p_peer_device_address(DBusMessageIter *iter,
1514                                                      DBusError *error,
1515                                                      void *user_data)
1516 {
1517         struct peer_handler_args *peer_args = user_data;
1518         const struct p2p_peer_info *info;
1519
1520         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1521                                   peer_args->p2p_device_addr, 0);
1522         if (info == NULL) {
1523                 dbus_set_error(error, DBUS_ERROR_FAILED,
1524                                "failed to find peer");
1525                 return FALSE;
1526         }
1527
1528         return wpas_dbus_simple_array_property_getter(
1529                 iter, DBUS_TYPE_BYTE, (char *) info->p2p_device_addr,
1530                 ETH_ALEN, error);
1531 }
1532
1533
1534 struct peer_group_data {
1535         struct wpa_supplicant *wpa_s;
1536         const struct p2p_peer_info *info;
1537         char **paths;
1538         unsigned int nb_paths;
1539         int error;
1540 };
1541
1542
1543 static int match_group_where_peer_is_client(struct p2p_group *group,
1544                                             void *user_data)
1545 {
1546         struct peer_group_data *data = user_data;
1547         const struct p2p_group_config *cfg;
1548         struct wpa_supplicant *wpa_s_go;
1549         char **paths;
1550
1551         if (!p2p_group_is_client_connected(group, data->info->p2p_device_addr))
1552                 return 1;
1553
1554         cfg = p2p_group_get_config(group);
1555
1556         wpa_s_go = wpas_get_p2p_go_iface(data->wpa_s, cfg->ssid,
1557                                          cfg->ssid_len);
1558         if (wpa_s_go == NULL)
1559                 return 1;
1560
1561         paths = os_realloc_array(data->paths, data->nb_paths + 1,
1562                                  sizeof(char *));
1563         if (paths == NULL)
1564                 goto out_of_memory;
1565
1566         data->paths = paths;
1567         data->paths[data->nb_paths] = wpa_s_go->dbus_groupobj_path;
1568         data->nb_paths++;
1569
1570         return 1;
1571
1572 out_of_memory:
1573         data->error = ENOMEM;
1574         return 0;
1575 }
1576
1577
1578 dbus_bool_t wpas_dbus_getter_p2p_peer_groups(DBusMessageIter *iter,
1579                                              DBusError *error,
1580                                              void *user_data)
1581 {
1582         struct peer_handler_args *peer_args = user_data;
1583         const struct p2p_peer_info *info;
1584         struct peer_group_data data;
1585         struct wpa_supplicant *wpa_s_go;
1586         dbus_bool_t success = FALSE;
1587
1588         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1589                                   peer_args->p2p_device_addr, 0);
1590         if (info == NULL) {
1591                 dbus_set_error(error, DBUS_ERROR_FAILED,
1592                                "failed to find peer");
1593                 return FALSE;
1594         }
1595
1596         os_memset(&data, 0, sizeof(data));
1597         wpa_s_go = wpas_get_p2p_client_iface(peer_args->wpa_s,
1598                                              info->p2p_device_addr);
1599         if (wpa_s_go) {
1600                 data.paths = os_calloc(1, sizeof(char *));
1601                 if (data.paths == NULL)
1602                         goto out_of_memory;
1603                 data.paths[0] = wpa_s_go->dbus_groupobj_path;
1604                 data.nb_paths = 1;
1605         }
1606
1607         data.wpa_s = peer_args->wpa_s;
1608         data.info = info;
1609
1610         p2p_loop_on_all_groups(peer_args->wpa_s->global->p2p,
1611                                match_group_where_peer_is_client, &data);
1612         if (data.error)
1613                 goto out_of_memory;
1614
1615         if (data.paths == NULL) {
1616                 return wpas_dbus_simple_array_property_getter(
1617                         iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
1618         }
1619
1620         success = wpas_dbus_simple_array_property_getter(iter,
1621                                                          DBUS_TYPE_OBJECT_PATH,
1622                                                          data.paths,
1623                                                          data.nb_paths, error);
1624         goto out;
1625
1626 out_of_memory:
1627         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1628 out:
1629         os_free(data.paths);
1630         return success;
1631 }
1632
1633
1634 /**
1635  * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
1636  * @iter: Pointer to incoming dbus message iter
1637  * @error: Location to store error on failure
1638  * @user_data: Function specific data
1639  * Returns: TRUE on success, FALSE on failure
1640  *
1641  * Getter for "PersistentGroups" property.
1642  */
1643 dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
1644                                                DBusError *error,
1645                                                void *user_data)
1646 {
1647         struct wpa_supplicant *wpa_s = user_data;
1648         struct wpa_ssid *ssid;
1649         char **paths;
1650         unsigned int i = 0, num = 0;
1651         dbus_bool_t success = FALSE;
1652
1653         if (wpa_s->conf == NULL) {
1654                 wpa_printf(MSG_ERROR, "dbus: %s: "
1655                            "An error occurred getting persistent groups list",
1656                            __func__);
1657                 dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
1658                                      "occurred getting persistent groups list");
1659                 return FALSE;
1660         }
1661
1662         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1663                 if (network_is_persistent_group(ssid))
1664                         num++;
1665
1666         paths = os_calloc(num, sizeof(char *));
1667         if (!paths) {
1668                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1669                 return FALSE;
1670         }
1671
1672         /* Loop through configured networks and append object path of each */
1673         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1674                 if (!network_is_persistent_group(ssid))
1675                         continue;
1676                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1677                 if (paths[i] == NULL) {
1678                         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
1679                                              "no memory");
1680                         goto out;
1681                 }
1682                 /* Construct the object path for this network. */
1683                 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1684                             "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1685                             wpa_s->dbus_new_path, ssid->id);
1686         }
1687
1688         success = wpas_dbus_simple_array_property_getter(iter,
1689                                                          DBUS_TYPE_OBJECT_PATH,
1690                                                          paths, num, error);
1691
1692 out:
1693         while (i)
1694                 os_free(paths[--i]);
1695         os_free(paths);
1696         return success;
1697 }
1698
1699
1700 /**
1701  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1702  *      group
1703  * @iter: Pointer to incoming dbus message iter
1704  * @error: Location to store error on failure
1705  * @user_data: Function specific data
1706  * Returns: TRUE on success, FALSE on failure
1707  *
1708  * Getter for "Properties" property of a persistent group.
1709  */
1710 dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
1711                                                          DBusError *error,
1712                                                          void *user_data)
1713 {
1714         struct network_handler_args *net = user_data;
1715
1716         /* Leveraging the fact that persistent group object is still
1717          * represented in same manner as network within.
1718          */
1719         return wpas_dbus_getter_network_properties(iter, error, net);
1720 }
1721
1722
1723 /**
1724  * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1725  *      group
1726  * @iter: Pointer to incoming dbus message iter
1727  * @error: Location to store error on failure
1728  * @user_data: Function specific data
1729  * Returns: TRUE on success, FALSE on failure
1730  *
1731  * Setter for "Properties" property of a persistent group.
1732  */
1733 dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
1734                                                          DBusError *error,
1735                                                          void *user_data)
1736 {
1737         struct network_handler_args *net = user_data;
1738         struct wpa_ssid *ssid = net->ssid;
1739         DBusMessageIter variant_iter;
1740
1741         /*
1742          * Leveraging the fact that persistent group object is still
1743          * represented in same manner as network within.
1744          */
1745         dbus_message_iter_recurse(iter, &variant_iter);
1746         return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
1747 }
1748
1749
1750 /**
1751  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1752  *      persistent_group
1753  * @message: Pointer to incoming dbus message
1754  * @wpa_s: wpa_supplicant structure for a network interface
1755  * Returns: A dbus message containing the object path of the new
1756  * persistent group
1757  *
1758  * Handler function for "AddPersistentGroup" method call of a P2P Device
1759  * interface.
1760  */
1761 DBusMessage * wpas_dbus_handler_add_persistent_group(
1762         DBusMessage *message, struct wpa_supplicant *wpa_s)
1763 {
1764         DBusMessage *reply = NULL;
1765         DBusMessageIter iter;
1766         struct wpa_ssid *ssid = NULL;
1767         char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1768         DBusError error;
1769
1770         dbus_message_iter_init(message, &iter);
1771
1772         ssid = wpa_config_add_network(wpa_s->conf);
1773         if (ssid == NULL) {
1774                 wpa_printf(MSG_ERROR, "dbus: %s: "
1775                            "Cannot add new persistent group", __func__);
1776                 reply = wpas_dbus_error_unknown_error(
1777                         message,
1778                         "wpa_supplicant could not add "
1779                         "a persistent group on this interface.");
1780                 goto err;
1781         }
1782
1783         /* Mark the ssid as being a persistent group before the notification */
1784         ssid->disabled = 2;
1785         ssid->p2p_persistent_group = 1;
1786         wpas_notify_persistent_group_added(wpa_s, ssid);
1787
1788         wpa_config_set_network_defaults(ssid);
1789
1790         dbus_error_init(&error);
1791         if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1792                 wpa_printf(MSG_DEBUG, "dbus: %s: "
1793                            "Control interface could not set persistent group "
1794                            "properties", __func__);
1795                 reply = wpas_dbus_reply_new_from_error(message, &error,
1796                                                        DBUS_ERROR_INVALID_ARGS,
1797                                                        "Failed to set network "
1798                                                        "properties");
1799                 dbus_error_free(&error);
1800                 goto err;
1801         }
1802
1803         /* Construct the object path for this network. */
1804         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1805                     "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1806                     wpa_s->dbus_new_path, ssid->id);
1807
1808         reply = dbus_message_new_method_return(message);
1809         if (reply == NULL) {
1810                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1811                                                NULL);
1812                 goto err;
1813         }
1814         if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1815                                       DBUS_TYPE_INVALID)) {
1816                 dbus_message_unref(reply);
1817                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1818                                                NULL);
1819                 goto err;
1820         }
1821
1822         return reply;
1823
1824 err:
1825         if (ssid) {
1826                 wpas_notify_persistent_group_removed(wpa_s, ssid);
1827                 wpa_config_remove_network(wpa_s->conf, ssid->id);
1828         }
1829         return reply;
1830 }
1831
1832
1833 /**
1834  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1835  *      group
1836  * @message: Pointer to incoming dbus message
1837  * @wpa_s: wpa_supplicant structure for a network interface
1838  * Returns: NULL on success or dbus error on failure
1839  *
1840  * Handler function for "RemovePersistentGroup" method call of a P2P Device
1841  * interface.
1842  */
1843 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1844         DBusMessage *message, struct wpa_supplicant *wpa_s)
1845 {
1846         DBusMessage *reply = NULL;
1847         const char *op;
1848         char *iface = NULL, *persistent_group_id = NULL;
1849         int id;
1850         struct wpa_ssid *ssid;
1851
1852         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1853                               DBUS_TYPE_INVALID);
1854
1855         /*
1856          * Extract the network ID and ensure the network is actually a child of
1857          * this interface.
1858          */
1859         iface = wpas_dbus_new_decompose_object_path(op, 1,
1860                                                     &persistent_group_id,
1861                                                     NULL);
1862         if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1863                 reply = wpas_dbus_error_invalid_args(message, op);
1864                 goto out;
1865         }
1866
1867         id = strtoul(persistent_group_id, NULL, 10);
1868         if (errno == EINVAL) {
1869                 reply = wpas_dbus_error_invalid_args(message, op);
1870                 goto out;
1871         }
1872
1873         ssid = wpa_config_get_network(wpa_s->conf, id);
1874         if (ssid == NULL) {
1875                 reply = wpas_dbus_error_persistent_group_unknown(message);
1876                 goto out;
1877         }
1878
1879         wpas_notify_persistent_group_removed(wpa_s, ssid);
1880
1881         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1882                 wpa_printf(MSG_ERROR, "dbus: %s: "
1883                            "error occurred when removing persistent group %d",
1884                            __func__, id);
1885                 reply = wpas_dbus_error_unknown_error(
1886                         message,
1887                         "error removing the specified persistent group on "
1888                         "this interface.");
1889                 goto out;
1890         }
1891
1892 out:
1893         os_free(iface);
1894         os_free(persistent_group_id);
1895         return reply;
1896 }
1897
1898
1899 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1900                                     struct wpa_ssid *ssid)
1901 {
1902         wpas_notify_persistent_group_removed(wpa_s, ssid);
1903
1904         if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1905                 wpa_printf(MSG_ERROR, "dbus: %s: "
1906                            "error occurred when removing persistent group %d",
1907                            __func__, ssid->id);
1908                 return;
1909         }
1910 }
1911
1912
1913 /**
1914  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1915  * persistent groups
1916  * @message: Pointer to incoming dbus message
1917  * @wpa_s: wpa_supplicant structure for a network interface
1918  * Returns: NULL on success or dbus error on failure
1919  *
1920  * Handler function for "RemoveAllPersistentGroups" method call of a
1921  * P2P Device interface.
1922  */
1923 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1924         DBusMessage *message, struct wpa_supplicant *wpa_s)
1925 {
1926         struct wpa_ssid *ssid, *next;
1927         struct wpa_config *config;
1928
1929         config = wpa_s->conf;
1930         ssid = config->ssid;
1931         while (ssid) {
1932                 next = ssid->next;
1933                 if (network_is_persistent_group(ssid))
1934                         remove_persistent_group(wpa_s, ssid);
1935                 ssid = next;
1936         }
1937         return NULL;
1938 }
1939
1940
1941 /*
1942  * Group object properties accessor methods
1943  */
1944
1945 dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
1946                                                DBusError *error,
1947                                                void *user_data)
1948 {
1949         struct wpa_supplicant *wpa_s = user_data;
1950         struct wpa_ssid *ssid;
1951         unsigned int num_members;
1952         char **paths;
1953         unsigned int i;
1954         void *next = NULL;
1955         const u8 *addr;
1956         dbus_bool_t success = FALSE;
1957
1958         /* Verify correct role for this property */
1959         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) {
1960                 return wpas_dbus_simple_array_property_getter(
1961                         iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error);
1962         }
1963
1964         ssid = wpa_s->conf->ssid;
1965         /* At present WPAS P2P_GO mode only applicable for p2p_go */
1966         if (ssid->mode != WPAS_MODE_P2P_GO &&
1967             ssid->mode != WPAS_MODE_AP &&
1968             ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1969                 return FALSE;
1970
1971         num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1972
1973         paths = os_calloc(num_members, sizeof(char *));
1974         if (!paths)
1975                 goto out_of_memory;
1976
1977         i = 0;
1978         while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1979                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1980                 if (!paths[i])
1981                         goto out_of_memory;
1982                 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1983                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1984                             "/" COMPACT_MACSTR,
1985                             wpa_s->parent->dbus_new_path, MAC2STR(addr));
1986                 i++;
1987         }
1988
1989         success = wpas_dbus_simple_array_property_getter(iter,
1990                                                          DBUS_TYPE_OBJECT_PATH,
1991                                                          paths, num_members,
1992                                                          error);
1993
1994         for (i = 0; i < num_members; i++)
1995                 os_free(paths[i]);
1996         os_free(paths);
1997         return success;
1998
1999 out_of_memory:
2000         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2001         if (paths) {
2002                 for (i = 0; i < num_members; i++)
2003                         os_free(paths[i]);
2004                 os_free(paths);
2005         }
2006         return FALSE;
2007 }
2008
2009
2010 dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter,
2011                                             DBusError *error, void *user_data)
2012 {
2013         struct wpa_supplicant *wpa_s = user_data;
2014         if (wpa_s->current_ssid == NULL)
2015                 return FALSE;
2016         return wpas_dbus_simple_array_property_getter(
2017                 iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid,
2018                 wpa_s->current_ssid->ssid_len, error);
2019 }
2020
2021
2022 dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter,
2023                                              DBusError *error,
2024                                              void *user_data)
2025 {
2026         struct wpa_supplicant *wpa_s = user_data;
2027         u8 role = wpas_get_p2p_role(wpa_s);
2028         u8 *p_bssid;
2029
2030         if (role == WPAS_P2P_ROLE_CLIENT) {
2031                 if (wpa_s->current_ssid == NULL)
2032                         return FALSE;
2033                 p_bssid = wpa_s->current_ssid->bssid;
2034         } else {
2035                 if (wpa_s->ap_iface == NULL)
2036                         return FALSE;
2037                 p_bssid = wpa_s->ap_iface->bss[0]->own_addr;
2038         }
2039
2040         return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2041                                                       p_bssid, ETH_ALEN,
2042                                                       error);
2043 }
2044
2045
2046 dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter,
2047                                                  DBusError *error,
2048                                                  void *user_data)
2049 {
2050         struct wpa_supplicant *wpa_s = user_data;
2051         u16 op_freq;
2052         u8 role = wpas_get_p2p_role(wpa_s);
2053
2054         if (role == WPAS_P2P_ROLE_CLIENT) {
2055                 if (wpa_s->go_params == NULL)
2056                         return FALSE;
2057                 op_freq = wpa_s->go_params->freq;
2058         } else {
2059                 if (wpa_s->ap_iface == NULL)
2060                         return FALSE;
2061                 op_freq = wpa_s->ap_iface->freq;
2062         }
2063
2064         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
2065                                                 &op_freq, error);
2066 }
2067
2068
2069 dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter,
2070                                                   DBusError *error,
2071                                                   void *user_data)
2072 {
2073         struct wpa_supplicant *wpa_s = user_data;
2074         u8 role = wpas_get_p2p_role(wpa_s);
2075         char *p_pass = NULL;
2076
2077         /* Verify correct role for this property */
2078         if (role == WPAS_P2P_ROLE_GO) {
2079                 if (wpa_s->current_ssid == NULL)
2080                         return FALSE;
2081                 p_pass = wpa_s->current_ssid->passphrase;
2082         } else
2083                 p_pass = "";
2084
2085         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2086                                                 &p_pass, error);
2087
2088 }
2089
2090
2091 dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter,
2092                                            DBusError *error, void *user_data)
2093 {
2094         struct wpa_supplicant *wpa_s = user_data;
2095         u8 role = wpas_get_p2p_role(wpa_s);
2096         u8 *p_psk = NULL;
2097         u8 psk_len = 0;
2098
2099         /* Verify correct role for this property */
2100         if (role == WPAS_P2P_ROLE_CLIENT) {
2101                 if (wpa_s->current_ssid == NULL)
2102                         return FALSE;
2103                 p_psk = wpa_s->current_ssid->psk;
2104                 psk_len = 32;
2105         }
2106
2107         return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
2108                                                       &p_psk, psk_len, error);
2109 }
2110
2111
2112 dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter,
2113                                                   DBusError *error,
2114                                                   void *user_data)
2115 {
2116         struct wpa_supplicant *wpa_s = user_data;
2117         struct hostapd_data *hapd;
2118         struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
2119         unsigned int i, num_vendor_ext = 0;
2120
2121         os_memset(vendor_ext, 0, sizeof(vendor_ext));
2122
2123         /* Verify correct role for this property */
2124         if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) {
2125                 if (wpa_s->ap_iface == NULL)
2126                         return FALSE;
2127                 hapd = wpa_s->ap_iface->bss[0];
2128
2129                 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
2130                 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2131                         if (hapd->conf->wps_vendor_ext[i] == NULL)
2132                                 continue;
2133                         vendor_ext[num_vendor_ext++] =
2134                                 hapd->conf->wps_vendor_ext[i];
2135                 }
2136         }
2137
2138         /* Return vendor extensions or no data */
2139         return wpas_dbus_simple_array_array_property_getter(iter,
2140                                                             DBUS_TYPE_BYTE,
2141                                                             vendor_ext,
2142                                                             num_vendor_ext,
2143                                                             error);
2144 }
2145
2146
2147 dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter,
2148                                                   DBusError *error,
2149                                                   void *user_data)
2150 {
2151         struct wpa_supplicant *wpa_s = user_data;
2152         DBusMessageIter variant_iter, iter_dict;
2153         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
2154         unsigned int i;
2155         struct hostapd_data *hapd = NULL;
2156
2157         if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO &&
2158             wpa_s->ap_iface != NULL)
2159                 hapd = wpa_s->ap_iface->bss[0];
2160         else
2161                 return FALSE;
2162
2163         dbus_message_iter_recurse(iter, &variant_iter);
2164         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
2165                 return FALSE;
2166
2167         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2168                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
2169                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2170                                              "invalid message format");
2171                         return FALSE;
2172                 }
2173
2174                 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
2175                         if (entry.type != DBUS_TYPE_ARRAY ||
2176                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
2177                             entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
2178                                 goto error;
2179
2180                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
2181                                 if (i < entry.array_len) {
2182                                         hapd->conf->wps_vendor_ext[i] =
2183                                                 entry.binarray_value[i];
2184                                         entry.binarray_value[i] = NULL;
2185                                 } else
2186                                         hapd->conf->wps_vendor_ext[i] = NULL;
2187                         }
2188
2189                         hostapd_update_wps(hapd);
2190                 } else
2191                         goto error;
2192
2193                 wpa_dbus_dict_entry_clear(&entry);
2194         }
2195
2196         return TRUE;
2197
2198 error:
2199         wpa_dbus_dict_entry_clear(&entry);
2200         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
2201                              "invalid message format");
2202         return FALSE;
2203 }
2204
2205
2206 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
2207                                                 struct wpa_supplicant *wpa_s)
2208 {
2209         DBusMessageIter iter_dict;
2210         DBusMessage *reply = NULL;
2211         DBusMessageIter iter;
2212         struct wpa_dbus_dict_entry entry;
2213         int upnp = 0;
2214         int bonjour = 0;
2215         char *service = NULL;
2216         struct wpabuf *query = NULL;
2217         struct wpabuf *resp = NULL;
2218         u8 version = 0;
2219
2220         dbus_message_iter_init(message, &iter);
2221
2222         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2223                 goto error;
2224
2225         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2226                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2227                         goto error;
2228
2229                 if (!os_strcmp(entry.key, "service_type") &&
2230                     (entry.type == DBUS_TYPE_STRING)) {
2231                         if (!os_strcmp(entry.str_value, "upnp"))
2232                                 upnp = 1;
2233                         else if (!os_strcmp(entry.str_value, "bonjour"))
2234                                 bonjour = 1;
2235                         else
2236                                 goto error_clear;
2237                 } else if (!os_strcmp(entry.key, "version") &&
2238                            entry.type == DBUS_TYPE_INT32) {
2239                         version = entry.uint32_value;
2240                 } else if (!os_strcmp(entry.key, "service") &&
2241                              (entry.type == DBUS_TYPE_STRING)) {
2242                         service = os_strdup(entry.str_value);
2243                 } else if (!os_strcmp(entry.key, "query")) {
2244                         if ((entry.type != DBUS_TYPE_ARRAY) ||
2245                             (entry.array_type != DBUS_TYPE_BYTE))
2246                                 goto error_clear;
2247                         query = wpabuf_alloc_copy(
2248                                 entry.bytearray_value,
2249                                 entry.array_len);
2250                 } else if (!os_strcmp(entry.key, "response")) {
2251                         if ((entry.type != DBUS_TYPE_ARRAY) ||
2252                             (entry.array_type != DBUS_TYPE_BYTE))
2253                                 goto error_clear;
2254                         resp = wpabuf_alloc_copy(entry.bytearray_value,
2255                                                  entry.array_len);
2256                 }
2257                 wpa_dbus_dict_entry_clear(&entry);
2258         }
2259
2260         if (upnp == 1) {
2261                 if (version <= 0 || service == NULL)
2262                         goto error;
2263
2264                 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
2265                         goto error;
2266
2267                 os_free(service);
2268                 service = NULL;
2269         } else if (bonjour == 1) {
2270                 if (query == NULL || resp == NULL)
2271                         goto error;
2272
2273                 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0)
2274                         goto error;
2275                 query = NULL;
2276                 resp = NULL;
2277         } else
2278                 goto error;
2279
2280         return reply;
2281 error_clear:
2282         wpa_dbus_dict_entry_clear(&entry);
2283 error:
2284         os_free(service);
2285         wpabuf_free(query);
2286         wpabuf_free(resp);
2287         return wpas_dbus_error_invalid_args(message, NULL);
2288 }
2289
2290
2291 DBusMessage * wpas_dbus_handler_p2p_delete_service(
2292         DBusMessage *message, struct wpa_supplicant *wpa_s)
2293 {
2294         DBusMessageIter iter_dict;
2295         DBusMessage *reply = NULL;
2296         DBusMessageIter iter;
2297         struct wpa_dbus_dict_entry entry;
2298         int upnp = 0;
2299         int bonjour = 0;
2300         int ret = 0;
2301         char *service = NULL;
2302         struct wpabuf *query = NULL;
2303         u8 version = 0;
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         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2311                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2312                         goto error;
2313
2314                 if (!os_strcmp(entry.key, "service_type") &&
2315                     (entry.type == DBUS_TYPE_STRING)) {
2316                         if (!os_strcmp(entry.str_value, "upnp"))
2317                                 upnp = 1;
2318                         else if (!os_strcmp(entry.str_value, "bonjour"))
2319                                 bonjour = 1;
2320                         else
2321                                 goto error_clear;
2322                         wpa_dbus_dict_entry_clear(&entry);
2323                 }
2324         }
2325         if (upnp == 1) {
2326                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2327                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2328                                 goto error;
2329                         if (!os_strcmp(entry.key, "version") &&
2330                             entry.type == DBUS_TYPE_INT32)
2331                                 version = entry.uint32_value;
2332                         else if (!os_strcmp(entry.key, "service") &&
2333                                  entry.type == DBUS_TYPE_STRING)
2334                                 service = os_strdup(entry.str_value);
2335                         else
2336                                 goto error_clear;
2337
2338                         wpa_dbus_dict_entry_clear(&entry);
2339                 }
2340
2341                 if (version <= 0 || service == NULL)
2342                         goto error;
2343
2344                 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
2345                 os_free(service);
2346                 if (ret != 0)
2347                         goto error;
2348         } else if (bonjour == 1) {
2349                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2350                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2351                                 goto error;
2352
2353                         if (!os_strcmp(entry.key, "query")) {
2354                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
2355                                     (entry.array_type != DBUS_TYPE_BYTE))
2356                                         goto error_clear;
2357                                 query = wpabuf_alloc_copy(
2358                                         entry.bytearray_value,
2359                                         entry.array_len);
2360                         } else
2361                                 goto error_clear;
2362
2363                         wpa_dbus_dict_entry_clear(&entry);
2364                 }
2365
2366                 if (query == NULL)
2367                         goto error;
2368
2369                 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
2370                 if (ret != 0)
2371                         goto error;
2372                 wpabuf_free(query);
2373         } else
2374                 goto error;
2375
2376         return reply;
2377 error_clear:
2378         wpa_dbus_dict_entry_clear(&entry);
2379 error:
2380         return wpas_dbus_error_invalid_args(message, NULL);
2381 }
2382
2383
2384 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
2385                                                   struct wpa_supplicant *wpa_s)
2386 {
2387         wpas_p2p_service_flush(wpa_s);
2388         return NULL;
2389 }
2390
2391
2392 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
2393         DBusMessage *message, struct wpa_supplicant *wpa_s)
2394 {
2395         DBusMessageIter iter_dict;
2396         DBusMessage *reply = NULL;
2397         DBusMessageIter iter;
2398         struct wpa_dbus_dict_entry entry;
2399         int upnp = 0;
2400         char *service = NULL;
2401         char *peer_object_path = NULL;
2402         struct wpabuf *tlv = NULL;
2403         u8 version = 0;
2404         u64 ref = 0;
2405         u8 addr_buf[ETH_ALEN], *addr;
2406
2407         dbus_message_iter_init(message, &iter);
2408
2409         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2410                 goto error;
2411
2412         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2413                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2414                         goto error;
2415                 if (!os_strcmp(entry.key, "peer_object") &&
2416                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2417                         peer_object_path = os_strdup(entry.str_value);
2418                 } else if (!os_strcmp(entry.key, "service_type") &&
2419                            entry.type == DBUS_TYPE_STRING) {
2420                         if (!os_strcmp(entry.str_value, "upnp"))
2421                                 upnp = 1;
2422                         else
2423                                 goto error_clear;
2424                 } else if (!os_strcmp(entry.key, "version") &&
2425                            entry.type == DBUS_TYPE_INT32) {
2426                         version = entry.uint32_value;
2427                 } else if (!os_strcmp(entry.key, "service") &&
2428                            entry.type == DBUS_TYPE_STRING) {
2429                         service = os_strdup(entry.str_value);
2430                 } else if (!os_strcmp(entry.key, "tlv")) {
2431                         if (entry.type != DBUS_TYPE_ARRAY ||
2432                             entry.array_type != DBUS_TYPE_BYTE)
2433                                 goto error_clear;
2434                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2435                                                 entry.array_len);
2436                 } else
2437                         goto error_clear;
2438
2439                 wpa_dbus_dict_entry_clear(&entry);
2440         }
2441
2442         if (!peer_object_path) {
2443                 addr = NULL;
2444         } else {
2445                 if (parse_peer_object_path(peer_object_path, addr_buf) < 0 ||
2446                     !p2p_peer_known(wpa_s->global->p2p, addr_buf))
2447                         goto error;
2448
2449                 addr = addr_buf;
2450         }
2451
2452         if (upnp == 1) {
2453                 if (version <= 0 || service == NULL)
2454                         goto error;
2455
2456                 ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
2457         } else {
2458                 if (tlv == NULL)
2459                         goto error;
2460                 ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
2461                 wpabuf_free(tlv);
2462         }
2463
2464         if (ref != 0) {
2465                 reply = dbus_message_new_method_return(message);
2466                 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2467                                          &ref, DBUS_TYPE_INVALID);
2468         } else {
2469                 reply = wpas_dbus_error_unknown_error(
2470                         message, "Unable to send SD request");
2471         }
2472 out:
2473         os_free(service);
2474         os_free(peer_object_path);
2475         return reply;
2476 error_clear:
2477         wpa_dbus_dict_entry_clear(&entry);
2478 error:
2479         if (tlv)
2480                 wpabuf_free(tlv);
2481         reply = wpas_dbus_error_invalid_args(message, NULL);
2482         goto out;
2483 }
2484
2485
2486 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2487         DBusMessage *message, struct wpa_supplicant *wpa_s)
2488 {
2489         DBusMessageIter iter_dict;
2490         DBusMessage *reply = NULL;
2491         DBusMessageIter iter;
2492         struct wpa_dbus_dict_entry entry;
2493         char *peer_object_path = NULL;
2494         struct wpabuf *tlv = NULL;
2495         int freq = 0;
2496         int dlg_tok = 0;
2497         u8 addr[ETH_ALEN];
2498
2499         dbus_message_iter_init(message, &iter);
2500
2501         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2502                 goto error;
2503
2504         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2505                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2506                         goto error;
2507
2508                 if (!os_strcmp(entry.key, "peer_object") &&
2509                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2510                         peer_object_path = os_strdup(entry.str_value);
2511                 } else if (!os_strcmp(entry.key, "frequency") &&
2512                            entry.type == DBUS_TYPE_INT32) {
2513                         freq = entry.uint32_value;
2514                 } else if (!os_strcmp(entry.key, "dialog_token") &&
2515                            entry.type == DBUS_TYPE_UINT32) {
2516                         dlg_tok = entry.uint32_value;
2517                 } else if (!os_strcmp(entry.key, "tlvs")) {
2518                         if (entry.type != DBUS_TYPE_ARRAY ||
2519                             entry.array_type != DBUS_TYPE_BYTE)
2520                                 goto error_clear;
2521                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2522                                                 entry.array_len);
2523                 } else
2524                         goto error_clear;
2525
2526                 wpa_dbus_dict_entry_clear(&entry);
2527         }
2528         if (!peer_object_path ||
2529             (parse_peer_object_path(peer_object_path, addr) < 0) ||
2530             !p2p_peer_known(wpa_s->global->p2p, addr))
2531                 goto error;
2532
2533         if (tlv == NULL)
2534                 goto error;
2535
2536         wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2537         wpabuf_free(tlv);
2538 out:
2539         os_free(peer_object_path);
2540         return reply;
2541 error_clear:
2542         wpa_dbus_dict_entry_clear(&entry);
2543 error:
2544         reply = wpas_dbus_error_invalid_args(message, NULL);
2545         goto out;
2546 }
2547
2548
2549 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2550         DBusMessage *message, struct wpa_supplicant *wpa_s)
2551 {
2552         DBusMessageIter iter;
2553         u64 req = 0;
2554
2555         dbus_message_iter_init(message, &iter);
2556         dbus_message_iter_get_basic(&iter, &req);
2557
2558         if (req == 0)
2559                 goto error;
2560
2561         if (wpas_p2p_sd_cancel_request(wpa_s, req) < 0)
2562                 goto error;
2563
2564         return NULL;
2565 error:
2566         return wpas_dbus_error_invalid_args(message, NULL);
2567 }
2568
2569
2570 DBusMessage * wpas_dbus_handler_p2p_service_update(
2571         DBusMessage *message, struct wpa_supplicant *wpa_s)
2572 {
2573         wpas_p2p_sd_service_update(wpa_s);
2574         return NULL;
2575 }
2576
2577
2578 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2579         DBusMessage *message, struct wpa_supplicant *wpa_s)
2580 {
2581         DBusMessageIter iter;
2582         int ext = 0;
2583
2584         dbus_message_iter_init(message, &iter);
2585         dbus_message_iter_get_basic(&iter, &ext);
2586
2587         wpa_s->p2p_sd_over_ctrl_iface = ext;
2588
2589         return NULL;
2590
2591 }