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