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