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