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