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