DBus: Add support for P2P primitives
[mech_eap.git] / wpa_supplicant / dbus / dbus_new_handlers_p2p.c
1 /*
2  * WPA Supplicant / dbus-based control interface (P2P)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * Alternatively, this software may be distributed under the terms of BSD
9  * license.
10  *
11  * See README and COPYING for more details.
12  */
13
14 #include "includes.h"
15
16 #include "utils/includes.h"
17 #include "common.h"
18 #include "../config.h"
19 #include "../wpa_supplicant_i.h"
20 #include "../wps_supplicant.h"
21 #include "dbus_new_helpers.h"
22 #include "dbus_new.h"
23 #include "dbus_new_handlers.h"
24 #include "dbus_new_handlers_p2p.h"
25 #include "dbus_dict_helpers.h"
26 #include "p2p/p2p.h"
27 #include "common/ieee802_11_defs.h"
28 #include "ap/hostapd.h"
29 #include "ap/ap_config.h"
30 #include "ap/wps_hostapd.h"
31
32 #include "../p2p_supplicant.h"
33
34 /**
35  * Parses out the mac address from the peer object path.
36  * @peer_path - object path of the form
37  *      /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
38  * @addr - out param must be of ETH_ALEN size
39  * Returns 0 if valid (including MAC), -1 otherwise
40  */
41 static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
42 {
43         char *p;
44
45         if (!peer_path)
46                 return -1;
47         p = strrchr(peer_path, '/');
48         if (!p)
49                 return -1;
50         p++;
51         return hwaddr_compact_aton(p, addr);
52 }
53
54 DBusMessage *wpas_dbus_handler_p2p_find(DBusMessage * message,
55                                         struct wpa_supplicant * wpa_s)
56 {
57         struct wpa_dbus_dict_entry entry;
58         DBusMessage *reply = NULL;
59         DBusMessageIter iter;
60         DBusMessageIter iter_dict;
61         unsigned int timeout = 0;
62         unsigned int searchonly = 0;
63         enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
64         int num_req_dev_types = 0;
65         unsigned int i;
66         u8 *req_dev_types = NULL;
67
68         dbus_message_iter_init(message, &iter);
69
70         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
71                 goto error;
72
73         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
74                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
75                         goto error;
76
77                 if (!os_strcmp(entry.key, "Timeout") &&
78                     (entry.type == DBUS_TYPE_INT32)) {
79                         timeout = entry.uint32_value;
80                 } else if (!os_strcmp(entry.key, "SearchOnly") &&
81                            (entry.type == DBUS_TYPE_BOOLEAN)) {
82                         searchonly = (entry.bool_value == TRUE) ? 1 : 0;
83                 } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
84                         if ((entry.type != DBUS_TYPE_ARRAY) ||
85                             (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
86                                 goto error_clear;
87
88                         req_dev_types =
89                                 os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
90                         if (!req_dev_types)
91                                 goto error_clear;
92
93                         for (i = 0; i < entry.array_len; i++) {
94                                 if (wpabuf_len(entry.binarray_value[i]) !=
95                                                         WPS_DEV_TYPE_LEN)
96                                         goto error_clear;
97                                 os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
98                                           wpabuf_head(entry.binarray_value[i]),
99                                           WPS_DEV_TYPE_LEN);
100                         }
101
102                         num_req_dev_types = entry.array_len;
103                 } else
104                         goto error_clear;
105                 wpa_dbus_dict_entry_clear(&entry);
106         }
107
108         wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
109         return reply;
110
111 error_clear:
112         os_free(req_dev_types);
113         wpa_dbus_dict_entry_clear(&entry);
114 error:
115         reply = wpas_dbus_error_invalid_args(message, entry.key);
116         return reply;
117 }
118
119 DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message,
120                                              struct wpa_supplicant * wpa_s)
121 {
122         wpas_p2p_stop_find(wpa_s);
123         return NULL;
124 }
125
126 DBusMessage *wpas_dbus_handler_p2p_rejectpeer(DBusMessage * message,
127                                               struct wpa_supplicant * wpa_s)
128 {
129         DBusMessageIter iter;
130         char *peer_object_path = NULL;
131         u8 peer_addr[ETH_ALEN];
132
133         dbus_message_iter_init(message, &iter);
134         dbus_message_iter_get_basic(&iter, &peer_object_path);
135
136         if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
137                 return wpas_dbus_error_invalid_args(message, NULL);
138
139         if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
140                 return wpas_dbus_error_unknown_error(message,
141                                 "Failed to call wpas_p2p_reject method.");
142
143         return NULL;
144 }
145
146 DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message,
147                                           struct wpa_supplicant * wpa_s)
148 {
149         dbus_int32_t timeout = 0;
150
151         if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
152                                    DBUS_TYPE_INVALID))
153                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
154                                               NULL);
155
156         if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
157                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
158                                               NULL);
159
160         return NULL;
161 }
162
163 DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message,
164                                                   struct wpa_supplicant * wpa_s)
165 {
166         unsigned int period = 0, interval = 0;
167         struct wpa_dbus_dict_entry entry;
168         DBusMessageIter iter;
169         DBusMessageIter iter_dict;
170
171         dbus_message_iter_init(message, &iter);
172
173         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
174                 goto error;
175
176         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
177                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
178                         goto error;
179
180                 if (!strcmp(entry.key, "period") &&
181                     (entry.type == DBUS_TYPE_INT32))
182                         period = entry.uint32_value;
183                 else if (!strcmp(entry.key, "interval") &&
184                          (entry.type == DBUS_TYPE_INT32))
185                         interval = entry.uint32_value;
186                 else
187                         goto error_clear;
188                 wpa_dbus_dict_entry_clear(&entry);
189         }
190
191         if (wpas_p2p_ext_listen(wpa_s, period, interval))
192                 return wpas_dbus_error_unknown_error(message,
193                                         "failed to initiate a p2p_ext_listen.");
194
195         return NULL;
196
197 error_clear:
198         wpa_dbus_dict_entry_clear(&entry);
199 error:
200         return wpas_dbus_error_invalid_args(message, entry.key);
201 }
202
203 DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message,
204                                                     struct wpa_supplicant *
205                                                     wpa_s)
206 {
207         unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
208         struct wpa_dbus_dict_entry entry;
209         DBusMessageIter iter;
210         DBusMessageIter iter_dict;
211
212         dbus_message_iter_init(message, &iter);
213
214         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
215                 goto error;
216
217         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
218                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
219                         goto error;
220
221                 if (!strcmp(entry.key, "duration1") &&
222                     (entry.type == DBUS_TYPE_INT32))
223                         dur1 = entry.uint32_value;
224                 else if (!strcmp(entry.key, "interval1") &&
225                          entry.type == DBUS_TYPE_INT32)
226                         int1 = entry.uint32_value;
227                 else if (!strcmp(entry.key, "duration2") &&
228                          entry.type == DBUS_TYPE_INT32)
229                         dur2 = entry.uint32_value;
230                 else if (!strcmp(entry.key, "interval2") &&
231                          entry.type == DBUS_TYPE_INT32)
232                         int2 = entry.uint32_value;
233                 else
234                         goto error_clear;
235
236                 wpa_dbus_dict_entry_clear(&entry);
237         }
238         if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
239                 return wpas_dbus_error_unknown_error(message,
240                                 "Failed to invoke presence request.");
241
242         return NULL;
243
244 error_clear:
245         wpa_dbus_dict_entry_clear(&entry);
246 error:
247         return wpas_dbus_error_invalid_args(message, entry.key);
248 }
249
250 DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message,
251                                              struct wpa_supplicant * wpa_s)
252 {
253         DBusMessageIter iter_dict;
254         DBusMessage *reply = NULL;
255         DBusMessageIter iter;
256         struct wpa_dbus_dict_entry entry;
257         char *network_object_path = NULL;
258         int persistent_group = 0;
259         int freq = 0;
260         char *iface = NULL;
261         char *net_id_str = NULL;
262         unsigned int group_id = 0;
263         struct wpa_ssid *ssid;
264
265         dbus_message_iter_init(message, &iter);
266
267         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
268                 goto inv_args;
269
270         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
271                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
272                         goto inv_args;
273
274                 if (!strcmp(entry.key, "persistent") &&
275                     (entry.type == DBUS_TYPE_BOOLEAN)) {
276                         persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
277                 } else if (!strcmp(entry.key, "frequency") &&
278                            (entry.type == DBUS_TYPE_INT32)) {
279                         freq = entry.int32_value;
280                         if (freq <= 0)
281                                 goto inv_args_clear;
282                 } else if (!strcmp(entry.key, "network_object") &&
283                            entry.type == DBUS_TYPE_OBJECT_PATH)
284                         network_object_path = os_strdup(entry.str_value);
285                 else
286                         goto inv_args_clear;
287
288                 wpa_dbus_dict_entry_clear(&entry);
289         }
290
291         if (network_object_path != NULL) {
292                 /*
293                  * A Network Object Path is defined meaning we want to re-invoke
294                  * a persisatnt group.
295                  */
296
297                 iface = wpas_dbus_new_decompose_object_path(network_object_path,
298                                                             &net_id_str, NULL);
299                 if (iface == NULL ||
300                     os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
301                         reply =
302                             wpas_dbus_error_invalid_args(message,
303                                                          network_object_path);
304                         goto out;
305                 }
306
307                 group_id = strtoul(net_id_str, NULL, 10);
308                 if (errno == EINVAL) {
309                         reply = wpas_dbus_error_invalid_args(
310                                                 message, network_object_path);
311                         goto out;
312                 }
313
314                 /* Get the SSID structure form the persistant group id */
315                 ssid = wpa_config_get_network(wpa_s->conf, group_id);
316                 if (ssid == NULL || ssid->disabled != 2)
317                         goto inv_args;
318
319                 if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
320                         reply = wpas_dbus_error_unknown_error(message,
321                                                               "Failed to reinvoke a persistent group");
322                         goto out;
323                 }
324         } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
325                 goto inv_args;
326
327 out:
328         os_free(network_object_path);
329         os_free(net_id_str);
330         os_free(iface);
331         return reply;
332 inv_args_clear:
333         wpa_dbus_dict_entry_clear(&entry);
334 inv_args:
335         reply = wpas_dbus_error_invalid_args(message, NULL);
336         goto out;
337 }
338
339 DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
340                                               struct wpa_supplicant *wpa_s)
341 {
342         if (wpas_p2p_disconnect(wpa_s))
343                 return wpas_dbus_error_unknown_error(message,
344                                                 "failed to disconnect");
345
346         return NULL;
347 }
348
349 DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message,
350                                          struct wpa_supplicant * wpa_s)
351 {
352         os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
353         wpa_s->force_long_sd = 0;
354         p2p_flush(wpa_s->global->p2p);
355
356         return NULL;
357 }
358
359 DBusMessage *wpas_dbus_handler_p2p_connect(DBusMessage * message,
360                                            struct wpa_supplicant * wpa_s)
361 {
362         DBusMessageIter iter_dict;
363         DBusMessage *reply = NULL;
364         DBusMessageIter iter;
365         struct wpa_dbus_dict_entry entry;
366         char *peer_object_path = NULL;
367         int persistent_group = 0;
368         int join = 0;
369         int authorize_only = 0;
370         int go_intent = -1;
371         int freq = 0;
372         u8 addr[ETH_ALEN];
373         char *pin = NULL;
374         enum p2p_wps_method wps_method = WPS_NOT_READY;
375         int new_pin;
376         char *err_msg = NULL;
377         char *iface = NULL;
378
379         dbus_message_iter_init(message, &iter);
380
381         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
382                 goto inv_args;
383
384         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
385                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
386                         goto inv_args;
387
388                 if (!strcmp(entry.key, "peer") &&
389                     (entry.type == DBUS_TYPE_OBJECT_PATH)) {
390                         peer_object_path = os_strdup(entry.str_value);
391                 } else if (!strcmp(entry.key, "persistent") &&
392                            (entry.type == DBUS_TYPE_BOOLEAN)) {
393                         persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
394                 } else if (!strcmp(entry.key, "join") &&
395                            (entry.type == DBUS_TYPE_BOOLEAN)) {
396                         join = (entry.bool_value == TRUE) ? 1 : 0;
397                 } else if (!strcmp(entry.key, "authorize_only") &&
398                            (entry.type == DBUS_TYPE_BOOLEAN)) {
399                         authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
400                 } else if (!strcmp(entry.key, "frequency") &&
401                            (entry.type == DBUS_TYPE_INT32)) {
402                         freq = entry.int32_value;
403                         if (freq <= 0)
404                                 goto inv_args_clear;
405                 } else if (!strcmp(entry.key, "go_intent") &&
406                            (entry.type == DBUS_TYPE_INT32)) {
407                         go_intent = entry.int32_value;
408                         if ((go_intent < 0) || (go_intent > 15))
409                                 goto inv_args_clear;
410                 } else if (!strcmp(entry.key, "wps_method") &&
411                            (entry.type == DBUS_TYPE_STRING)) {
412                         if (!strcmp(entry.str_value, "pbc"))
413                                 wps_method = WPS_PBC;
414                         else if (!strcmp(entry.str_value, "pin"))
415                                 wps_method = WPS_PIN_DISPLAY;
416                         else if (!strcmp(entry.str_value, "label"))
417                                 wps_method = WPS_PIN_LABEL;
418                         else if (!strcmp(entry.str_value, "display"))
419                                 wps_method = WPS_PIN_DISPLAY;
420                         else if (!strcmp(entry.str_value, "keypad"))
421                                 wps_method = WPS_PIN_KEYPAD;
422                         else
423                                 goto inv_args_clear;
424                 } else if (!strcmp(entry.key, "pin") &&
425                            (entry.type == DBUS_TYPE_STRING)) {
426                         pin = os_strdup(entry.str_value);
427                 } else
428                         goto inv_args_clear;
429
430                 wpa_dbus_dict_entry_clear(&entry);
431         }
432
433         if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
434             (parse_peer_object_path(peer_object_path, addr) < 0) ||
435             (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) {
436                 reply = wpas_dbus_error_invalid_args(message, NULL);
437                 goto inv_args;
438         }
439
440         /*
441          * Validate the wps_method specified and the pin value.
442          */
443         if ((!pin || !pin[0]) &&
444             ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
445                 goto inv_args;
446
447         new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
448                                    persistent_group, join, authorize_only,
449                                    go_intent, freq);
450
451         if (new_pin >= 0) {
452                 reply = dbus_message_new_method_return(message);
453                 dbus_message_append_args(reply, DBUS_TYPE_INT32,
454                                          &new_pin, DBUS_TYPE_INVALID);
455         } else {
456                 switch (new_pin) {
457                 case -2:
458                         err_msg = "connect failed due to"
459                                         " channel unavailability.";
460                         iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
461                         break;
462
463                 case -3:
464                         err_msg = "connect failed due to"
465                                         " unsupported channel.";
466                         iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
467                         break;
468
469                 default:
470                         err_msg = "connect failed due to"
471                                         " unspecified error.";
472                         iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
473                         break;
474                 }
475                 /*
476                  * TODO::
477                  * Do we need specialized errors corresponding to above
478                  * error conditions as against just returning a different
479                  * error message?
480                  */
481                 reply = dbus_message_new_error(message, iface, err_msg);
482         }
483
484 out:
485         os_free(peer_object_path);
486         os_free(pin);
487         return reply;
488 inv_args_clear:
489         wpa_dbus_dict_entry_clear(&entry);
490 inv_args:
491         reply = wpas_dbus_error_invalid_args(message, NULL);
492         goto out;
493 }
494
495 DBusMessage *wpas_dbus_handler_p2p_invite(DBusMessage * message,
496                                           struct wpa_supplicant *wpa_s)
497 {
498         DBusMessageIter iter_dict;
499         DBusMessage *reply = NULL;
500         DBusMessageIter iter;
501         struct wpa_dbus_dict_entry entry;
502         char *peer_object_path = NULL;
503         char *network_object_path = NULL;
504         char *iface = NULL;
505         char *net_id_str = NULL;
506         u8 peer_addr[ETH_ALEN];
507         unsigned int group_id = 0;
508         int persistent = 0;
509         struct wpa_ssid *ssid;
510
511         dbus_message_iter_init(message, &iter);
512
513         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
514                 goto err;
515
516         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
517                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
518                         goto err;
519
520                 if (!strcmp(entry.key, "peer") &&
521                     (entry.type == DBUS_TYPE_OBJECT_PATH)) {
522                         peer_object_path = os_strdup(entry.str_value);
523                         wpa_dbus_dict_entry_clear(&entry);
524                 } else if (!strcmp(entry.key, "network_object") &&
525                            (entry.type == DBUS_TYPE_OBJECT_PATH)) {
526                         network_object_path = os_strdup(entry.str_value);
527                         persistent = 1;
528                         wpa_dbus_dict_entry_clear(&entry);
529                 } else {
530                         wpa_dbus_dict_entry_clear(&entry);
531                         goto err;
532                 }
533         }
534
535         if (!peer_object_path ||
536             (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
537             (p2p_get_peer_info(wpa_s->global->p2p,
538                                peer_addr, 0, NULL, 0) < 0)) {
539                 goto err;
540         }
541
542         if (persistent) {
543                 /*
544                  * A group ID is defined meaning we want to re-invoke a
545                  * persisatnt group
546                  */
547
548                 iface = wpas_dbus_new_decompose_object_path(network_object_path,
549                                                             &net_id_str, NULL);
550                 if (iface == NULL ||
551                     os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
552                         reply =
553                             wpas_dbus_error_invalid_args(message,
554                                                          network_object_path);
555                         goto out;
556                 }
557
558                 group_id = strtoul(net_id_str, NULL, 10);
559                 if (errno == EINVAL) {
560                         reply = wpas_dbus_error_invalid_args(
561                                                 message, network_object_path);
562                         goto out;
563                 }
564
565                 /* Get the SSID structure form the persistant group id */
566                 ssid = wpa_config_get_network(wpa_s->conf, group_id);
567                 if (ssid == NULL || ssid->disabled != 2)
568                         goto err;
569
570                 if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
571                         reply = wpas_dbus_error_unknown_error(
572                                         message,
573                                         "Failed to reinvoke a persistent group");
574                         goto out;
575                 }
576         } else {
577                 /*
578                  * No group ID means propose to a peer to join my active group
579                  */
580                 if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
581                                          peer_addr, NULL)) {
582                         reply = wpas_dbus_error_unknown_error(
583                                         message,
584                                         "Failed to join to an active group");
585                         goto out;
586                 }
587         }
588
589 out:
590         os_free(network_object_path);
591         os_free(peer_object_path);
592         return reply;
593
594 err:
595         reply = wpas_dbus_error_invalid_args(message, NULL);
596         goto out;
597 }
598
599 DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message,
600                                                  struct wpa_supplicant *wpa_s)
601 {
602         DBusMessageIter iter;
603         char *peer_object_path = NULL;
604         char *config_method = NULL;
605         u8 peer_addr[ETH_ALEN];
606
607         dbus_message_iter_init(message, &iter);
608         dbus_message_iter_get_basic(&iter, &peer_object_path);
609
610         if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
611                 return wpas_dbus_error_invalid_args(message, NULL);
612
613         dbus_message_iter_next(&iter);
614         dbus_message_iter_get_basic(&iter, &config_method);
615
616         /*
617          * Validation checks on config_method are being duplicated here
618          * to be able to return invalid args reply since the error code
619          * from p2p module are not granular enough (yet).
620          */
621         if (os_strcmp(config_method, "display") &&
622             os_strcmp(config_method, "keypad") &&
623             os_strcmp(config_method, "pbc") &&
624             os_strcmp(config_method, "pushbutton"))
625                 return wpas_dbus_error_invalid_args(message, NULL);
626
627         if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
628                 return wpas_dbus_error_unknown_error(message,
629                                 "Failed to send provision discovery request");
630
631         return NULL;
632 }
633
634 /*
635  * P2P Device property accessor methods.
636  */
637
638 DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message,
639                                                     struct wpa_supplicant *
640                                                     wpa_s)
641 {
642         DBusMessage *reply = NULL;
643         DBusMessageIter iter, variant_iter, dict_iter;
644         const char *dev_name;
645         int num_sec_dev_types = 0;
646         int num_vendor_extensions = 0;
647         int i;
648         const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
649
650         if (message == NULL)
651                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
652         else
653                 reply = dbus_message_new_method_return(message);
654
655         if (!reply)
656                 goto err_no_mem;
657
658         dbus_message_iter_init_append(reply, &iter);
659
660         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
661                                               "a{sv}", &variant_iter) ||
662             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
663                 goto err_no_mem;
664
665         /* DeviceName */
666         dev_name = wpa_s->conf->device_name;
667         if (dev_name &&
668             !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
669                 goto err_no_mem;
670
671         /* Primary device type */
672         if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
673                                              (char *)wpa_s->conf->device_type,
674                                              WPS_DEV_TYPE_LEN))
675                 goto err_no_mem;
676
677         /* Secondary device types */
678         for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) {
679                 if (wpa_s->conf->sec_device_type[i] == NULL)
680                         break;
681                 num_sec_dev_types++;
682         }
683
684         if (!wpa_dbus_dict_append_string_array(
685                         &dict_iter, "SecondaryDeviceTypes",
686                         (const char **)wpa_s->conf->sec_device_type,
687                         num_sec_dev_types))
688                 goto err_no_mem;
689
690         /* Vendor Extensions */
691         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
692                 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
693                         continue;
694                 vendor_ext[num_vendor_extensions++] =
695                         wpa_s->conf->wps_vendor_ext[i];
696         }
697
698         if (num_vendor_extensions &&
699             !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
700                                                "VendorExtension",
701                                                vendor_ext,
702                                                num_vendor_extensions))
703                 goto err_no_mem;
704
705         /* GO Intent */
706         if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
707                                          wpa_s->conf->p2p_go_intent))
708                 goto err_no_mem;
709
710         /* Persistant Reconnect */
711         if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
712                                        wpa_s->conf->persistent_reconnect))
713                 goto err_no_mem;
714
715         /* Listen Reg Class */
716         if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
717                                          wpa_s->conf->p2p_listen_reg_class))
718                 goto err_no_mem;
719
720         /* Listen Channel */
721         if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
722                                          wpa_s->conf->p2p_listen_channel))
723                 goto err_no_mem;
724
725         /* Oper Reg Class */
726         if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
727                                          wpa_s->conf->p2p_oper_reg_class))
728                 goto err_no_mem;
729
730         /* Oper Channel */
731         if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
732                                          wpa_s->conf->p2p_oper_channel))
733                 goto err_no_mem;
734
735         /* SSID Postfix */
736         if (wpa_s->conf->p2p_ssid_postfix &&
737             !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
738                                          wpa_s->conf->p2p_ssid_postfix))
739                 goto err_no_mem;
740
741         /* Intra Bss */
742         if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
743                                        wpa_s->conf->p2p_intra_bss))
744                 goto err_no_mem;
745
746         /* Group Idle */
747         if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
748                                          wpa_s->conf->p2p_group_idle))
749                 goto err_no_mem;
750
751         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
752             !dbus_message_iter_close_container(&iter, &variant_iter))
753                 goto err_no_mem;
754
755         return reply;
756 err_no_mem:
757         dbus_message_unref(reply);
758         return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
759 }
760
761 DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
762                                                     struct wpa_supplicant *
763                                                     wpa_s)
764 {
765         DBusMessage *reply = NULL;
766         DBusMessageIter iter, variant_iter;
767         struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
768         DBusMessageIter iter_dict;
769         unsigned int i;
770
771         dbus_message_iter_init(message, &iter);
772
773         dbus_message_iter_next(&iter);
774         dbus_message_iter_next(&iter);
775
776         dbus_message_iter_recurse(&iter, &variant_iter);
777
778         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
779                 return wpas_dbus_error_invalid_args(message, NULL);
780
781         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
782                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
783                         return wpas_dbus_error_invalid_args(message, NULL);
784
785                 if (os_strcmp(entry.key, "DeviceName") == 0) {
786                         char *devname;
787
788                         if (entry.type != DBUS_TYPE_STRING)
789                                 goto error_clear;
790
791                         devname = os_strdup(entry.str_value);
792                         if (devname == NULL)
793                                 goto err_no_mem_clear;
794
795                         os_free(wpa_s->conf->device_name);
796                         wpa_s->conf->device_name = devname;
797
798                         wpa_s->conf->changed_parameters |=
799                                                         CFG_CHANGED_DEVICE_NAME;
800                 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
801                         if (entry.type != DBUS_TYPE_ARRAY ||
802                             entry.array_type != DBUS_TYPE_BYTE ||
803                             entry.array_len != WPS_DEV_TYPE_LEN)
804                                 goto error_clear;
805
806                         os_memcpy(wpa_s->conf->device_type,
807                                   entry.bytearray_value,
808                                   WPS_DEV_TYPE_LEN);
809                         wpa_s->conf->changed_parameters |=
810                                 CFG_CHANGED_DEVICE_TYPE;
811                 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
812                         if (entry.type != DBUS_TYPE_ARRAY ||
813                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
814                             entry.array_len > MAX_SEC_DEVICE_TYPES)
815                                 goto error;
816
817                         for (i = 0; i < entry.array_len; i++)
818                                 if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
819                                         goto err_no_mem_clear;
820                         for (i = 0; i < entry.array_len; i++)
821                                 os_memcpy(wpa_s->conf->sec_device_type[i],
822                                           wpabuf_head(entry.binarray_value[i]),
823                                           WPS_DEV_TYPE_LEN);
824                         wpa_s->conf->num_sec_device_types = entry.array_len;
825                         wpa_s->conf->changed_parameters |=
826                                         CFG_CHANGED_SEC_DEVICE_TYPE;
827                 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
828                         if ((entry.type != DBUS_TYPE_ARRAY) ||
829                             (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
830                             (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
831                                 goto error_clear;
832
833                         wpa_s->conf->changed_parameters |=
834                                         CFG_CHANGED_VENDOR_EXTENSION;
835
836                         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
837                                 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
838                                 if (i < entry.array_len) {
839                                         wpa_s->conf->wps_vendor_ext[i] =
840                                                 entry.binarray_value[i];
841                                         entry.binarray_value[i] = NULL;
842                                 } else
843                                         wpa_s->conf->wps_vendor_ext[i] = NULL;
844                         }
845                 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
846                            (entry.type == DBUS_TYPE_UINT32) &&
847                            (entry.uint32_value <= 15))
848                         wpa_s->conf->p2p_go_intent = entry.uint32_value;
849
850                 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
851                          (entry.type == DBUS_TYPE_BOOLEAN))
852                         wpa_s->conf->persistent_reconnect = entry.bool_value;
853
854                 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
855                          (entry.type == DBUS_TYPE_UINT32))
856                         wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
857
858                 else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
859                          (entry.type == DBUS_TYPE_UINT32))
860                         wpa_s->conf->p2p_listen_channel = entry.uint32_value;
861
862                 else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
863                          (entry.type == DBUS_TYPE_UINT32))
864                         wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
865
866                 else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
867                          (entry.type == DBUS_TYPE_UINT32))
868                         wpa_s->conf->p2p_oper_channel = entry.uint32_value;
869
870                 else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
871                         char *postfix;
872
873                         if (entry.type != DBUS_TYPE_STRING)
874                                 goto error_clear;
875
876                         postfix = os_strdup(entry.str_value);
877                         if (!postfix)
878                                 goto err_no_mem_clear;
879
880                         os_free(wpa_s->conf->p2p_ssid_postfix);
881                         wpa_s->conf->p2p_ssid_postfix = postfix;
882
883                         wpa_s->conf->changed_parameters |=
884                                         CFG_CHANGED_P2P_SSID_POSTFIX;
885                 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
886                            (entry.type == DBUS_TYPE_BOOLEAN)) {
887                         wpa_s->conf->p2p_intra_bss = entry.bool_value;
888                         wpa_s->conf->changed_parameters |=
889                                                       CFG_CHANGED_P2P_INTRA_BSS;
890                 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
891                            (entry.type == DBUS_TYPE_UINT32))
892                         wpa_s->conf->p2p_group_idle = entry.uint32_value;
893                 else
894                         goto error_clear;
895
896                 wpa_dbus_dict_entry_clear(&entry);
897         }
898
899         if (wpa_s->conf->changed_parameters) {
900                 /* Some changed parameters requires to update config*/
901                 wpa_supplicant_update_config(wpa_s);
902         }
903
904         return reply;
905
906  error_clear:
907         wpa_dbus_dict_entry_clear(&entry);
908  error:
909         reply = wpas_dbus_error_invalid_args(message, entry.key);
910         wpa_dbus_dict_entry_clear(&entry);
911
912         return reply;
913  err_no_mem_clear:
914         wpa_dbus_dict_entry_clear(&entry);
915         return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
916 }
917
918 DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
919                                         struct wpa_supplicant * wpa_s)
920 {
921         DBusMessage *reply = NULL;
922         struct p2p_data *p2p = wpa_s->global->p2p;
923         int next = 0, i = 0;
924         int num = 0, out_of_mem = 0;
925         const u8 *addr;
926         const struct p2p_peer_info *peer_info = NULL;
927
928         struct dl_list peer_objpath_list;
929         struct peer_objpath_node {
930                 struct dl_list list;
931                 char path[WPAS_DBUS_OBJECT_PATH_MAX];
932         } *node, *tmp;
933
934         char **peer_obj_paths = NULL;
935
936         dl_list_init(&peer_objpath_list);
937
938         /* Get the first peer info */
939         peer_info = p2p_get_peer_found(p2p, NULL, next);
940
941         /* Get next and accumulate them */
942         next = 1;
943         while (peer_info != NULL) {
944                 node = os_zalloc(sizeof(struct peer_objpath_node));
945                 if (!node) {
946                         out_of_mem = 1;
947                         goto error;
948                 }
949
950                 addr = peer_info->p2p_device_addr;
951                 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
952                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
953                             "/" COMPACT_MACSTR,
954                             wpa_s->dbus_new_path, MAC2STR(addr));
955                 dl_list_add_tail(&peer_objpath_list, &node->list);
956                 num++;
957
958                 peer_info = p2p_get_peer_found(p2p, addr, next);
959         }
960
961         /*
962          * Now construct the peer object paths in a form suitable for
963          * array_property_getter helper below.
964          */
965         peer_obj_paths = os_zalloc(num * sizeof(char *));
966
967         if (!peer_obj_paths) {
968                 out_of_mem = 1;
969                 goto error;
970         }
971
972         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
973                               struct peer_objpath_node, list)
974                 peer_obj_paths[i++] = node->path;
975
976         reply = wpas_dbus_simple_array_property_getter(message,
977                                                        DBUS_TYPE_OBJECT_PATH,
978                                                        peer_obj_paths, num);
979
980 error:
981         if (peer_obj_paths)
982                 os_free(peer_obj_paths);
983
984         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
985                               struct peer_objpath_node, list) {
986                 dl_list_del(&node->list);
987                 os_free(node);
988         }
989         if (out_of_mem)
990                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
991                                                NULL);
992
993         return reply;
994 }
995
996 enum wpas_p2p_role {
997         WPAS_P2P_ROLE_DEVICE,
998         WPAS_P2P_ROLE_GO,
999         WPAS_P2P_ROLE_CLIENT,
1000 };
1001
1002 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1003 {
1004         struct wpa_ssid *ssid = wpa_s->current_ssid;
1005
1006         if (!ssid)
1007                 return WPAS_P2P_ROLE_DEVICE;
1008         if (wpa_s->wpa_state != WPA_COMPLETED)
1009                 return WPAS_P2P_ROLE_DEVICE;
1010
1011         switch (ssid->mode) {
1012         case WPAS_MODE_P2P_GO:
1013         case WPAS_MODE_P2P_GROUP_FORMATION:
1014                 return WPAS_P2P_ROLE_GO;
1015         case WPAS_MODE_INFRA:
1016                 if (ssid->p2p_group)
1017                         return WPAS_P2P_ROLE_CLIENT;
1018                 return WPAS_P2P_ROLE_DEVICE;
1019         default:
1020                 return WPAS_P2P_ROLE_DEVICE;
1021         }
1022 }
1023
1024 DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
1025                                        struct wpa_supplicant * wpa_s)
1026 {
1027         char *str;
1028
1029         switch (wpas_get_p2p_role(wpa_s)) {
1030         case WPAS_P2P_ROLE_GO:
1031                 str = "GO";
1032                 break;
1033         case WPAS_P2P_ROLE_CLIENT:
1034                 str = "client";
1035                 break;
1036         default:
1037                 str = "device";
1038         }
1039
1040         return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
1041                                                 &str);
1042 }
1043
1044 DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
1045                                         struct wpa_supplicant * wpa_s)
1046 {
1047         if (wpa_s->dbus_groupobj_path == NULL)
1048                 return NULL;
1049
1050         return wpas_dbus_simple_property_getter(message,
1051                                                 DBUS_TYPE_OBJECT_PATH,
1052                                                 &wpa_s->dbus_groupobj_path);
1053 }
1054
1055 DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
1056                                          struct wpa_supplicant * wpa_s)
1057 {
1058         char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1059
1060         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1061                 return NULL;
1062
1063         os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1064                     "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1065                     wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1066         path = go_peer_obj_path;
1067         return wpas_dbus_simple_property_getter(message,
1068                                                 DBUS_TYPE_OBJECT_PATH, &path);
1069 }
1070
1071 /*
1072  * Peer object properties accessor methods
1073  */
1074
1075 DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
1076                                                   struct peer_handler_args *
1077                                                   peer_args)
1078 {
1079         DBusMessage *reply = NULL;
1080         DBusMessageIter iter, variant_iter, dict_iter;
1081         const struct p2p_peer_info *info = NULL;
1082         char devtype[WPS_DEV_TYPE_BUFSIZE];
1083
1084         /* get the peer info */
1085         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1086                                   peer_args->p2p_device_addr, 0);
1087         if (info == NULL)
1088                 return NULL;
1089
1090         if (message == NULL)
1091                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1092         else
1093                 reply = dbus_message_new_method_return(message);
1094
1095         if (!reply)
1096                 goto err_no_mem;
1097
1098         dbus_message_iter_init_append(reply, &iter);
1099         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1100                                               "a{sv}", &variant_iter) ||
1101             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1102                 goto err_no_mem;
1103
1104         /* Fill out the dictionary */
1105         wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1106         if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1107                                          info->device_name))
1108                 goto err_no_mem;
1109         if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1110                                          devtype))
1111                 goto err_no_mem;
1112         if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1113                                          info->config_methods))
1114                 goto err_no_mem;
1115         if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1116                                        info->dev_capab))
1117                 goto err_no_mem;
1118         if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1119                                        info->group_capab))
1120                 goto err_no_mem;
1121
1122         if (info->wps_sec_dev_type_list_len) {
1123                 char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1124                 u8 *sec_dev_type_list = NULL;
1125                 char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1126                 int num_sec_dev_types = 0;
1127                 int i;
1128
1129                 sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1130
1131                 if (sec_dev_type_list == NULL)
1132                         goto err_no_mem;
1133
1134                 os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1135                           info->wps_sec_dev_type_list_len);
1136
1137                 for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1138                        i < (int) (info->wps_sec_dev_type_list_len /
1139                                   WPS_DEV_TYPE_LEN);
1140                      i++) {
1141                         sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1142
1143                         if (!sec_dev_types[i] ||
1144                             wps_dev_type_bin2str(
1145                                         &sec_dev_type_list[i *
1146                                                            WPS_DEV_TYPE_LEN],
1147                                         sec_dev_types[i],
1148                                         sizeof(secdevtype)) == NULL) {
1149                                 while (--i >= 0)
1150                                         os_free(sec_dev_types[i]);
1151                                 os_free(sec_dev_type_list);
1152                                 goto err_no_mem;
1153                         }
1154
1155                         num_sec_dev_types++;
1156                 }
1157
1158                 os_free(sec_dev_type_list);
1159
1160                 if (num_sec_dev_types) {
1161                         if (!wpa_dbus_dict_append_string_array(&dict_iter,
1162                                                 "SecondaryDeviceTypes",
1163                                                 (const char **)sec_dev_types,
1164                                                 num_sec_dev_types)) {
1165                                 for (i = 0; i < num_sec_dev_types; i++)
1166                                         os_free(sec_dev_types[i]);
1167                                 goto err_no_mem;
1168                         }
1169
1170                         for (i = 0; i < num_sec_dev_types; i++)
1171                                 os_free(sec_dev_types[i]);
1172                 }
1173         }
1174
1175         {
1176                 /* Add WPS vendor extensions attribute */
1177                 const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1178                 int i, num = 0;
1179
1180                 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1181                         if (info->wps_vendor_ext[i] == NULL)
1182                                 continue;
1183                         vendor_extension[num] = info->wps_vendor_ext[i];
1184                         num++;
1185                 }
1186
1187                 if (!wpa_dbus_dict_append_wpabuf_array(
1188                                         &dict_iter, "VendorExtension",
1189                                         vendor_extension, num))
1190                         goto err_no_mem;
1191         }
1192
1193         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1194             !dbus_message_iter_close_container(&iter, &variant_iter))
1195                 goto err_no_mem;
1196
1197         return reply;
1198 err_no_mem:
1199         dbus_message_unref(reply);
1200         return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1201 }
1202
1203 DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
1204                                            struct peer_handler_args * peer_args)
1205 {
1206         return NULL;
1207 }
1208
1209
1210 /*
1211  * Group object properties accessor methods
1212  */
1213
1214 DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
1215                                                 struct wpa_supplicant * wpa_s)
1216 {
1217         DBusMessage *reply = NULL;
1218         struct wpa_ssid *ssid;
1219         unsigned int num_members;
1220         char **paths;
1221         unsigned int i;
1222         void *next = NULL;
1223         const u8 *addr;
1224
1225         /* Ensure we are a GO */
1226         if (wpa_s->wpa_state != WPA_COMPLETED)
1227                 goto out;
1228
1229         ssid = wpa_s->conf->ssid;
1230         /* At present WPAS P2P_GO mode only applicable for p2p_go */
1231         if (ssid->mode != WPAS_MODE_P2P_GO &&
1232             ssid->mode != WPAS_MODE_AP &&
1233             ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1234                 goto out;
1235
1236         num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1237
1238         paths = os_zalloc(num_members * sizeof(char *));
1239         if (!paths)
1240                 goto out_of_memory;
1241
1242         i = 0;
1243         while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1244                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1245                 if (!paths[i])
1246                         goto out_of_memory;
1247                 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1248                             "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1249                             "/" COMPACT_MACSTR,
1250                             wpa_s->dbus_groupobj_path, MAC2STR(addr));
1251                 i++;
1252         }
1253
1254         reply = wpas_dbus_simple_array_property_getter(message,
1255                                                        DBUS_TYPE_OBJECT_PATH,
1256                                                        paths, num_members);
1257
1258 out_free:
1259         for (i = 0; i < num_members; i++)
1260                 os_free(paths[i]);
1261         os_free(paths);
1262 out:
1263         return reply;
1264 out_of_memory:
1265         reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1266         goto out_free;
1267 }
1268
1269
1270 DBusMessage *wpas_dbus_getter_p2p_group_properties(
1271         DBusMessage *message,
1272         struct wpa_supplicant *wpa_s)
1273 {
1274         DBusMessage *reply = NULL;
1275         DBusMessageIter iter, variant_iter, dict_iter;
1276         struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1277         const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1278         int num_vendor_ext = 0;
1279         int i;
1280
1281         if (!hapd) {
1282                 reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
1283                                                NULL);
1284                 return reply;
1285         }
1286
1287         if (message == NULL)
1288                 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1289         else
1290                 reply = dbus_message_new_method_return(message);
1291
1292         if (!reply)
1293                 goto err_no_mem;
1294
1295         dbus_message_iter_init_append(reply, &iter);
1296
1297         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1298                                               "a{sv}", &variant_iter) ||
1299             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1300                 goto err_no_mem;
1301
1302         /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1303         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1304                 if (hapd->conf->wps_vendor_ext[i] == NULL)
1305                         continue;
1306                 vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1307         }
1308
1309         if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1310                                                "WPSVendorExtensions",
1311                                                vendor_ext, num_vendor_ext))
1312                 goto err_no_mem;
1313
1314         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1315             !dbus_message_iter_close_container(&iter, &variant_iter))
1316                 goto err_no_mem;
1317
1318         return reply;
1319
1320 err_no_mem:
1321         dbus_message_unref(reply);
1322         return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1323 }
1324
1325 DBusMessage *wpas_dbus_setter_p2p_group_properties(
1326         DBusMessage *message,
1327         struct wpa_supplicant *wpa_s)
1328 {
1329         DBusMessage *reply = NULL;
1330         DBusMessageIter iter, variant_iter;
1331         struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
1332         DBusMessageIter iter_dict;
1333         unsigned int i;
1334
1335         struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1336
1337         if (!hapd)
1338                 goto error;
1339
1340         dbus_message_iter_init(message, &iter);
1341
1342         dbus_message_iter_next(&iter);
1343         dbus_message_iter_next(&iter);
1344
1345         dbus_message_iter_recurse(&iter, &variant_iter);
1346
1347         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
1348                 return wpas_dbus_error_invalid_args(message, NULL);
1349
1350         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1351                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1352                         reply = wpas_dbus_error_invalid_args(message, NULL);
1353                         break;
1354                 }
1355
1356                 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1357                         if (entry.type != DBUS_TYPE_ARRAY ||
1358                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1359                             entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1360                                 goto error;
1361
1362                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1363                                 if (i < entry.array_len) {
1364                                         hapd->conf->wps_vendor_ext[i] =
1365                                                 entry.binarray_value[i];
1366                                         entry.binarray_value[i] = NULL;
1367                                 } else
1368                                         hapd->conf->wps_vendor_ext[i] = NULL;
1369                         }
1370
1371                         hostapd_update_wps(hapd);
1372                 } else
1373                         goto error;
1374
1375                 wpa_dbus_dict_entry_clear(&entry);
1376         }
1377
1378         return reply;
1379
1380 error:
1381         reply = wpas_dbus_error_invalid_args(message, entry.key);
1382         wpa_dbus_dict_entry_clear(&entry);
1383
1384         return reply;
1385 }
1386
1387 DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
1388                                                struct wpa_supplicant * wpa_s)
1389 {
1390         DBusMessageIter iter_dict;
1391         DBusMessage *reply = NULL;
1392         DBusMessageIter iter;
1393         struct wpa_dbus_dict_entry entry;
1394         int upnp = 0;
1395         int bonjour = 0;
1396         char *service = NULL;
1397         struct wpabuf *query = NULL;
1398         struct wpabuf *resp = NULL;
1399         u8 version = 0;
1400
1401         dbus_message_iter_init(message, &iter);
1402
1403         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1404                 goto error;
1405
1406         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1407                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1408                         goto error;
1409
1410                 if (!strcmp(entry.key, "service_type") &&
1411                     (entry.type == DBUS_TYPE_STRING)) {
1412                         if (!strcmp(entry.str_value, "upnp"))
1413                                 upnp = 1;
1414                         else if (!strcmp(entry.str_value, "bonjour"))
1415                                 bonjour = 1;
1416                         else
1417                                 goto error_clear;
1418                         wpa_dbus_dict_entry_clear(&entry);
1419                 }
1420         }
1421
1422         if (upnp == 1) {
1423                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1424                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1425                                 goto error;
1426
1427                         if (!strcmp(entry.key, "version") &&
1428                             entry.type == DBUS_TYPE_INT32)
1429                                 version = entry.uint32_value;
1430                         else if (!strcmp(entry.key, "service") &&
1431                                  entry.type == DBUS_TYPE_STRING)
1432                                 service = os_strdup(entry.str_value);
1433                         wpa_dbus_dict_entry_clear(&entry);
1434                 }
1435                 if (version <= 0 || service == NULL)
1436                         goto error;
1437
1438                 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1439                         goto error;
1440
1441                 os_free(service);
1442         } else if (bonjour == 1) {
1443                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1444                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1445                                 goto error;
1446
1447                         if (!strcmp(entry.key, "query")) {
1448                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1449                                     (entry.array_type != DBUS_TYPE_BYTE))
1450                                         goto error_clear;
1451                                 query = wpabuf_alloc_copy(entry.bytearray_value,
1452                                                           entry.array_len);
1453                         } else if (!strcmp(entry.key, "response")) {
1454                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1455                                     (entry.array_type != DBUS_TYPE_BYTE))
1456                                         goto error_clear;
1457                                 resp = wpabuf_alloc_copy(entry.bytearray_value,
1458                                                          entry.array_len);
1459                         }
1460
1461                         wpa_dbus_dict_entry_clear(&entry);
1462                 }
1463
1464                 if (query == NULL || resp == NULL)
1465                         goto error;
1466
1467                 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1468                         wpabuf_free(query);
1469                         wpabuf_free(resp);
1470                         goto error;
1471                 }
1472         } else
1473                 goto error;
1474
1475         return reply;
1476 error_clear:
1477         wpa_dbus_dict_entry_clear(&entry);
1478 error:
1479         return wpas_dbus_error_invalid_args(message, NULL);
1480 }
1481
1482 DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
1483                                                   struct wpa_supplicant * wpa_s)
1484 {
1485         DBusMessageIter iter_dict;
1486         DBusMessage *reply = NULL;
1487         DBusMessageIter iter;
1488         struct wpa_dbus_dict_entry entry;
1489         int upnp = 0;
1490         int bonjour = 0;
1491         int ret = 0;
1492         char *service = NULL;
1493         struct wpabuf *query = NULL;
1494         u8 version = 0;
1495
1496         dbus_message_iter_init(message, &iter);
1497
1498         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1499                 goto error;
1500
1501         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1502                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1503                         goto error;
1504
1505                 if (!strcmp(entry.key, "service_type") &&
1506                     (entry.type == DBUS_TYPE_STRING)) {
1507                         if (!strcmp(entry.str_value, "upnp"))
1508                                 upnp = 1;
1509                         else if (!strcmp(entry.str_value, "bonjour"))
1510                                 bonjour = 1;
1511                         else
1512                                 goto error_clear;
1513                         wpa_dbus_dict_entry_clear(&entry);
1514                 }
1515         }
1516         if (upnp == 1) {
1517                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1518                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1519                                 goto error;
1520                         if (!strcmp(entry.key, "version") &&
1521                             entry.type == DBUS_TYPE_INT32)
1522                                 version = entry.uint32_value;
1523                         else if (!strcmp(entry.key, "service") &&
1524                                  entry.type == DBUS_TYPE_STRING)
1525                                 service = os_strdup(entry.str_value);
1526                         else
1527                                 goto error_clear;
1528
1529                         wpa_dbus_dict_entry_clear(&entry);
1530                 }
1531
1532                 if (version <= 0 || service == NULL)
1533                         goto error;
1534
1535                 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1536                 os_free(service);
1537                 if (ret != 0)
1538                         goto error;
1539         } else if (bonjour == 1) {
1540                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1541                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1542                                 goto error;
1543
1544                         if (!strcmp(entry.key, "query")) {
1545                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1546                                     (entry.array_type != DBUS_TYPE_BYTE))
1547                                         goto error_clear;
1548                                 query = wpabuf_alloc_copy(entry.bytearray_value,
1549                                                           entry.array_len);
1550                         } else
1551                                 goto error_clear;
1552
1553                         wpa_dbus_dict_entry_clear(&entry);
1554                 }
1555
1556                 if (query == NULL)
1557                         goto error;
1558
1559                 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1560                 if (ret != 0)
1561                         goto error;
1562                 wpabuf_free(query);
1563         } else
1564                 goto error;
1565
1566         return reply;
1567 error_clear:
1568         wpa_dbus_dict_entry_clear(&entry);
1569 error:
1570         return wpas_dbus_error_invalid_args(message, NULL);
1571 }
1572
1573 DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
1574                                                  struct wpa_supplicant * wpa_s)
1575 {
1576         wpas_p2p_service_flush(wpa_s);
1577         return NULL;
1578 }
1579
1580 DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
1581                                                   struct wpa_supplicant * wpa_s)
1582 {
1583         DBusMessageIter iter_dict;
1584         DBusMessage *reply = NULL;
1585         DBusMessageIter iter;
1586         struct wpa_dbus_dict_entry entry;
1587         int upnp = 0;
1588         char *service = NULL;
1589         char *peer_object_path = NULL;
1590         struct wpabuf *tlv = NULL;
1591         u8 version = 0;
1592         u64 ref = 0;
1593         u8 addr[ETH_ALEN];
1594
1595         dbus_message_iter_init(message, &iter);
1596
1597         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1598                 goto error;
1599
1600         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1601                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1602                         goto error;
1603                 if (!strcmp(entry.key, "peer_object") &&
1604                     entry.type == DBUS_TYPE_OBJECT_PATH) {
1605                         peer_object_path = os_strdup(entry.str_value);
1606                 } else if (!strcmp(entry.key, "service_type") &&
1607                            entry.type == DBUS_TYPE_STRING) {
1608                         if (!strcmp(entry.str_value, "upnp"))
1609                                 upnp = 1;
1610                         else
1611                                 goto error_clear;
1612                 } else if (!strcmp(entry.key, "version") &&
1613                            entry.type == DBUS_TYPE_INT32) {
1614                         version = entry.uint32_value;
1615                 } else if (!strcmp(entry.key, "service") &&
1616                            entry.type == DBUS_TYPE_STRING) {
1617                         service = os_strdup(entry.str_value);
1618                 } else if (!strcmp(entry.key, "tlv")) {
1619                         if (entry.type != DBUS_TYPE_ARRAY ||
1620                             entry.array_type != DBUS_TYPE_BYTE)
1621                                 goto error_clear;
1622                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
1623                                                 entry.array_len);
1624                 } else
1625                         goto error_clear;
1626
1627                 wpa_dbus_dict_entry_clear(&entry);
1628         }
1629
1630         if (!peer_object_path ||
1631             (parse_peer_object_path(peer_object_path, addr) < 0) ||
1632             (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
1633                 goto error;
1634
1635         if (upnp == 1) {
1636                 if (version <= 0 || service == NULL)
1637                         goto error;
1638
1639                 ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
1640                                                               version, service);
1641         } else {
1642                 if (tlv == NULL)
1643                         goto error;
1644                 ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
1645                 wpabuf_free(tlv);
1646         }
1647
1648         if (ref != 0) {
1649                 reply = dbus_message_new_method_return(message);
1650                 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
1651                                          &ref, DBUS_TYPE_INVALID);
1652         } else {
1653                 reply = wpas_dbus_error_unknown_error(message,
1654                                 "Unable to send SD request");
1655         }
1656 out:
1657         os_free(service);
1658         os_free(peer_object_path);
1659         return reply;
1660 error_clear:
1661         wpa_dbus_dict_entry_clear(&entry);
1662 error:
1663         if (tlv)
1664                 wpabuf_free(tlv);
1665         reply = wpas_dbus_error_invalid_args(message, NULL);
1666         goto out;
1667 }
1668
1669 DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
1670         DBusMessage *message, struct wpa_supplicant *wpa_s)
1671 {
1672         DBusMessageIter iter_dict;
1673         DBusMessage *reply = NULL;
1674         DBusMessageIter iter;
1675         struct wpa_dbus_dict_entry entry;
1676         char *peer_object_path = NULL;
1677         struct wpabuf *tlv = NULL;
1678         int freq = 0;
1679         int dlg_tok = 0;
1680         u8 addr[ETH_ALEN];
1681
1682         dbus_message_iter_init(message, &iter);
1683
1684         if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1685                 goto error;
1686
1687         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1688                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1689                         goto error;
1690
1691                 if (!strcmp(entry.key, "peer_object") &&
1692                     entry.type == DBUS_TYPE_OBJECT_PATH) {
1693                         peer_object_path = os_strdup(entry.str_value);
1694                 } else if (!strcmp(entry.key, "frequency") &&
1695                            entry.type == DBUS_TYPE_INT32) {
1696                         freq = entry.uint32_value;
1697                 } else if (!strcmp(entry.key, "dialog_token") &&
1698                            entry.type == DBUS_TYPE_UINT32) {
1699                         dlg_tok = entry.uint32_value;
1700                 } else if (!strcmp(entry.key, "tlvs")) {
1701                         if (entry.type != DBUS_TYPE_ARRAY ||
1702                             entry.array_type != DBUS_TYPE_BYTE)
1703                                 goto error_clear;
1704                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
1705                                                 entry.array_len);
1706                 } else
1707                         goto error_clear;
1708
1709                 wpa_dbus_dict_entry_clear(&entry);
1710         }
1711         if (!peer_object_path ||
1712             (parse_peer_object_path(peer_object_path, addr) < 0) ||
1713             (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
1714                 goto error;
1715
1716         if (tlv == NULL)
1717                 goto error;
1718
1719         wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
1720         wpabuf_free(tlv);
1721 out:
1722         os_free(peer_object_path);
1723         return reply;
1724 error_clear:
1725         wpa_dbus_dict_entry_clear(&entry);
1726 error:
1727         reply = wpas_dbus_error_invalid_args(message, NULL);
1728         goto out;
1729 }
1730
1731 DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
1732                                                          *wpa_s)
1733 {
1734         DBusMessageIter iter;
1735         u64 req = 0;
1736
1737         dbus_message_iter_init(message, &iter);
1738         dbus_message_iter_get_basic(&iter, &req);
1739
1740         if (req == 0)
1741                 goto error;
1742
1743         if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
1744                 goto error;
1745
1746         return NULL;
1747 error:
1748         return wpas_dbus_error_invalid_args(message, NULL);
1749 }
1750
1751 DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
1752                                                   struct wpa_supplicant * wpa_s)
1753 {
1754         wpas_p2p_sd_service_update(wpa_s);
1755         return NULL;
1756 }
1757
1758 DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
1759                                                       struct wpa_supplicant *
1760                                                       wpa_s)
1761 {
1762         DBusMessageIter iter;
1763         int ext = 0;
1764
1765         dbus_message_iter_init(message, &iter);
1766         dbus_message_iter_get_basic(&iter, &ext);
1767
1768         wpa_s->p2p_sd_over_ctrl_iface = ext;
1769
1770         return NULL;
1771
1772 }