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