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