2476e6216968eea865bfd90df11e74fe690e30ec
[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 "../notify.h"
22 #include "dbus_new_helpers.h"
23 #include "dbus_new.h"
24 #include "dbus_new_handlers.h"
25 #include "dbus_new_handlers_p2p.h"
26 #include "dbus_dict_helpers.h"
27 #include "p2p/p2p.h"
28 #include "common/ieee802_11_defs.h"
29 #include "ap/hostapd.h"
30 #include "ap/ap_config.h"
31 #include "ap/wps_hostapd.h"
32
33 #include "../p2p_supplicant.h"
34
35 /**
36  * Parses out the mac address from the peer object path.
37  * @peer_path - object path of the form
38  *      /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
39  * @addr - out param must be of ETH_ALEN size
40  * Returns 0 if valid (including MAC), -1 otherwise
41  */
42 static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
43 {
44         char *p;
45
46         if (!peer_path)
47                 return -1;
48         p = strrchr(peer_path, '/');
49         if (!p)
50                 return -1;
51         p++;
52         return hwaddr_compact_aton(p, addr);
53 }
54
55
56 /**
57  * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
58  * error message
59  * @message: Pointer to incoming dbus message this error refers to
60  * Returns: a dbus error message
61  *
62  * Convenience function to create and return an invalid persistent group error.
63  */
64 static DBusMessage * wpas_dbus_error_persistent_group_unknown(
65         DBusMessage *message)
66 {
67         return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
68                                       "There is no such persistent group in "
69                                       "this P2P device.");
70 }
71
72
73 DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
74                                          struct wpa_supplicant *wpa_s)
75 {
76         struct wpa_dbus_dict_entry entry;
77         DBusMessage *reply = NULL;
78         DBusMessageIter iter;
79         DBusMessageIter iter_dict;
80         unsigned int timeout = 0;
81         enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
82         int num_req_dev_types = 0;
83         unsigned int i;
84         u8 *req_dev_types = NULL;
85
86         dbus_message_iter_init(message, &iter);
87         entry.key = NULL;
88
89         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
90                 goto error;
91
92         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
93                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
94                         goto error;
95
96                 if (!os_strcmp(entry.key, "Timeout") &&
97                     (entry.type == DBUS_TYPE_INT32)) {
98                         timeout = entry.uint32_value;
99                 } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
100                         if ((entry.type != DBUS_TYPE_ARRAY) ||
101                             (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
102                                 goto error_clear;
103
104                         os_free(req_dev_types);
105                         req_dev_types =
106                                 os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
107                         if (!req_dev_types)
108                                 goto error_clear;
109
110                         for (i = 0; i < entry.array_len; i++) {
111                                 if (wpabuf_len(entry.binarray_value[i]) !=
112                                                         WPS_DEV_TYPE_LEN)
113                                         goto error_clear;
114                                 os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
115                                           wpabuf_head(entry.binarray_value[i]),
116                                           WPS_DEV_TYPE_LEN);
117                         }
118                         num_req_dev_types = entry.array_len;
119                 } else if (!os_strcmp(entry.key, "DiscoveryType") &&
120                            (entry.type == DBUS_TYPE_STRING)) {
121                         if (!os_strcmp(entry.str_value, "start_with_full"))
122                                 type = P2P_FIND_START_WITH_FULL;
123                         else if (!os_strcmp(entry.str_value, "social"))
124                                 type = P2P_FIND_ONLY_SOCIAL;
125                         else if (!os_strcmp(entry.str_value, "progressive"))
126                                 type = P2P_FIND_PROGRESSIVE;
127                         else
128                                 goto error_clear;
129                 } else
130                         goto error_clear;
131                 wpa_dbus_dict_entry_clear(&entry);
132         }
133
134         wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
135                       NULL);
136         os_free(req_dev_types);
137         return reply;
138
139 error_clear:
140         wpa_dbus_dict_entry_clear(&entry);
141 error:
142         os_free(req_dev_types);
143         reply = wpas_dbus_error_invalid_args(message, entry.key);
144         return reply;
145 }
146
147
148 DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
149                                               struct wpa_supplicant *wpa_s)
150 {
151         wpas_p2p_stop_find(wpa_s);
152         return NULL;
153 }
154
155
156 DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
157                                                struct wpa_supplicant *wpa_s)
158 {
159         DBusMessageIter iter;
160         char *peer_object_path = NULL;
161         u8 peer_addr[ETH_ALEN];
162
163         dbus_message_iter_init(message, &iter);
164         dbus_message_iter_get_basic(&iter, &peer_object_path);
165
166         if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
167                 return wpas_dbus_error_invalid_args(message, NULL);
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 dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
185                                               NULL);
186
187         if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
188                 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
189                                               NULL);
190
191         return NULL;
192 }
193
194
195 DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
196         DBusMessage *message, struct wpa_supplicant *wpa_s)
197 {
198         unsigned int period = 0, interval = 0;
199         struct wpa_dbus_dict_entry entry;
200         DBusMessageIter iter;
201         DBusMessageIter iter_dict;
202
203         dbus_message_iter_init(message, &iter);
204         entry.key = NULL;
205
206         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
207                 goto error;
208
209         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
210                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
211                         goto error;
212
213                 if (!os_strcmp(entry.key, "period") &&
214                     (entry.type == DBUS_TYPE_INT32))
215                         period = entry.uint32_value;
216                 else if (!os_strcmp(entry.key, "interval") &&
217                          (entry.type == DBUS_TYPE_INT32))
218                         interval = entry.uint32_value;
219                 else
220                         goto error_clear;
221                 wpa_dbus_dict_entry_clear(&entry);
222         }
223
224         if (wpas_p2p_ext_listen(wpa_s, period, interval))
225                 return wpas_dbus_error_unknown_error(
226                         message, "failed to initiate a p2p_ext_listen.");
227
228         return NULL;
229
230 error_clear:
231         wpa_dbus_dict_entry_clear(&entry);
232 error:
233         return wpas_dbus_error_invalid_args(message, entry.key);
234 }
235
236
237 DBusMessage * wpas_dbus_handler_p2p_presence_request(
238         DBusMessage *message, struct wpa_supplicant *wpa_s)
239 {
240         unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
241         struct wpa_dbus_dict_entry entry;
242         DBusMessageIter iter;
243         DBusMessageIter iter_dict;
244
245         dbus_message_iter_init(message, &iter);
246         entry.key = NULL;
247
248         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
249                 goto error;
250
251         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
252                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
253                         goto error;
254
255                 if (!os_strcmp(entry.key, "duration1") &&
256                     (entry.type == DBUS_TYPE_INT32))
257                         dur1 = entry.uint32_value;
258                 else if (!os_strcmp(entry.key, "interval1") &&
259                          entry.type == DBUS_TYPE_INT32)
260                         int1 = entry.uint32_value;
261                 else if (!os_strcmp(entry.key, "duration2") &&
262                          entry.type == DBUS_TYPE_INT32)
263                         dur2 = entry.uint32_value;
264                 else if (!os_strcmp(entry.key, "interval2") &&
265                          entry.type == DBUS_TYPE_INT32)
266                         int2 = entry.uint32_value;
267                 else
268                         goto error_clear;
269
270                 wpa_dbus_dict_entry_clear(&entry);
271         }
272         if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
273                 return wpas_dbus_error_unknown_error(message,
274                                 "Failed to invoke presence request.");
275
276         return NULL;
277
278 error_clear:
279         wpa_dbus_dict_entry_clear(&entry);
280 error:
281         return wpas_dbus_error_invalid_args(message, entry.key);
282 }
283
284
285 DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
286                                               struct wpa_supplicant *wpa_s)
287 {
288         DBusMessageIter iter_dict;
289         DBusMessage *reply = NULL;
290         DBusMessageIter iter;
291         struct wpa_dbus_dict_entry entry;
292         char *pg_object_path = NULL;
293         int persistent_group = 0;
294         int freq = 0;
295         char *iface = NULL;
296         char *net_id_str = NULL;
297         unsigned int group_id = 0;
298         struct wpa_ssid *ssid;
299
300         dbus_message_iter_init(message, &iter);
301
302         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
303                 goto inv_args;
304
305         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
306                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
307                         goto inv_args;
308
309                 if (!os_strcmp(entry.key, "persistent") &&
310                     (entry.type == DBUS_TYPE_BOOLEAN)) {
311                         persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
312                 } else if (!os_strcmp(entry.key, "frequency") &&
313                            (entry.type == DBUS_TYPE_INT32)) {
314                         freq = entry.int32_value;
315                         if (freq <= 0)
316                                 goto inv_args_clear;
317                 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
318                            entry.type == DBUS_TYPE_OBJECT_PATH)
319                         pg_object_path = os_strdup(entry.str_value);
320                 else
321                         goto inv_args_clear;
322
323                 wpa_dbus_dict_entry_clear(&entry);
324         }
325
326         if (pg_object_path != NULL) {
327                 /*
328                  * A persistent group Object Path is defined meaning we want
329                  * to re-invoke a persistent group.
330                  */
331
332                 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
333                                                             &net_id_str, NULL);
334                 if (iface == NULL ||
335                     os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
336                         reply =
337                             wpas_dbus_error_invalid_args(message,
338                                                          pg_object_path);
339                         goto out;
340                 }
341
342                 group_id = strtoul(net_id_str, NULL, 10);
343                 if (errno == EINVAL) {
344                         reply = wpas_dbus_error_invalid_args(
345                                                 message, pg_object_path);
346                         goto out;
347                 }
348
349                 /* Get the SSID structure from the persistent group id */
350                 ssid = wpa_config_get_network(wpa_s->conf, group_id);
351                 if (ssid == NULL || ssid->disabled != 2)
352                         goto inv_args;
353
354                 if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
355                         reply = wpas_dbus_error_unknown_error(
356                                 message,
357                                 "Failed to reinvoke a persistent group");
358                         goto out;
359                 }
360         } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
361                 goto inv_args;
362
363 out:
364         os_free(pg_object_path);
365         os_free(net_id_str);
366         os_free(iface);
367         return reply;
368 inv_args_clear:
369         wpa_dbus_dict_entry_clear(&entry);
370 inv_args:
371         reply = wpas_dbus_error_invalid_args(message, NULL);
372         goto out;
373 }
374
375
376 DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
377                                                struct wpa_supplicant *wpa_s)
378 {
379         if (wpas_p2p_disconnect(wpa_s))
380                 return wpas_dbus_error_unknown_error(message,
381                                                 "failed to disconnect");
382
383         return NULL;
384 }
385
386
387 static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
388                                               DBusMessage *message,
389                                               DBusMessage **out_reply,
390                                               DBusError *error)
391 {
392         /* Return an error message or an error if P2P isn't available */
393         if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
394                 if (out_reply) {
395                         *out_reply = dbus_message_new_error(
396                                 message, DBUS_ERROR_FAILED,
397                                 "P2P is not available for this interface");
398                 }
399                 dbus_set_error_const(error, DBUS_ERROR_FAILED,
400                                      "P2P is not available for this "
401                                      "interface");
402                 return FALSE;
403         }
404         return TRUE;
405 }
406
407
408 DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
409                                           struct wpa_supplicant *wpa_s)
410 {
411         DBusMessage *reply = NULL;
412
413         if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
414                 return reply;
415
416         os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
417         wpa_s->force_long_sd = 0;
418         p2p_flush(wpa_s->global->p2p);
419
420         return NULL;
421 }
422
423
424 DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
425                                             struct wpa_supplicant *wpa_s)
426 {
427         DBusMessageIter iter_dict;
428         DBusMessage *reply = NULL;
429         DBusMessageIter iter;
430         struct wpa_dbus_dict_entry entry;
431         char *peer_object_path = NULL;
432         int persistent_group = 0;
433         int join = 0;
434         int authorize_only = 0;
435         int go_intent = -1;
436         int freq = 0;
437         u8 addr[ETH_ALEN];
438         char *pin = NULL;
439         enum p2p_wps_method wps_method = WPS_NOT_READY;
440         int new_pin;
441         char *err_msg = NULL;
442         char *iface = NULL;
443
444         if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
445                 return reply;
446
447         dbus_message_iter_init(message, &iter);
448
449         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
450                 goto inv_args;
451
452         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
453                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
454                         goto inv_args;
455
456                 if (!os_strcmp(entry.key, "peer") &&
457                     (entry.type == DBUS_TYPE_OBJECT_PATH)) {
458                         peer_object_path = os_strdup(entry.str_value);
459                 } else if (!os_strcmp(entry.key, "persistent") &&
460                            (entry.type == DBUS_TYPE_BOOLEAN)) {
461                         persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
462                 } else if (!os_strcmp(entry.key, "join") &&
463                            (entry.type == DBUS_TYPE_BOOLEAN)) {
464                         join = (entry.bool_value == TRUE) ? 1 : 0;
465                 } else if (!os_strcmp(entry.key, "authorize_only") &&
466                            (entry.type == DBUS_TYPE_BOOLEAN)) {
467                         authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
468                 } else if (!os_strcmp(entry.key, "frequency") &&
469                            (entry.type == DBUS_TYPE_INT32)) {
470                         freq = entry.int32_value;
471                         if (freq <= 0)
472                                 goto inv_args_clear;
473                 } else if (!os_strcmp(entry.key, "go_intent") &&
474                            (entry.type == DBUS_TYPE_INT32)) {
475                         go_intent = entry.int32_value;
476                         if ((go_intent < 0) || (go_intent > 15))
477                                 goto inv_args_clear;
478                 } else if (!os_strcmp(entry.key, "wps_method") &&
479                            (entry.type == DBUS_TYPE_STRING)) {
480                         if (!os_strcmp(entry.str_value, "pbc"))
481                                 wps_method = WPS_PBC;
482                         else if (!os_strcmp(entry.str_value, "pin"))
483                                 wps_method = WPS_PIN_DISPLAY;
484                         else if (!os_strcmp(entry.str_value, "display"))
485                                 wps_method = WPS_PIN_DISPLAY;
486                         else if (!os_strcmp(entry.str_value, "keypad"))
487                                 wps_method = WPS_PIN_KEYPAD;
488                         else
489                                 goto inv_args_clear;
490                 } else if (!os_strcmp(entry.key, "pin") &&
491                            (entry.type == DBUS_TYPE_STRING)) {
492                         pin = os_strdup(entry.str_value);
493                 } else
494                         goto inv_args_clear;
495
496                 wpa_dbus_dict_entry_clear(&entry);
497         }
498
499         if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
500             (parse_peer_object_path(peer_object_path, addr) < 0) ||
501             !p2p_peer_known(wpa_s->global->p2p, addr))
502                 goto inv_args;
503
504         /*
505          * Validate the wps_method specified and the pin value.
506          */
507         if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
508                 goto inv_args;
509
510         new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
511                                    persistent_group, join, authorize_only,
512                                    go_intent, freq);
513
514         if (new_pin >= 0) {
515                 char npin[9];
516                 char *generated_pin;
517                 os_snprintf(npin, sizeof(npin), "%08d", new_pin);
518                 generated_pin = npin;
519                 reply = dbus_message_new_method_return(message);
520                 dbus_message_append_args(reply, DBUS_TYPE_STRING,
521                                          &generated_pin, DBUS_TYPE_INVALID);
522         } else {
523                 switch (new_pin) {
524                 case -2:
525                         err_msg = "connect failed due to channel "
526                                 "unavailability.";
527                         iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
528                         break;
529
530                 case -3:
531                         err_msg = "connect failed due to unsupported channel.";
532                         iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
533                         break;
534
535                 default:
536                         err_msg = "connect failed due to unspecified error.";
537                         iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
538                         break;
539                 }
540
541                 /*
542                  * TODO:
543                  * Do we need specialized errors corresponding to above
544                  * error conditions as against just returning a different
545                  * error message?
546                  */
547                 reply = dbus_message_new_error(message, iface, err_msg);
548         }
549
550 out:
551         os_free(peer_object_path);
552         os_free(pin);
553         return reply;
554 inv_args_clear:
555         wpa_dbus_dict_entry_clear(&entry);
556 inv_args:
557         reply = wpas_dbus_error_invalid_args(message, NULL);
558         goto out;
559 }
560
561
562 DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
563                                            struct wpa_supplicant *wpa_s)
564 {
565         DBusMessageIter iter_dict;
566         DBusMessage *reply = NULL;
567         DBusMessageIter iter;
568         struct wpa_dbus_dict_entry entry;
569         char *peer_object_path = NULL;
570         char *pg_object_path = NULL;
571         char *iface = NULL;
572         char *net_id_str = NULL;
573         u8 peer_addr[ETH_ALEN];
574         unsigned int group_id = 0;
575         int persistent = 0;
576         struct wpa_ssid *ssid;
577
578         if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
579                 return reply;
580
581         dbus_message_iter_init(message, &iter);
582
583         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
584                 goto err;
585
586         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
587                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
588                         goto err;
589
590                 if (!os_strcmp(entry.key, "peer") &&
591                     (entry.type == DBUS_TYPE_OBJECT_PATH)) {
592                         peer_object_path = os_strdup(entry.str_value);
593                         wpa_dbus_dict_entry_clear(&entry);
594                 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
595                            (entry.type == DBUS_TYPE_OBJECT_PATH)) {
596                         pg_object_path = os_strdup(entry.str_value);
597                         persistent = 1;
598                         wpa_dbus_dict_entry_clear(&entry);
599                 } else {
600                         wpa_dbus_dict_entry_clear(&entry);
601                         goto err;
602                 }
603         }
604
605         if (!peer_object_path ||
606             (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
607             !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
608                 goto err;
609         }
610
611         if (persistent) {
612                 /*
613                  * A group ID is defined meaning we want to re-invoke a
614                  * persistent group
615                  */
616
617                 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
618                                                             &net_id_str, NULL);
619                 if (iface == NULL ||
620                     os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
621                         reply = wpas_dbus_error_invalid_args(message,
622                                                              pg_object_path);
623                         goto out;
624                 }
625
626                 group_id = strtoul(net_id_str, NULL, 10);
627                 if (errno == EINVAL) {
628                         reply = wpas_dbus_error_invalid_args(
629                                 message, pg_object_path);
630                         goto out;
631                 }
632
633                 /* Get the SSID structure from the persistent group id */
634                 ssid = wpa_config_get_network(wpa_s->conf, group_id);
635                 if (ssid == NULL || ssid->disabled != 2)
636                         goto err;
637
638                 if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
639                         reply = wpas_dbus_error_unknown_error(
640                                 message,
641                                 "Failed to reinvoke a persistent group");
642                         goto out;
643                 }
644         } else {
645                 /*
646                  * No group ID means propose to a peer to join my active group
647                  */
648                 if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
649                                           peer_addr, NULL)) {
650                         reply = wpas_dbus_error_unknown_error(
651                                 message, "Failed to join to an active group");
652                         goto out;
653                 }
654         }
655
656 out:
657         os_free(pg_object_path);
658         os_free(peer_object_path);
659         return reply;
660
661 err:
662         reply = wpas_dbus_error_invalid_args(message, NULL);
663         goto out;
664 }
665
666
667 DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
668                                                   struct wpa_supplicant *wpa_s)
669 {
670         DBusMessageIter iter;
671         char *peer_object_path = NULL;
672         char *config_method = NULL;
673         u8 peer_addr[ETH_ALEN];
674
675         dbus_message_iter_init(message, &iter);
676         dbus_message_iter_get_basic(&iter, &peer_object_path);
677
678         if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
679                 return wpas_dbus_error_invalid_args(message, NULL);
680
681         dbus_message_iter_next(&iter);
682         dbus_message_iter_get_basic(&iter, &config_method);
683
684         /*
685          * Validation checks on config_method are being duplicated here
686          * to be able to return invalid args reply since the error code
687          * from p2p module are not granular enough (yet).
688          */
689         if (os_strcmp(config_method, "display") &&
690             os_strcmp(config_method, "keypad") &&
691             os_strcmp(config_method, "pbc") &&
692             os_strcmp(config_method, "pushbutton"))
693                 return wpas_dbus_error_invalid_args(message, NULL);
694
695         if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0)
696                 return wpas_dbus_error_unknown_error(message,
697                                 "Failed to send provision discovery request");
698
699         return NULL;
700 }
701
702
703 /*
704  * P2P Device property accessor methods.
705  */
706
707 dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
708                                                    DBusError *error,
709                                                    void *user_data)
710 {
711         struct wpa_supplicant *wpa_s = user_data;
712         DBusMessageIter variant_iter, dict_iter;
713         DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
714                 iter_secdev_dict_array;
715         const char *dev_name;
716         int num_vendor_extensions = 0;
717         int i;
718         const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
719
720         if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
721                 return FALSE;
722
723         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
724                                               "a{sv}", &variant_iter) ||
725             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
726                 goto err_no_mem;
727
728         /* DeviceName */
729         dev_name = wpa_s->conf->device_name;
730         if (dev_name &&
731             !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
732                 goto err_no_mem;
733
734         /* Primary device type */
735         if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
736                                              (char *)wpa_s->conf->device_type,
737                                              WPS_DEV_TYPE_LEN))
738                 goto err_no_mem;
739
740         /* Secondary device types */
741         if (wpa_s->conf->num_sec_device_types) {
742                 if (!wpa_dbus_dict_begin_array(&dict_iter,
743                                                "SecondaryDeviceTypes",
744                                                DBUS_TYPE_ARRAY_AS_STRING
745                                                DBUS_TYPE_BYTE_AS_STRING,
746                                                &iter_secdev_dict_entry,
747                                                &iter_secdev_dict_val,
748                                                &iter_secdev_dict_array))
749                         goto err_no_mem;
750
751                 for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
752                         wpa_dbus_dict_bin_array_add_element(
753                                 &iter_secdev_dict_array,
754                                 wpa_s->conf->sec_device_type[i],
755                                 WPS_DEV_TYPE_LEN);
756
757                 if (!wpa_dbus_dict_end_array(&dict_iter,
758                                              &iter_secdev_dict_entry,
759                                              &iter_secdev_dict_val,
760                                              &iter_secdev_dict_array))
761                         goto err_no_mem;
762         }
763
764         /* Vendor Extensions */
765         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
766                 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
767                         continue;
768                 vendor_ext[num_vendor_extensions++] =
769                         wpa_s->conf->wps_vendor_ext[i];
770         }
771
772         if (num_vendor_extensions &&
773             !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
774                                                "VendorExtension",
775                                                vendor_ext,
776                                                num_vendor_extensions))
777                 goto err_no_mem;
778
779         /* GO Intent */
780         if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
781                                          wpa_s->conf->p2p_go_intent))
782                 goto err_no_mem;
783
784         /* Persistent Reconnect */
785         if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
786                                        wpa_s->conf->persistent_reconnect))
787                 goto err_no_mem;
788
789         /* Listen Reg Class */
790         if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
791                                          wpa_s->conf->p2p_listen_reg_class))
792                 goto err_no_mem;
793
794         /* Listen Channel */
795         if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
796                                          wpa_s->conf->p2p_listen_channel))
797                 goto err_no_mem;
798
799         /* Oper Reg Class */
800         if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
801                                          wpa_s->conf->p2p_oper_reg_class))
802                 goto err_no_mem;
803
804         /* Oper Channel */
805         if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
806                                          wpa_s->conf->p2p_oper_channel))
807                 goto err_no_mem;
808
809         /* SSID Postfix */
810         if (wpa_s->conf->p2p_ssid_postfix &&
811             !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
812                                          wpa_s->conf->p2p_ssid_postfix))
813                 goto err_no_mem;
814
815         /* Intra Bss */
816         if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
817                                        wpa_s->conf->p2p_intra_bss))
818                 goto err_no_mem;
819
820         /* Group Idle */
821         if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
822                                          wpa_s->conf->p2p_group_idle))
823                 goto err_no_mem;
824
825         /* Dissasociation low ack */
826         if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
827                                          wpa_s->conf->disassoc_low_ack))
828                 goto err_no_mem;
829
830         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
831             !dbus_message_iter_close_container(iter, &variant_iter))
832                 goto err_no_mem;
833
834         return TRUE;
835
836 err_no_mem:
837         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
838         return FALSE;
839 }
840
841
842 dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
843                                                    DBusError *error,
844                                                    void *user_data)
845 {
846         struct wpa_supplicant *wpa_s = user_data;
847         DBusMessageIter variant_iter, iter_dict;
848         struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
849         unsigned int i;
850
851         if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
852                 return FALSE;
853
854         dbus_message_iter_recurse(iter, &variant_iter);
855         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
856                 return FALSE;
857
858         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
859                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
860                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
861                                              "invalid message format");
862                         return FALSE;
863                 }
864
865                 if (os_strcmp(entry.key, "DeviceName") == 0) {
866                         char *devname;
867
868                         if (entry.type != DBUS_TYPE_STRING)
869                                 goto error;
870
871                         devname = os_strdup(entry.str_value);
872                         if (devname == NULL)
873                                 goto err_no_mem_clear;
874
875                         os_free(wpa_s->conf->device_name);
876                         wpa_s->conf->device_name = devname;
877
878                         wpa_s->conf->changed_parameters |=
879                                 CFG_CHANGED_DEVICE_NAME;
880                 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
881                         if (entry.type != DBUS_TYPE_ARRAY ||
882                             entry.array_type != DBUS_TYPE_BYTE ||
883                             entry.array_len != WPS_DEV_TYPE_LEN)
884                                 goto error;
885
886                         os_memcpy(wpa_s->conf->device_type,
887                                   entry.bytearray_value,
888                                   WPS_DEV_TYPE_LEN);
889                         wpa_s->conf->changed_parameters |=
890                                 CFG_CHANGED_DEVICE_TYPE;
891                 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
892                         if (entry.type != DBUS_TYPE_ARRAY ||
893                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
894                             entry.array_len > MAX_SEC_DEVICE_TYPES)
895                                 goto error;
896
897                         for (i = 0; i < entry.array_len; i++)
898                                 if (wpabuf_len(entry.binarray_value[i]) !=
899                                     WPS_DEV_TYPE_LEN)
900                                         goto err_no_mem_clear;
901                         for (i = 0; i < entry.array_len; i++)
902                                 os_memcpy(wpa_s->conf->sec_device_type[i],
903                                           wpabuf_head(entry.binarray_value[i]),
904                                           WPS_DEV_TYPE_LEN);
905                         wpa_s->conf->num_sec_device_types = entry.array_len;
906                         wpa_s->conf->changed_parameters |=
907                                         CFG_CHANGED_SEC_DEVICE_TYPE;
908                 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
909                         if ((entry.type != DBUS_TYPE_ARRAY) ||
910                             (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
911                             (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
912                                 goto error;
913
914                         wpa_s->conf->changed_parameters |=
915                                 CFG_CHANGED_VENDOR_EXTENSION;
916
917                         for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
918                                 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
919                                 if (i < entry.array_len) {
920                                         wpa_s->conf->wps_vendor_ext[i] =
921                                                 entry.binarray_value[i];
922                                         entry.binarray_value[i] = NULL;
923                                 } else
924                                         wpa_s->conf->wps_vendor_ext[i] = NULL;
925                         }
926                 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
927                            (entry.type == DBUS_TYPE_UINT32) &&
928                            (entry.uint32_value <= 15))
929                         wpa_s->conf->p2p_go_intent = entry.uint32_value;
930                 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
931                          (entry.type == DBUS_TYPE_BOOLEAN))
932                         wpa_s->conf->persistent_reconnect = entry.bool_value;
933                 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
934                          (entry.type == DBUS_TYPE_UINT32)) {
935                         wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
936                         wpa_s->conf->changed_parameters |=
937                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
938                 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
939                            (entry.type == DBUS_TYPE_UINT32)) {
940                         wpa_s->conf->p2p_listen_channel = entry.uint32_value;
941                         wpa_s->conf->changed_parameters |=
942                                 CFG_CHANGED_P2P_LISTEN_CHANNEL;
943                 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
944                            (entry.type == DBUS_TYPE_UINT32)) {
945                         wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
946                         wpa_s->conf->changed_parameters |=
947                                 CFG_CHANGED_P2P_OPER_CHANNEL;
948                 } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
949                            (entry.type == DBUS_TYPE_UINT32)) {
950                         wpa_s->conf->p2p_oper_channel = entry.uint32_value;
951                         wpa_s->conf->changed_parameters |=
952                                 CFG_CHANGED_P2P_OPER_CHANNEL;
953                 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
954                         char *postfix;
955
956                         if (entry.type != DBUS_TYPE_STRING)
957                                 goto error;
958
959                         postfix = os_strdup(entry.str_value);
960                         if (!postfix)
961                                 goto err_no_mem_clear;
962
963                         os_free(wpa_s->conf->p2p_ssid_postfix);
964                         wpa_s->conf->p2p_ssid_postfix = postfix;
965
966                         wpa_s->conf->changed_parameters |=
967                                         CFG_CHANGED_P2P_SSID_POSTFIX;
968                 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
969                            (entry.type == DBUS_TYPE_BOOLEAN)) {
970                         wpa_s->conf->p2p_intra_bss = entry.bool_value;
971                         wpa_s->conf->changed_parameters |=
972                                 CFG_CHANGED_P2P_INTRA_BSS;
973                 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
974                            (entry.type == DBUS_TYPE_UINT32))
975                         wpa_s->conf->p2p_group_idle = entry.uint32_value;
976                 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
977                          entry.type == DBUS_TYPE_UINT32)
978                         wpa_s->conf->disassoc_low_ack = entry.uint32_value;
979                 else
980                         goto error;
981
982                 wpa_dbus_dict_entry_clear(&entry);
983         }
984
985         if (wpa_s->conf->changed_parameters) {
986                 /* Some changed parameters requires to update config*/
987                 wpa_supplicant_update_config(wpa_s);
988         }
989
990         return TRUE;
991
992  error:
993         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
994                              "invalid message format");
995         wpa_dbus_dict_entry_clear(&entry);
996         return FALSE;
997
998  err_no_mem_clear:
999         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1000         wpa_dbus_dict_entry_clear(&entry);
1001         return FALSE;
1002 }
1003
1004
1005 dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
1006                                        void *user_data)
1007 {
1008         struct wpa_supplicant *wpa_s = user_data;
1009         struct p2p_data *p2p = wpa_s->global->p2p;
1010         int next = 0, i = 0;
1011         int num = 0, out_of_mem = 0;
1012         const u8 *addr;
1013         const struct p2p_peer_info *peer_info = NULL;
1014         dbus_bool_t success = FALSE;
1015
1016         struct dl_list peer_objpath_list;
1017         struct peer_objpath_node {
1018                 struct dl_list list;
1019                 char path[WPAS_DBUS_OBJECT_PATH_MAX];
1020         } *node, *tmp;
1021
1022         char **peer_obj_paths = NULL;
1023
1024         if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
1025                 return FALSE;
1026
1027         dl_list_init(&peer_objpath_list);
1028
1029         /* Get the first peer info */
1030         peer_info = p2p_get_peer_found(p2p, NULL, next);
1031
1032         /* Get next and accumulate them */
1033         next = 1;
1034         while (peer_info != NULL) {
1035                 node = os_zalloc(sizeof(struct peer_objpath_node));
1036                 if (!node) {
1037                         out_of_mem = 1;
1038                         goto error;
1039                 }
1040
1041                 addr = peer_info->p2p_device_addr;
1042                 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
1043                             "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1044                             "/" COMPACT_MACSTR,
1045                             wpa_s->dbus_new_path, MAC2STR(addr));
1046                 dl_list_add_tail(&peer_objpath_list, &node->list);
1047                 num++;
1048
1049                 peer_info = p2p_get_peer_found(p2p, addr, next);
1050         }
1051
1052         /*
1053          * Now construct the peer object paths in a form suitable for
1054          * array_property_getter helper below.
1055          */
1056         peer_obj_paths = os_zalloc(num * sizeof(char *));
1057
1058         if (!peer_obj_paths) {
1059                 out_of_mem = 1;
1060                 goto error;
1061         }
1062
1063         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1064                               struct peer_objpath_node, list)
1065                 peer_obj_paths[i++] = node->path;
1066
1067         success = wpas_dbus_simple_array_property_getter(iter,
1068                                                          DBUS_TYPE_OBJECT_PATH,
1069                                                          peer_obj_paths, num,
1070                                                          error);
1071
1072 error:
1073         if (peer_obj_paths)
1074                 os_free(peer_obj_paths);
1075
1076         dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1077                               struct peer_objpath_node, list) {
1078                 dl_list_del(&node->list);
1079                 os_free(node);
1080         }
1081         if (out_of_mem)
1082                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1083
1084         return success;
1085 }
1086
1087
1088 enum wpas_p2p_role {
1089         WPAS_P2P_ROLE_DEVICE,
1090         WPAS_P2P_ROLE_GO,
1091         WPAS_P2P_ROLE_CLIENT,
1092 };
1093
1094 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1095 {
1096         struct wpa_ssid *ssid = wpa_s->current_ssid;
1097
1098         if (!ssid)
1099                 return WPAS_P2P_ROLE_DEVICE;
1100         if (wpa_s->wpa_state != WPA_COMPLETED)
1101                 return WPAS_P2P_ROLE_DEVICE;
1102
1103         switch (ssid->mode) {
1104         case WPAS_MODE_P2P_GO:
1105         case WPAS_MODE_P2P_GROUP_FORMATION:
1106                 return WPAS_P2P_ROLE_GO;
1107         case WPAS_MODE_INFRA:
1108                 if (ssid->p2p_group)
1109                         return WPAS_P2P_ROLE_CLIENT;
1110                 return WPAS_P2P_ROLE_DEVICE;
1111         default:
1112                 return WPAS_P2P_ROLE_DEVICE;
1113         }
1114 }
1115
1116
1117 dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
1118                                       void *user_data)
1119 {
1120         struct wpa_supplicant *wpa_s = user_data;
1121         char *str;
1122
1123         switch (wpas_get_p2p_role(wpa_s)) {
1124         case WPAS_P2P_ROLE_GO:
1125                 str = "GO";
1126                 break;
1127         case WPAS_P2P_ROLE_CLIENT:
1128                 str = "client";
1129                 break;
1130         default:
1131                 str = "device";
1132         }
1133
1134         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
1135                                                 error);
1136 }
1137
1138
1139 dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
1140                                        void *user_data)
1141 {
1142         struct wpa_supplicant *wpa_s = user_data;
1143
1144         if (wpa_s->dbus_groupobj_path == NULL)
1145                 return FALSE;
1146
1147         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1148                                                 &wpa_s->dbus_groupobj_path,
1149                                                 error);
1150 }
1151
1152
1153 dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
1154                                         DBusError *error, void *user_data)
1155 {
1156         struct wpa_supplicant *wpa_s = user_data;
1157         char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1158
1159         if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1160                 return FALSE;
1161
1162         os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1163                     "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1164                     wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1165         path = go_peer_obj_path;
1166         return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1167                                                 &path, error);
1168 }
1169
1170
1171 /*
1172  * Peer object properties accessor methods
1173  */
1174
1175 dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
1176         DBusError *error, void *user_data)
1177 {
1178         struct peer_handler_args *peer_args = user_data;
1179         DBusMessageIter variant_iter, dict_iter;
1180         const struct p2p_peer_info *info = NULL;
1181         const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1182         int i, num;
1183
1184         if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
1185                 return FALSE;
1186
1187         /* get the peer info */
1188         info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1189                                   peer_args->p2p_device_addr, 0);
1190         if (info == NULL) {
1191                 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1192                 return FALSE;
1193         }
1194
1195         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1196                                               "a{sv}", &variant_iter) ||
1197             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1198                 goto err_no_mem;
1199
1200         /* Fill out the dictionary */
1201         if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1202                                          info->device_name))
1203                 goto err_no_mem;
1204         if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
1205                                              (char *)info->pri_dev_type,
1206                                              WPS_DEV_TYPE_LEN))
1207                 goto err_no_mem;
1208         if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1209                                          info->config_methods))
1210                 goto err_no_mem;
1211         if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1212                                         info->level))
1213                 goto err_no_mem;
1214         if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1215                                        info->dev_capab))
1216                 goto err_no_mem;
1217         if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1218                                        info->group_capab))
1219                 goto err_no_mem;
1220
1221         if (info->wps_sec_dev_type_list_len) {
1222                 const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
1223                 int num_sec_dev_types =
1224                         info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
1225                 DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
1226                                 iter_secdev_dict_array;
1227
1228                 if (num_sec_dev_types) {
1229                         if (!wpa_dbus_dict_begin_array(&dict_iter,
1230                                                 "SecondaryDeviceTypes",
1231                                                 DBUS_TYPE_ARRAY_AS_STRING
1232                                                 DBUS_TYPE_BYTE_AS_STRING,
1233                                                 &iter_secdev_dict_entry,
1234                                                 &iter_secdev_dict_val,
1235                                                 &iter_secdev_dict_array))
1236                                 goto err_no_mem;
1237                         for (i = 0; i < num_sec_dev_types; i++) {
1238                                 wpa_dbus_dict_bin_array_add_element(
1239                                                 &iter_secdev_dict_array,
1240                                                 sec_dev_type_list,
1241                                                 WPS_DEV_TYPE_LEN);
1242                                 sec_dev_type_list += WPS_DEV_TYPE_LEN;
1243                         }
1244
1245                         if (!wpa_dbus_dict_end_array(&dict_iter,
1246                                                 &iter_secdev_dict_entry,
1247                                                 &iter_secdev_dict_val,
1248                                                 &iter_secdev_dict_array))
1249                                 goto err_no_mem;
1250                 }
1251         }
1252
1253         /* Add WPS vendor extensions attribute */
1254         for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1255                 if (info->wps_vendor_ext[i] == NULL)
1256                         continue;
1257                 vendor_extension[num] = info->wps_vendor_ext[i];
1258                 num++;
1259         }
1260
1261         if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension",
1262                                                vendor_extension, num))
1263                 goto err_no_mem;
1264
1265         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1266             !dbus_message_iter_close_container(iter, &variant_iter))
1267                 goto err_no_mem;
1268
1269         return TRUE;
1270
1271 err_no_mem:
1272         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1273         return FALSE;
1274 }
1275
1276
1277 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
1278                                           DBusError *error, void *user_data)
1279 {
1280         /* struct peer_handler_args *peer_args = user_data; */
1281
1282         dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
1283         return FALSE;
1284 }
1285
1286
1287 /**
1288  * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
1289  * @iter: Pointer to incoming dbus message iter
1290  * @error: Location to store error on failure
1291  * @user_data: Function specific data
1292  * Returns: TRUE on success, FALSE on failure
1293  *
1294  * Getter for "PersistentGroups" property.
1295  */
1296 dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
1297                                                DBusError *error,
1298                                                void *user_data)
1299 {
1300         struct wpa_supplicant *wpa_s = user_data;
1301         struct wpa_ssid *ssid;
1302         char **paths;
1303         unsigned int i = 0, num = 0;
1304         dbus_bool_t success = FALSE;
1305
1306         if (wpa_s->conf == NULL) {
1307                 wpa_printf(MSG_ERROR, "dbus: %s: "
1308                            "An error occurred getting persistent groups list",
1309                            __func__);
1310                 dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
1311                                      "occurred getting persistent groups list");
1312                 return FALSE;
1313         }
1314
1315         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1316                 if (network_is_persistent_group(ssid))
1317                         num++;
1318
1319         paths = os_zalloc(num * sizeof(char *));
1320         if (!paths) {
1321                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1322                 return FALSE;
1323         }
1324
1325         /* Loop through configured networks and append object path of each */
1326         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1327                 if (!network_is_persistent_group(ssid))
1328                         continue;
1329                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1330                 if (paths[i] == NULL) {
1331                         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
1332                                              "no memory");
1333                         goto out;
1334                 }
1335                 /* Construct the object path for this network. */
1336                 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1337                             "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1338                             wpa_s->dbus_new_path, ssid->id);
1339         }
1340
1341         success = wpas_dbus_simple_array_property_getter(iter,
1342                                                          DBUS_TYPE_OBJECT_PATH,
1343                                                          paths, num, error);
1344
1345 out:
1346         while (i)
1347                 os_free(paths[--i]);
1348         os_free(paths);
1349         return success;
1350 }
1351
1352
1353 /**
1354  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1355  *      group
1356  * @iter: Pointer to incoming dbus message iter
1357  * @error: Location to store error on failure
1358  * @user_data: Function specific data
1359  * Returns: TRUE on success, FALSE on failure
1360  *
1361  * Getter for "Properties" property of a persistent group.
1362  */
1363 dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
1364                                                          DBusError *error,
1365                                                          void *user_data)
1366 {
1367         struct network_handler_args *net = user_data;
1368
1369         /* Leveraging the fact that persistent group object is still
1370          * represented in same manner as network within.
1371          */
1372         return wpas_dbus_getter_network_properties(iter, error, net);
1373 }
1374
1375
1376 /**
1377  * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1378  *      group
1379  * @iter: Pointer to incoming dbus message iter
1380  * @error: Location to store error on failure
1381  * @user_data: Function specific data
1382  * Returns: TRUE on success, FALSE on failure
1383  *
1384  * Setter for "Properties" property of a persistent group.
1385  */
1386 dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
1387                                                          DBusError *error,
1388                                                          void *user_data)
1389 {
1390         struct network_handler_args *net = user_data;
1391         struct wpa_ssid *ssid = net->ssid;
1392         DBusMessageIter variant_iter;
1393
1394         /*
1395          * Leveraging the fact that persistent group object is still
1396          * represented in same manner as network within.
1397          */
1398         dbus_message_iter_recurse(iter, &variant_iter);
1399         return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
1400 }
1401
1402
1403 /**
1404  * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1405  *      persistent_group
1406  * @message: Pointer to incoming dbus message
1407  * @wpa_s: wpa_supplicant structure for a network interface
1408  * Returns: A dbus message containing the object path of the new
1409  * persistent group
1410  *
1411  * Handler function for "AddPersistentGroup" method call of a P2P Device
1412  * interface.
1413  */
1414 DBusMessage * wpas_dbus_handler_add_persistent_group(
1415         DBusMessage *message, struct wpa_supplicant *wpa_s)
1416 {
1417         DBusMessage *reply = NULL;
1418         DBusMessageIter iter;
1419         struct wpa_ssid *ssid = NULL;
1420         char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1421         DBusError error;
1422
1423         dbus_message_iter_init(message, &iter);
1424
1425         ssid = wpa_config_add_network(wpa_s->conf);
1426         if (ssid == NULL) {
1427                 wpa_printf(MSG_ERROR, "dbus: %s: "
1428                            "Cannot add new persistent group", __func__);
1429                 reply = wpas_dbus_error_unknown_error(
1430                         message,
1431                         "wpa_supplicant could not add "
1432                         "a persistent group on this interface.");
1433                 goto err;
1434         }
1435
1436         /* Mark the ssid as being a persistent group before the notification */
1437         ssid->disabled = 2;
1438         ssid->p2p_persistent_group = 1;
1439         wpas_notify_persistent_group_added(wpa_s, ssid);
1440
1441         wpa_config_set_network_defaults(ssid);
1442
1443         dbus_error_init(&error);
1444         if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1445                 wpa_printf(MSG_DEBUG, "dbus: %s: "
1446                            "Control interface could not set persistent group "
1447                            "properties", __func__);
1448                 reply = wpas_dbus_reply_new_from_error(message, &error,
1449                                                        DBUS_ERROR_INVALID_ARGS,
1450                                                        "Failed to set network "
1451                                                        "properties");
1452                 dbus_error_free(&error);
1453                 goto err;
1454         }
1455
1456         /* Construct the object path for this network. */
1457         os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1458                     "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1459                     wpa_s->dbus_new_path, ssid->id);
1460
1461         reply = dbus_message_new_method_return(message);
1462         if (reply == NULL) {
1463                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1464                                                NULL);
1465                 goto err;
1466         }
1467         if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1468                                       DBUS_TYPE_INVALID)) {
1469                 dbus_message_unref(reply);
1470                 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1471                                                NULL);
1472                 goto err;
1473         }
1474
1475         return reply;
1476
1477 err:
1478         if (ssid) {
1479                 wpas_notify_persistent_group_removed(wpa_s, ssid);
1480                 wpa_config_remove_network(wpa_s->conf, ssid->id);
1481         }
1482         return reply;
1483 }
1484
1485
1486 /**
1487  * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1488  *      group
1489  * @message: Pointer to incoming dbus message
1490  * @wpa_s: wpa_supplicant structure for a network interface
1491  * Returns: NULL on success or dbus error on failure
1492  *
1493  * Handler function for "RemovePersistentGroup" method call of a P2P Device
1494  * interface.
1495  */
1496 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1497         DBusMessage *message, struct wpa_supplicant *wpa_s)
1498 {
1499         DBusMessage *reply = NULL;
1500         const char *op;
1501         char *iface = NULL, *persistent_group_id = NULL;
1502         int id;
1503         struct wpa_ssid *ssid;
1504
1505         dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1506                               DBUS_TYPE_INVALID);
1507
1508         /*
1509          * Extract the network ID and ensure the network is actually a child of
1510          * this interface.
1511          */
1512         iface = wpas_dbus_new_decompose_object_path(op, 1,
1513                                                     &persistent_group_id,
1514                                                     NULL);
1515         if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1516                 reply = wpas_dbus_error_invalid_args(message, op);
1517                 goto out;
1518         }
1519
1520         id = strtoul(persistent_group_id, NULL, 10);
1521         if (errno == EINVAL) {
1522                 reply = wpas_dbus_error_invalid_args(message, op);
1523                 goto out;
1524         }
1525
1526         ssid = wpa_config_get_network(wpa_s->conf, id);
1527         if (ssid == NULL) {
1528                 reply = wpas_dbus_error_persistent_group_unknown(message);
1529                 goto out;
1530         }
1531
1532         wpas_notify_persistent_group_removed(wpa_s, ssid);
1533
1534         if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1535                 wpa_printf(MSG_ERROR, "dbus: %s: "
1536                            "error occurred when removing persistent group %d",
1537                            __func__, id);
1538                 reply = wpas_dbus_error_unknown_error(
1539                         message,
1540                         "error removing the specified persistent group on "
1541                         "this interface.");
1542                 goto out;
1543         }
1544
1545 out:
1546         os_free(iface);
1547         os_free(persistent_group_id);
1548         return reply;
1549 }
1550
1551
1552 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1553                                     struct wpa_ssid *ssid)
1554 {
1555         wpas_notify_persistent_group_removed(wpa_s, ssid);
1556
1557         if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1558                 wpa_printf(MSG_ERROR, "dbus: %s: "
1559                            "error occurred when removing persistent group %d",
1560                            __func__, ssid->id);
1561                 return;
1562         }
1563 }
1564
1565
1566 /**
1567  * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1568  * persistent groups
1569  * @message: Pointer to incoming dbus message
1570  * @wpa_s: wpa_supplicant structure for a network interface
1571  * Returns: NULL on success or dbus error on failure
1572  *
1573  * Handler function for "RemoveAllPersistentGroups" method call of a
1574  * P2P Device interface.
1575  */
1576 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1577         DBusMessage *message, struct wpa_supplicant *wpa_s)
1578 {
1579         struct wpa_ssid *ssid, *next;
1580         struct wpa_config *config;
1581
1582         config = wpa_s->conf;
1583         ssid = config->ssid;
1584         while (ssid) {
1585                 next = ssid->next;
1586                 if (network_is_persistent_group(ssid))
1587                         remove_persistent_group(wpa_s, ssid);
1588                 ssid = next;
1589         }
1590         return NULL;
1591 }
1592
1593
1594 /*
1595  * Group object properties accessor methods
1596  */
1597
1598 dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
1599                                                DBusError *error,
1600                                                void *user_data)
1601 {
1602         struct wpa_supplicant *wpa_s = user_data;
1603         struct wpa_ssid *ssid;
1604         unsigned int num_members;
1605         char **paths;
1606         unsigned int i;
1607         void *next = NULL;
1608         const u8 *addr;
1609         dbus_bool_t success = FALSE;
1610
1611         /* Ensure we are a GO */
1612         if (wpa_s->wpa_state != WPA_COMPLETED)
1613                 return FALSE;
1614
1615         ssid = wpa_s->conf->ssid;
1616         /* At present WPAS P2P_GO mode only applicable for p2p_go */
1617         if (ssid->mode != WPAS_MODE_P2P_GO &&
1618             ssid->mode != WPAS_MODE_AP &&
1619             ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1620                 return FALSE;
1621
1622         num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1623
1624         paths = os_zalloc(num_members * sizeof(char *));
1625         if (!paths)
1626                 goto out_of_memory;
1627
1628         i = 0;
1629         while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1630                 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1631                 if (!paths[i])
1632                         goto out_of_memory;
1633                 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1634                             "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1635                             "/" COMPACT_MACSTR,
1636                             wpa_s->dbus_groupobj_path, MAC2STR(addr));
1637                 i++;
1638         }
1639
1640         success = wpas_dbus_simple_array_property_getter(iter,
1641                                                          DBUS_TYPE_OBJECT_PATH,
1642                                                          paths, num_members,
1643                                                          error);
1644
1645         for (i = 0; i < num_members; i++)
1646                 os_free(paths[i]);
1647         os_free(paths);
1648         return success;
1649
1650 out_of_memory:
1651         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1652         if (paths) {
1653                 for (i = 0; i < num_members; i++)
1654                         os_free(paths[i]);
1655                 os_free(paths);
1656         }
1657         return FALSE;
1658 }
1659
1660
1661 dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
1662                                                   DBusError *error,
1663                                                   void *user_data)
1664 {
1665         struct wpa_supplicant *wpa_s = user_data;
1666         DBusMessageIter variant_iter, dict_iter;
1667         struct hostapd_data *hapd = NULL;
1668         const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1669         int num_vendor_ext = 0;
1670         int i;
1671         u8 role = wpas_get_p2p_role(wpa_s);
1672         u16 op_freq = 0;
1673         u8 *p_bssid = NULL;
1674         char *role_name = NULL;
1675
1676         if (!wpa_s->current_ssid)
1677                 return FALSE;
1678
1679         /* Check current role and adjust information accordingly */
1680         switch (role) {
1681         case WPAS_P2P_ROLE_CLIENT:
1682                 /* go_params is only valid for a client */
1683                 if (wpa_s->go_params) {
1684                         op_freq = wpa_s->go_params->freq;
1685                         p_bssid = wpa_s->current_ssid->bssid;
1686                         role_name = "client";
1687                 } else
1688                         return FALSE;
1689                 break;
1690         case WPAS_P2P_ROLE_GO:
1691                 /* ap_iface is only valid for a GO */
1692                 if (wpa_s->ap_iface) {
1693                         hapd = wpa_s->ap_iface->bss[0];
1694                         p_bssid = hapd->own_addr;
1695                         op_freq = wpa_s->ap_iface->freq;
1696                         role_name = "GO";
1697                 } else
1698                         return FALSE;
1699                 break;
1700         default:
1701                 /* Error condition; this should NEVER occur */
1702                 return FALSE;
1703         }
1704
1705         if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1706                                               "a{sv}", &variant_iter) ||
1707             !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1708                 goto err_no_mem;
1709         /* Provide the SSID */
1710         if (!wpa_dbus_dict_append_byte_array(
1711                     &dict_iter, "SSID",
1712                     (const char *) wpa_s->current_ssid->ssid,
1713                     wpa_s->current_ssid->ssid_len))
1714                 goto err_no_mem;
1715         /* Provide the BSSID */
1716         if (p_bssid &&
1717             !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
1718                                              (const char *) p_bssid, ETH_ALEN))
1719                 goto err_no_mem;
1720         /* Provide the role within the group */
1721         if (role_name &&
1722             !wpa_dbus_dict_append_string(&dict_iter, "Role", role_name))
1723                 goto err_no_mem;
1724         /* Provide the operational frequency */
1725         if (!wpa_dbus_dict_append_uint16(&dict_iter, "Frequency", op_freq))
1726                 goto err_no_mem;
1727
1728         /* Additional information for group owners */
1729         if (role == WPAS_P2P_ROLE_GO) {
1730                 /* Provide the passphrase */
1731                 if (!wpa_dbus_dict_append_string(&dict_iter, "Passphrase",
1732                                         wpa_s->current_ssid->passphrase))
1733                         goto err_no_mem;
1734                 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1735                 for (i = 0; hapd && i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1736                         if (hapd->conf->wps_vendor_ext[i] == NULL)
1737                                 continue;
1738                         vendor_ext[num_vendor_ext++] =
1739                                 hapd->conf->wps_vendor_ext[i];
1740                 }
1741                 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1742                                         "WPSVendorExtensions",
1743                                         vendor_ext, num_vendor_ext))
1744                         goto err_no_mem;
1745         } else {
1746                 /* If not a GO, provide the PSK */
1747                 if (!wpa_dbus_dict_append_byte_array(
1748                             &dict_iter, "PSK",
1749                             (const char *) wpa_s->current_ssid->psk, 32))
1750                         goto err_no_mem;
1751         }
1752
1753         if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1754             !dbus_message_iter_close_container(iter, &variant_iter))
1755                 goto err_no_mem;
1756
1757         return TRUE;
1758
1759 err_no_mem:
1760         dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1761         return FALSE;
1762 }
1763
1764
1765 dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
1766                                                   DBusError *error,
1767                                                   void *user_data)
1768 {
1769         struct wpa_supplicant *wpa_s = user_data;
1770         DBusMessageIter variant_iter, iter_dict;
1771         struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1772         unsigned int i;
1773         struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1774
1775         if (!hapd) {
1776                 dbus_set_error_const(error, DBUS_ERROR_FAILED,
1777                                      "internal error");
1778                 return FALSE;
1779         }
1780
1781         dbus_message_iter_recurse(iter, &variant_iter);
1782         if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
1783                 return FALSE;
1784
1785         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1786                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1787                         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1788                                              "invalid message format");
1789                         return FALSE;
1790                 }
1791
1792                 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1793                         if (entry.type != DBUS_TYPE_ARRAY ||
1794                             entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1795                             entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1796                                 goto error;
1797
1798                         for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1799                                 if (i < entry.array_len) {
1800                                         hapd->conf->wps_vendor_ext[i] =
1801                                                 entry.binarray_value[i];
1802                                         entry.binarray_value[i] = NULL;
1803                                 } else
1804                                         hapd->conf->wps_vendor_ext[i] = NULL;
1805                         }
1806
1807                         hostapd_update_wps(hapd);
1808                 } else
1809                         goto error;
1810
1811                 wpa_dbus_dict_entry_clear(&entry);
1812         }
1813
1814         return TRUE;
1815
1816 error:
1817         wpa_dbus_dict_entry_clear(&entry);
1818         dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1819                              "invalid message format");
1820         return FALSE;
1821 }
1822
1823
1824 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
1825                                                 struct wpa_supplicant *wpa_s)
1826 {
1827         DBusMessageIter iter_dict;
1828         DBusMessage *reply = NULL;
1829         DBusMessageIter iter;
1830         struct wpa_dbus_dict_entry entry;
1831         int upnp = 0;
1832         int bonjour = 0;
1833         char *service = NULL;
1834         struct wpabuf *query = NULL;
1835         struct wpabuf *resp = NULL;
1836         u8 version = 0;
1837
1838         dbus_message_iter_init(message, &iter);
1839
1840         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1841                 goto error;
1842
1843         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1844                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1845                         goto error;
1846
1847                 if (!os_strcmp(entry.key, "service_type") &&
1848                     (entry.type == DBUS_TYPE_STRING)) {
1849                         if (!os_strcmp(entry.str_value, "upnp"))
1850                                 upnp = 1;
1851                         else if (!os_strcmp(entry.str_value, "bonjour"))
1852                                 bonjour = 1;
1853                         else
1854                                 goto error_clear;
1855                         wpa_dbus_dict_entry_clear(&entry);
1856                 }
1857         }
1858
1859         if (upnp == 1) {
1860                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1861                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1862                                 goto error;
1863
1864                         if (!os_strcmp(entry.key, "version") &&
1865                             entry.type == DBUS_TYPE_INT32)
1866                                 version = entry.uint32_value;
1867                         else if (!os_strcmp(entry.key, "service") &&
1868                                  entry.type == DBUS_TYPE_STRING)
1869                                 service = os_strdup(entry.str_value);
1870                         wpa_dbus_dict_entry_clear(&entry);
1871                 }
1872                 if (version <= 0 || service == NULL)
1873                         goto error;
1874
1875                 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1876                         goto error;
1877
1878                 os_free(service);
1879         } else if (bonjour == 1) {
1880                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1881                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1882                                 goto error;
1883
1884                         if (!os_strcmp(entry.key, "query")) {
1885                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1886                                     (entry.array_type != DBUS_TYPE_BYTE))
1887                                         goto error_clear;
1888                                 query = wpabuf_alloc_copy(
1889                                         entry.bytearray_value,
1890                                         entry.array_len);
1891                         } else if (!os_strcmp(entry.key, "response")) {
1892                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1893                                     (entry.array_type != DBUS_TYPE_BYTE))
1894                                         goto error_clear;
1895                                 resp = wpabuf_alloc_copy(entry.bytearray_value,
1896                                                          entry.array_len);
1897                         }
1898
1899                         wpa_dbus_dict_entry_clear(&entry);
1900                 }
1901
1902                 if (query == NULL || resp == NULL)
1903                         goto error;
1904
1905                 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1906                         wpabuf_free(query);
1907                         wpabuf_free(resp);
1908                         goto error;
1909                 }
1910         } else
1911                 goto error;
1912
1913         return reply;
1914 error_clear:
1915         wpa_dbus_dict_entry_clear(&entry);
1916 error:
1917         return wpas_dbus_error_invalid_args(message, NULL);
1918 }
1919
1920
1921 DBusMessage * wpas_dbus_handler_p2p_delete_service(
1922         DBusMessage *message, struct wpa_supplicant *wpa_s)
1923 {
1924         DBusMessageIter iter_dict;
1925         DBusMessage *reply = NULL;
1926         DBusMessageIter iter;
1927         struct wpa_dbus_dict_entry entry;
1928         int upnp = 0;
1929         int bonjour = 0;
1930         int ret = 0;
1931         char *service = NULL;
1932         struct wpabuf *query = NULL;
1933         u8 version = 0;
1934
1935         dbus_message_iter_init(message, &iter);
1936
1937         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1938                 goto error;
1939
1940         if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1941                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1942                         goto error;
1943
1944                 if (!os_strcmp(entry.key, "service_type") &&
1945                     (entry.type == DBUS_TYPE_STRING)) {
1946                         if (!os_strcmp(entry.str_value, "upnp"))
1947                                 upnp = 1;
1948                         else if (!os_strcmp(entry.str_value, "bonjour"))
1949                                 bonjour = 1;
1950                         else
1951                                 goto error_clear;
1952                         wpa_dbus_dict_entry_clear(&entry);
1953                 }
1954         }
1955         if (upnp == 1) {
1956                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1957                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1958                                 goto error;
1959                         if (!os_strcmp(entry.key, "version") &&
1960                             entry.type == DBUS_TYPE_INT32)
1961                                 version = entry.uint32_value;
1962                         else if (!os_strcmp(entry.key, "service") &&
1963                                  entry.type == DBUS_TYPE_STRING)
1964                                 service = os_strdup(entry.str_value);
1965                         else
1966                                 goto error_clear;
1967
1968                         wpa_dbus_dict_entry_clear(&entry);
1969                 }
1970
1971                 if (version <= 0 || service == NULL)
1972                         goto error;
1973
1974                 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1975                 os_free(service);
1976                 if (ret != 0)
1977                         goto error;
1978         } else if (bonjour == 1) {
1979                 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1980                         if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1981                                 goto error;
1982
1983                         if (!os_strcmp(entry.key, "query")) {
1984                                 if ((entry.type != DBUS_TYPE_ARRAY) ||
1985                                     (entry.array_type != DBUS_TYPE_BYTE))
1986                                         goto error_clear;
1987                                 query = wpabuf_alloc_copy(
1988                                         entry.bytearray_value,
1989                                         entry.array_len);
1990                         } else
1991                                 goto error_clear;
1992
1993                         wpa_dbus_dict_entry_clear(&entry);
1994                 }
1995
1996                 if (query == NULL)
1997                         goto error;
1998
1999                 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
2000                 if (ret != 0)
2001                         goto error;
2002                 wpabuf_free(query);
2003         } else
2004                 goto error;
2005
2006         return reply;
2007 error_clear:
2008         wpa_dbus_dict_entry_clear(&entry);
2009 error:
2010         return wpas_dbus_error_invalid_args(message, NULL);
2011 }
2012
2013
2014 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
2015                                                   struct wpa_supplicant *wpa_s)
2016 {
2017         wpas_p2p_service_flush(wpa_s);
2018         return NULL;
2019 }
2020
2021
2022 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
2023         DBusMessage *message, struct wpa_supplicant *wpa_s)
2024 {
2025         DBusMessageIter iter_dict;
2026         DBusMessage *reply = NULL;
2027         DBusMessageIter iter;
2028         struct wpa_dbus_dict_entry entry;
2029         int upnp = 0;
2030         char *service = NULL;
2031         char *peer_object_path = NULL;
2032         struct wpabuf *tlv = NULL;
2033         u8 version = 0;
2034         u64 ref = 0;
2035         u8 addr[ETH_ALEN];
2036
2037         dbus_message_iter_init(message, &iter);
2038
2039         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2040                 goto error;
2041
2042         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2043                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2044                         goto error;
2045                 if (!os_strcmp(entry.key, "peer_object") &&
2046                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2047                         peer_object_path = os_strdup(entry.str_value);
2048                 } else if (!os_strcmp(entry.key, "service_type") &&
2049                            entry.type == DBUS_TYPE_STRING) {
2050                         if (!os_strcmp(entry.str_value, "upnp"))
2051                                 upnp = 1;
2052                         else
2053                                 goto error_clear;
2054                 } else if (!os_strcmp(entry.key, "version") &&
2055                            entry.type == DBUS_TYPE_INT32) {
2056                         version = entry.uint32_value;
2057                 } else if (!os_strcmp(entry.key, "service") &&
2058                            entry.type == DBUS_TYPE_STRING) {
2059                         service = os_strdup(entry.str_value);
2060                 } else if (!os_strcmp(entry.key, "tlv")) {
2061                         if (entry.type != DBUS_TYPE_ARRAY ||
2062                             entry.array_type != DBUS_TYPE_BYTE)
2063                                 goto error_clear;
2064                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2065                                                 entry.array_len);
2066                 } else
2067                         goto error_clear;
2068
2069                 wpa_dbus_dict_entry_clear(&entry);
2070         }
2071
2072         if (!peer_object_path ||
2073             (parse_peer_object_path(peer_object_path, addr) < 0) ||
2074             !p2p_peer_known(wpa_s->global->p2p, addr))
2075                 goto error;
2076
2077         if (upnp == 1) {
2078                 if (version <= 0 || service == NULL)
2079                         goto error;
2080
2081                 ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
2082         } else {
2083                 if (tlv == NULL)
2084                         goto error;
2085                 ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
2086                 wpabuf_free(tlv);
2087         }
2088
2089         if (ref != 0) {
2090                 reply = dbus_message_new_method_return(message);
2091                 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2092                                          &ref, DBUS_TYPE_INVALID);
2093         } else {
2094                 reply = wpas_dbus_error_unknown_error(
2095                         message, "Unable to send SD request");
2096         }
2097 out:
2098         os_free(service);
2099         os_free(peer_object_path);
2100         return reply;
2101 error_clear:
2102         wpa_dbus_dict_entry_clear(&entry);
2103 error:
2104         if (tlv)
2105                 wpabuf_free(tlv);
2106         reply = wpas_dbus_error_invalid_args(message, NULL);
2107         goto out;
2108 }
2109
2110
2111 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2112         DBusMessage *message, struct wpa_supplicant *wpa_s)
2113 {
2114         DBusMessageIter iter_dict;
2115         DBusMessage *reply = NULL;
2116         DBusMessageIter iter;
2117         struct wpa_dbus_dict_entry entry;
2118         char *peer_object_path = NULL;
2119         struct wpabuf *tlv = NULL;
2120         int freq = 0;
2121         int dlg_tok = 0;
2122         u8 addr[ETH_ALEN];
2123
2124         dbus_message_iter_init(message, &iter);
2125
2126         if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2127                 goto error;
2128
2129         while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2130                 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2131                         goto error;
2132
2133                 if (!os_strcmp(entry.key, "peer_object") &&
2134                     entry.type == DBUS_TYPE_OBJECT_PATH) {
2135                         peer_object_path = os_strdup(entry.str_value);
2136                 } else if (!os_strcmp(entry.key, "frequency") &&
2137                            entry.type == DBUS_TYPE_INT32) {
2138                         freq = entry.uint32_value;
2139                 } else if (!os_strcmp(entry.key, "dialog_token") &&
2140                            entry.type == DBUS_TYPE_UINT32) {
2141                         dlg_tok = entry.uint32_value;
2142                 } else if (!os_strcmp(entry.key, "tlvs")) {
2143                         if (entry.type != DBUS_TYPE_ARRAY ||
2144                             entry.array_type != DBUS_TYPE_BYTE)
2145                                 goto error_clear;
2146                         tlv = wpabuf_alloc_copy(entry.bytearray_value,
2147                                                 entry.array_len);
2148                 } else
2149                         goto error_clear;
2150
2151                 wpa_dbus_dict_entry_clear(&entry);
2152         }
2153         if (!peer_object_path ||
2154             (parse_peer_object_path(peer_object_path, addr) < 0) ||
2155             !p2p_peer_known(wpa_s->global->p2p, addr))
2156                 goto error;
2157
2158         if (tlv == NULL)
2159                 goto error;
2160
2161         wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2162         wpabuf_free(tlv);
2163 out:
2164         os_free(peer_object_path);
2165         return reply;
2166 error_clear:
2167         wpa_dbus_dict_entry_clear(&entry);
2168 error:
2169         reply = wpas_dbus_error_invalid_args(message, NULL);
2170         goto out;
2171 }
2172
2173
2174 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2175         DBusMessage *message, struct wpa_supplicant *wpa_s)
2176 {
2177         DBusMessageIter iter;
2178         u64 req = 0;
2179
2180         dbus_message_iter_init(message, &iter);
2181         dbus_message_iter_get_basic(&iter, &req);
2182
2183         if (req == 0)
2184                 goto error;
2185
2186         if (!wpas_p2p_sd_cancel_request(wpa_s, req))
2187                 goto error;
2188
2189         return NULL;
2190 error:
2191         return wpas_dbus_error_invalid_args(message, NULL);
2192 }
2193
2194
2195 DBusMessage * wpas_dbus_handler_p2p_service_update(
2196         DBusMessage *message, struct wpa_supplicant *wpa_s)
2197 {
2198         wpas_p2p_sd_service_update(wpa_s);
2199         return NULL;
2200 }
2201
2202
2203 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2204         DBusMessage *message, struct wpa_supplicant *wpa_s)
2205 {
2206         DBusMessageIter iter;
2207         int ext = 0;
2208
2209         dbus_message_iter_init(message, &iter);
2210         dbus_message_iter_get_basic(&iter, &ext);
2211
2212         wpa_s->p2p_sd_over_ctrl_iface = ext;
2213
2214         return NULL;
2215
2216 }