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