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