xref: /dragonfly/contrib/wpa_supplicant/wpa_supplicant/dbus/dbus_new_handlers.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1 /*
2  * WPA Supplicant / dbus-based control interface
3  * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4  * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
5  * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
6  *
7  * This software may be distributed under the terms of the BSD license.
8  * See README for more details.
9  */
10 
11 #include "includes.h"
12 
13 #include "common.h"
14 #include "common/ieee802_11_defs.h"
15 #include "eap_peer/eap_methods.h"
16 #include "eapol_supp/eapol_supp_sm.h"
17 #include "rsn_supp/wpa.h"
18 #include "ap/hostapd.h"
19 #include "ap/sta_info.h"
20 #include "ap/ap_drv_ops.h"
21 #include "../config.h"
22 #include "../wpa_supplicant_i.h"
23 #include "../driver_i.h"
24 #include "../notify.h"
25 #include "../bss.h"
26 #include "../scan.h"
27 #include "../autoscan.h"
28 #include "../ap.h"
29 #include "dbus_new_helpers.h"
30 #include "dbus_new.h"
31 #include "dbus_new_handlers.h"
32 #include "dbus_dict_helpers.h"
33 #include "dbus_common_i.h"
34 #include "drivers/driver.h"
35 #ifdef CONFIG_MESH
36 #include "ap/hostapd.h"
37 #include "ap/sta_info.h"
38 #endif /* CONFIG_MESH */
39 
40 static const char * const debug_strings[] = {
41           "excessive", "msgdump", "debug", "info", "warning", "error", NULL
42 };
43 
44 
45 /**
46  * wpas_dbus_error_unknown_error - Return a new UnknownError error message
47  * @message: Pointer to incoming dbus message this error refers to
48  * @arg: Optional string appended to error message
49  * Returns: a dbus error message
50  *
51  * Convenience function to create and return an UnknownError
52  */
wpas_dbus_error_unknown_error(DBusMessage * message,const char * arg)53 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
54                                                       const char *arg)
55 {
56           return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
57                                               arg);
58 }
59 
60 
61 /**
62  * wpas_dbus_error_iface_unknown - Return a new invalid interface error message
63  * @message: Pointer to incoming dbus message this error refers to
64  * Returns: A dbus error message
65  *
66  * Convenience function to create and return an invalid interface error
67  */
wpas_dbus_error_iface_unknown(DBusMessage * message)68 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
69 {
70           return dbus_message_new_error(
71                     message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
72                     "wpa_supplicant knows nothing about this interface.");
73 }
74 
75 
76 /**
77  * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message
78  * @message: Pointer to incoming dbus message this error refers to
79  * Returns: a dbus error message
80  *
81  * Convenience function to create and return an invalid network error
82  */
wpas_dbus_error_network_unknown(DBusMessage * message)83 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
84 {
85           return dbus_message_new_error(
86                     message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
87                     "There is no such a network in this interface.");
88 }
89 
90 
91 /**
92  * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message
93  * @message: Pointer to incoming dbus message this error refers to
94  * Returns: a dbus error message
95  *
96  * Convenience function to create and return an invalid options error
97  */
wpas_dbus_error_invalid_args(DBusMessage * message,const char * arg)98 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
99                                                     const char *arg)
100 {
101           DBusMessage *reply;
102 
103           reply = dbus_message_new_error(
104                     message, WPAS_DBUS_ERROR_INVALID_ARGS,
105                     "Did not receive correct message arguments.");
106           if (arg != NULL)
107                     dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
108                                                    DBUS_TYPE_INVALID);
109 
110           return reply;
111 }
112 
113 
114 /**
115  * wpas_dbus_error_scan_error - Return a new ScanError error message
116  * @message: Pointer to incoming dbus message this error refers to
117  * @error: Optional string to be used as the error message
118  * Returns: a dbus error message
119  *
120  * Convenience function to create and return a scan error
121  */
wpas_dbus_error_scan_error(DBusMessage * message,const char * error)122 static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
123                                                             const char *error)
124 {
125           return dbus_message_new_error(message,
126                                               WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
127                                               error);
128 }
129 
130 
wpas_dbus_error_no_memory(DBusMessage * message)131 DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
132 {
133           wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
134           return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
135 }
136 
137 
138 static const char * const dont_quote[] = {
139           "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
140           "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
141           "bssid", "scan_freq", "freq_list", NULL
142 };
143 
should_quote_opt(const char * key)144 static dbus_bool_t should_quote_opt(const char *key)
145 {
146           int i = 0;
147 
148           while (dont_quote[i] != NULL) {
149                     if (os_strcmp(key, dont_quote[i]) == 0)
150                               return FALSE;
151                     i++;
152           }
153           return TRUE;
154 }
155 
156 /**
157  * get_iface_by_dbus_path - Get a new network interface
158  * @global: Pointer to global data from wpa_supplicant_init()
159  * @path: Pointer to a dbus object path representing an interface
160  * Returns: Pointer to the interface or %NULL if not found
161  */
get_iface_by_dbus_path(struct wpa_global * global,const char * path)162 static struct wpa_supplicant * get_iface_by_dbus_path(
163           struct wpa_global *global, const char *path)
164 {
165           struct wpa_supplicant *wpa_s;
166 
167           for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
168                     if (wpa_s->dbus_new_path &&
169                         os_strcmp(wpa_s->dbus_new_path, path) == 0)
170                               return wpa_s;
171           }
172           return NULL;
173 }
174 
175 
176 /**
177  * set_network_properties - Set properties of a configured network
178  * @wpa_s: wpa_supplicant structure for a network interface
179  * @ssid: wpa_ssid structure for a configured network
180  * @iter: DBus message iterator containing dictionary of network
181  * properties to set.
182  * @error: On failure, an error describing the failure
183  * Returns: TRUE if the request succeeds, FALSE if it failed
184  *
185  * Sets network configuration with parameters given id DBus dictionary
186  */
set_network_properties(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,DBusMessageIter * iter,DBusError * error)187 dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
188                                            struct wpa_ssid *ssid,
189                                            DBusMessageIter *iter,
190                                            DBusError *error)
191 {
192           struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
193           DBusMessageIter     iter_dict;
194           char *value = NULL;
195 
196           if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
197                     return FALSE;
198 
199           while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
200                     size_t size = 50;
201                     int ret;
202 
203                     if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
204                               goto error;
205 
206                     value = NULL;
207                     if (entry.type == DBUS_TYPE_ARRAY &&
208                         entry.array_type == DBUS_TYPE_BYTE) {
209                               if (entry.array_len <= 0)
210                                         goto error;
211 
212                               size = entry.array_len * 2 + 1;
213                               value = os_zalloc(size);
214                               if (value == NULL)
215                                         goto error;
216 
217                               ret = wpa_snprintf_hex(value, size,
218                                                          (u8 *) entry.bytearray_value,
219                                                          entry.array_len);
220                               if (ret <= 0)
221                                         goto error;
222                     } else if (entry.type == DBUS_TYPE_STRING) {
223                               if (should_quote_opt(entry.key)) {
224                                         size = os_strlen(entry.str_value);
225                                         if (size == 0)
226                                                   goto error;
227 
228                                         size += 3;
229                                         value = os_zalloc(size);
230                                         if (value == NULL)
231                                                   goto error;
232 
233                                         ret = os_snprintf(value, size, "\"%s\"",
234                                                               entry.str_value);
235                                         if (os_snprintf_error(size, ret))
236                                                   goto error;
237                               } else {
238                                         value = os_strdup(entry.str_value);
239                                         if (value == NULL)
240                                                   goto error;
241                               }
242                     } else if (entry.type == DBUS_TYPE_UINT32) {
243                               value = os_zalloc(size);
244                               if (value == NULL)
245                                         goto error;
246 
247                               ret = os_snprintf(value, size, "%u",
248                                                     entry.uint32_value);
249                               if (os_snprintf_error(size, ret))
250                                         goto error;
251                     } else if (entry.type == DBUS_TYPE_INT32) {
252                               value = os_zalloc(size);
253                               if (value == NULL)
254                                         goto error;
255 
256                               ret = os_snprintf(value, size, "%d",
257                                                     entry.int32_value);
258                               if (os_snprintf_error(size, ret))
259                                         goto error;
260                     } else
261                               goto error;
262 
263                     if (wpa_config_set(ssid, entry.key, value, 0) < 0)
264                               goto error;
265 
266                     if (os_strcmp(entry.key, "bssid") != 0 &&
267                         os_strcmp(entry.key, "priority") != 0)
268                               wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
269 
270                     if (wpa_s->current_ssid == ssid ||
271                         wpa_s->current_ssid == NULL) {
272                               /*
273                                * Invalidate the EAP session cache if anything in the
274                                * current or previously used configuration changes.
275                                */
276                               eapol_sm_invalidate_cached_session(wpa_s->eapol);
277                     }
278 
279                     if ((os_strcmp(entry.key, "psk") == 0 &&
280                          value[0] == '"' && ssid->ssid_len) ||
281                         (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
282                               wpa_config_update_psk(ssid);
283                     else if (os_strcmp(entry.key, "priority") == 0)
284                               wpa_config_update_prio_list(wpa_s->conf);
285 
286                     os_free(value);
287                     value = NULL;
288                     wpa_dbus_dict_entry_clear(&entry);
289           }
290 
291           return TRUE;
292 
293 error:
294           os_free(value);
295           wpa_dbus_dict_entry_clear(&entry);
296           dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
297                                    "invalid message format");
298           return FALSE;
299 }
300 
301 
302 /**
303  * wpas_dbus_simple_property_getter - Get basic type property
304  * @iter: Message iter to use when appending arguments
305  * @type: DBus type of property (must be basic type)
306  * @val: pointer to place holding property value
307  * @error: On failure an error describing the failure
308  * Returns: TRUE if the request was successful, FALSE if it failed
309  *
310  * Generic getter for basic type properties. Type is required to be basic.
311  */
wpas_dbus_simple_property_getter(DBusMessageIter * iter,const int type,const void * val,DBusError * error)312 dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
313                                                        const int type,
314                                                        const void *val,
315                                                        DBusError *error)
316 {
317           DBusMessageIter variant_iter;
318 
319           if (!dbus_type_is_basic(type)) {
320                     dbus_set_error(error, DBUS_ERROR_FAILED,
321                                      "%s: given type is not basic", __func__);
322                     return FALSE;
323           }
324 
325           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
326                                                         wpa_dbus_type_as_string(type),
327                                                         &variant_iter) ||
328               !dbus_message_iter_append_basic(&variant_iter, type, val) ||
329               !dbus_message_iter_close_container(iter, &variant_iter)) {
330                     dbus_set_error(error, DBUS_ERROR_FAILED,
331                                      "%s: error constructing reply", __func__);
332                     return FALSE;
333           }
334 
335           return TRUE;
336 }
337 
338 
339 /**
340  * wpas_dbus_simple_property_setter - Set basic type property
341  * @message: Pointer to incoming dbus message
342  * @type: DBus type of property (must be basic type)
343  * @val: pointer to place where value being set will be stored
344  * Returns: TRUE if the request was successful, FALSE if it failed
345  *
346  * Generic setter for basic type properties. Type is required to be basic.
347  */
wpas_dbus_simple_property_setter(DBusMessageIter * iter,DBusError * error,const int type,void * val)348 dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
349                                                        DBusError *error,
350                                                        const int type, void *val)
351 {
352           DBusMessageIter variant_iter;
353 
354           if (!dbus_type_is_basic(type)) {
355                     dbus_set_error(error, DBUS_ERROR_FAILED,
356                                      "%s: given type is not basic", __func__);
357                     return FALSE;
358           }
359 
360           /* Look at the new value */
361           dbus_message_iter_recurse(iter, &variant_iter);
362           if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
363                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
364                                              "wrong property type");
365                     return FALSE;
366           }
367           dbus_message_iter_get_basic(&variant_iter, val);
368 
369           return TRUE;
370 }
371 
372 
373 /**
374  * wpas_dbus_simple_array_property_getter - Get array type property
375  * @iter: Pointer to incoming dbus message iterator
376  * @type: DBus type of property array elements (must be basic type)
377  * @array: pointer to array of elements to put into response message
378  * @array_len: length of above array
379  * @error: a pointer to an error to fill on failure
380  * Returns: TRUE if the request succeeded, FALSE if it failed
381  *
382  * Generic getter for array type properties. Array elements type is
383  * required to be basic.
384  */
wpas_dbus_simple_array_property_getter(DBusMessageIter * iter,const int type,const void * array,size_t array_len,DBusError * error)385 dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
386                                                                const int type,
387                                                                const void *array,
388                                                                size_t array_len,
389                                                                DBusError *error)
390 {
391           DBusMessageIter variant_iter, array_iter;
392           char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
393           const char *sub_type_str;
394           size_t element_size, i;
395 
396           if (!dbus_type_is_basic(type)) {
397                     dbus_set_error(error, DBUS_ERROR_FAILED,
398                                      "%s: given type is not basic", __func__);
399                     return FALSE;
400           }
401 
402           sub_type_str = wpa_dbus_type_as_string(type);
403           type_str[1] = sub_type_str[0];
404 
405           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
406                                                         type_str, &variant_iter) ||
407               !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
408                                                         sub_type_str, &array_iter)) {
409                     dbus_set_error(error, DBUS_ERROR_FAILED,
410                                      "%s: failed to construct message", __func__);
411                     return FALSE;
412           }
413 
414           switch (type) {
415           case DBUS_TYPE_BYTE:
416           case DBUS_TYPE_BOOLEAN:
417                     element_size = 1;
418                     break;
419           case DBUS_TYPE_INT16:
420           case DBUS_TYPE_UINT16:
421                     element_size = sizeof(uint16_t);
422                     break;
423           case DBUS_TYPE_INT32:
424           case DBUS_TYPE_UINT32:
425                     element_size = sizeof(uint32_t);
426                     break;
427           case DBUS_TYPE_INT64:
428           case DBUS_TYPE_UINT64:
429                     element_size = sizeof(uint64_t);
430                     break;
431           case DBUS_TYPE_DOUBLE:
432                     element_size = sizeof(double);
433                     break;
434           case DBUS_TYPE_STRING:
435           case DBUS_TYPE_OBJECT_PATH:
436                     element_size = sizeof(char *);
437                     break;
438           default:
439                     dbus_set_error(error, DBUS_ERROR_FAILED,
440                                      "%s: unknown element type %d", __func__, type);
441                     return FALSE;
442           }
443 
444           for (i = 0; i < array_len; i++) {
445                     if (!dbus_message_iter_append_basic(&array_iter, type,
446                                                                 (const char *) array +
447                                                                 i * element_size)) {
448                               dbus_set_error(error, DBUS_ERROR_FAILED,
449                                                "%s: failed to construct message 2.5",
450                                                __func__);
451                               return FALSE;
452                     }
453           }
454 
455           if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
456               !dbus_message_iter_close_container(iter, &variant_iter)) {
457                     dbus_set_error(error, DBUS_ERROR_FAILED,
458                                      "%s: failed to construct message 3", __func__);
459                     return FALSE;
460           }
461 
462           return TRUE;
463 }
464 
465 
466 /**
467  * wpas_dbus_simple_array_array_property_getter - Get array array type property
468  * @iter: Pointer to incoming dbus message iterator
469  * @type: DBus type of property array elements (must be basic type)
470  * @array: pointer to array of elements to put into response message
471  * @array_len: length of above array
472  * @error: a pointer to an error to fill on failure
473  * Returns: TRUE if the request succeeded, FALSE if it failed
474  *
475  * Generic getter for array type properties. Array elements type is
476  * required to be basic.
477  */
wpas_dbus_simple_array_array_property_getter(DBusMessageIter * iter,const int type,struct wpabuf ** array,size_t array_len,DBusError * error)478 dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter,
479                                                                        const int type,
480                                                                        struct wpabuf **array,
481                                                                        size_t array_len,
482                                                                        DBusError *error)
483 {
484           DBusMessageIter variant_iter, array_iter;
485           char type_str[] = "aa?";
486           char inner_type_str[] = "a?";
487           const char *sub_type_str;
488           size_t i;
489 
490           if (!dbus_type_is_basic(type)) {
491                     dbus_set_error(error, DBUS_ERROR_FAILED,
492                                      "%s: given type is not basic", __func__);
493                     return FALSE;
494           }
495 
496           sub_type_str = wpa_dbus_type_as_string(type);
497           type_str[2] = sub_type_str[0];
498           inner_type_str[1] = sub_type_str[0];
499 
500           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
501                                                         type_str, &variant_iter) ||
502               !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
503                                                         inner_type_str, &array_iter)) {
504                     dbus_set_error(error, DBUS_ERROR_FAILED,
505                                      "%s: failed to construct message", __func__);
506                     return FALSE;
507           }
508 
509           for (i = 0; i < array_len && array[i]; i++) {
510                     wpa_dbus_dict_bin_array_add_element(&array_iter,
511                                                                 wpabuf_head(array[i]),
512                                                                 wpabuf_len(array[i]));
513 
514           }
515 
516           if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
517               !dbus_message_iter_close_container(iter, &variant_iter)) {
518                     dbus_set_error(error, DBUS_ERROR_FAILED,
519                                      "%s: failed to close message", __func__);
520                     return FALSE;
521           }
522 
523           return TRUE;
524 }
525 
526 
527 /**
528  * wpas_dbus_string_property_getter - Get string type property
529  * @iter: Message iter to use when appending arguments
530  * @val: Pointer to place holding property value, can be %NULL
531  * @error: On failure an error describing the failure
532  * Returns: TRUE if the request was successful, FALSE if it failed
533  *
534  * Generic getter for string type properties. %NULL is converted to an empty
535  * string.
536  */
wpas_dbus_string_property_getter(DBusMessageIter * iter,const void * val,DBusError * error)537 dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
538                                                        const void *val,
539                                                        DBusError *error)
540 {
541           if (!val)
542                     val = "";
543           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
544                                                             &val, error);
545 }
546 
547 
548 /**
549  * wpas_dbus_handler_create_interface - Request registration of a network iface
550  * @message: Pointer to incoming dbus message
551  * @global: %wpa_supplicant global data structure
552  * Returns: The object path of the new interface object,
553  *          or a dbus error message with more information
554  *
555  * Handler function for "CreateInterface" method call. Handles requests
556  * by dbus clients to register a network interface that wpa_supplicant
557  * will manage.
558  */
wpas_dbus_handler_create_interface(DBusMessage * message,struct wpa_global * global)559 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
560                                                              struct wpa_global *global)
561 {
562           DBusMessageIter iter_dict;
563           DBusMessage *reply = NULL;
564           DBusMessageIter iter;
565           struct wpa_dbus_dict_entry entry;
566           char *driver = NULL;
567           char *ifname = NULL;
568           char *confname = NULL;
569           char *bridge_ifname = NULL;
570 
571           dbus_message_iter_init(message, &iter);
572 
573           if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
574                     goto error;
575           while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
576                     if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
577                               goto error;
578                     if (os_strcmp(entry.key, "Driver") == 0 &&
579                         entry.type == DBUS_TYPE_STRING) {
580                               os_free(driver);
581                               driver = os_strdup(entry.str_value);
582                               wpa_dbus_dict_entry_clear(&entry);
583                               if (driver == NULL)
584                                         goto oom;
585                     } else if (os_strcmp(entry.key, "Ifname") == 0 &&
586                                  entry.type == DBUS_TYPE_STRING) {
587                               os_free(ifname);
588                               ifname = os_strdup(entry.str_value);
589                               wpa_dbus_dict_entry_clear(&entry);
590                               if (ifname == NULL)
591                                         goto oom;
592                     } else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
593                                  entry.type == DBUS_TYPE_STRING) {
594                               os_free(confname);
595                               confname = os_strdup(entry.str_value);
596                               wpa_dbus_dict_entry_clear(&entry);
597                               if (confname == NULL)
598                                         goto oom;
599                     } else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
600                                  entry.type == DBUS_TYPE_STRING) {
601                               os_free(bridge_ifname);
602                               bridge_ifname = os_strdup(entry.str_value);
603                               wpa_dbus_dict_entry_clear(&entry);
604                               if (bridge_ifname == NULL)
605                                         goto oom;
606                     } else {
607                               wpa_dbus_dict_entry_clear(&entry);
608                               goto error;
609                     }
610           }
611 
612           if (ifname == NULL)
613                     goto error; /* Required Ifname argument missing */
614 
615           /*
616            * Try to get the wpa_supplicant record for this iface, return
617            * an error if we already control it.
618            */
619           if (wpa_supplicant_get_iface(global, ifname) != NULL) {
620                     reply = dbus_message_new_error(
621                               message, WPAS_DBUS_ERROR_IFACE_EXISTS,
622                               "wpa_supplicant already controls this interface.");
623           } else {
624                     struct wpa_supplicant *wpa_s;
625                     struct wpa_interface iface;
626 
627                     os_memset(&iface, 0, sizeof(iface));
628                     iface.driver = driver;
629                     iface.ifname = ifname;
630                     iface.confname = confname;
631                     iface.bridge_ifname = bridge_ifname;
632                     /* Otherwise, have wpa_supplicant attach to it. */
633                     wpa_s = wpa_supplicant_add_iface(global, &iface, NULL);
634                     if (wpa_s && wpa_s->dbus_new_path) {
635                               const char *path = wpa_s->dbus_new_path;
636 
637                               reply = dbus_message_new_method_return(message);
638                               dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
639                                                              &path, DBUS_TYPE_INVALID);
640                     } else {
641                               reply = wpas_dbus_error_unknown_error(
642                                         message,
643                                         "wpa_supplicant couldn't grab this interface.");
644                     }
645           }
646 
647 out:
648           os_free(driver);
649           os_free(ifname);
650           os_free(confname);
651           os_free(bridge_ifname);
652           return reply;
653 
654 error:
655           reply = wpas_dbus_error_invalid_args(message, NULL);
656           goto out;
657 oom:
658           reply = wpas_dbus_error_no_memory(message);
659           goto out;
660 }
661 
662 
663 /**
664  * wpas_dbus_handler_remove_interface - Request deregistration of an interface
665  * @message: Pointer to incoming dbus message
666  * @global: wpa_supplicant global data structure
667  * Returns: a dbus message containing a UINT32 indicating success (1) or
668  *          failure (0), or returns a dbus error message with more information
669  *
670  * Handler function for "removeInterface" method call.  Handles requests
671  * by dbus clients to deregister a network interface that wpa_supplicant
672  * currently manages.
673  */
wpas_dbus_handler_remove_interface(DBusMessage * message,struct wpa_global * global)674 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message,
675                                                              struct wpa_global *global)
676 {
677           struct wpa_supplicant *wpa_s;
678           char *path;
679           DBusMessage *reply = NULL;
680 
681           dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
682                                     DBUS_TYPE_INVALID);
683 
684           wpa_s = get_iface_by_dbus_path(global, path);
685           if (wpa_s == NULL)
686                     reply = wpas_dbus_error_iface_unknown(message);
687           else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
688                     reply = wpas_dbus_error_unknown_error(
689                               message,
690                               "wpa_supplicant couldn't remove this interface.");
691           }
692 
693           return reply;
694 }
695 
696 
697 /**
698  * wpas_dbus_handler_get_interface - Get the object path for an interface name
699  * @message: Pointer to incoming dbus message
700  * @global: %wpa_supplicant global data structure
701  * Returns: The object path of the interface object,
702  *          or a dbus error message with more information
703  *
704  * Handler function for "getInterface" method call.
705  */
wpas_dbus_handler_get_interface(DBusMessage * message,struct wpa_global * global)706 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
707                                                         struct wpa_global *global)
708 {
709           DBusMessage *reply = NULL;
710           const char *ifname;
711           const char *path;
712           struct wpa_supplicant *wpa_s;
713 
714           dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname,
715                                     DBUS_TYPE_INVALID);
716 
717           wpa_s = wpa_supplicant_get_iface(global, ifname);
718           if (wpa_s == NULL || wpa_s->dbus_new_path == NULL)
719                     return wpas_dbus_error_iface_unknown(message);
720 
721           path = wpa_s->dbus_new_path;
722           reply = dbus_message_new_method_return(message);
723           if (reply == NULL)
724                     return wpas_dbus_error_no_memory(message);
725           if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
726                                               DBUS_TYPE_INVALID)) {
727                     dbus_message_unref(reply);
728                     return wpas_dbus_error_no_memory(message);
729           }
730 
731           return reply;
732 }
733 
734 
735 /**
736  * wpas_dbus_getter_debug_level - Get debug level
737  * @iter: Pointer to incoming dbus message iter
738  * @error: Location to store error on failure
739  * @user_data: Function specific data
740  * Returns: TRUE on success, FALSE on failure
741  *
742  * Getter for "DebugLevel" property.
743  */
wpas_dbus_getter_debug_level(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)744 dbus_bool_t wpas_dbus_getter_debug_level(
745           const struct wpa_dbus_property_desc *property_desc,
746           DBusMessageIter *iter, DBusError *error, void *user_data)
747 {
748           const char *str;
749           int idx = wpa_debug_level;
750 
751           if (idx < 0)
752                     idx = 0;
753           if (idx > 5)
754                     idx = 5;
755           str = debug_strings[idx];
756           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
757                                                             &str, error);
758 }
759 
760 
761 /**
762  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
763  * @iter: Pointer to incoming dbus message iter
764  * @error: Location to store error on failure
765  * @user_data: Function specific data
766  * Returns: TRUE on success, FALSE on failure
767  *
768  * Getter for "DebugTimestamp" property.
769  */
wpas_dbus_getter_debug_timestamp(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)770 dbus_bool_t wpas_dbus_getter_debug_timestamp(
771           const struct wpa_dbus_property_desc *property_desc,
772           DBusMessageIter *iter, DBusError *error, void *user_data)
773 {
774           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
775                                                             &wpa_debug_timestamp, error);
776 
777 }
778 
779 
780 /**
781  * wpas_dbus_getter_debug_show_keys - Get debug show keys
782  * @iter: Pointer to incoming dbus message iter
783  * @error: Location to store error on failure
784  * @user_data: Function specific data
785  * Returns: TRUE on success, FALSE on failure
786  *
787  * Getter for "DebugShowKeys" property.
788  */
wpas_dbus_getter_debug_show_keys(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)789 dbus_bool_t wpas_dbus_getter_debug_show_keys(
790           const struct wpa_dbus_property_desc *property_desc,
791           DBusMessageIter *iter, DBusError *error, void *user_data)
792 {
793           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
794                                                             &wpa_debug_show_keys, error);
795 
796 }
797 
798 /**
799  * wpas_dbus_setter_debug_level - Set debug level
800  * @iter: Pointer to incoming dbus message iter
801  * @error: Location to store error on failure
802  * @user_data: Function specific data
803  * Returns: TRUE on success, FALSE on failure
804  *
805  * Setter for "DebugLevel" property.
806  */
wpas_dbus_setter_debug_level(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)807 dbus_bool_t wpas_dbus_setter_debug_level(
808           const struct wpa_dbus_property_desc *property_desc,
809           DBusMessageIter *iter, DBusError *error, void *user_data)
810 {
811           struct wpa_global *global = user_data;
812           const char *str = NULL;
813           int i, val = -1;
814 
815           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
816                                                         &str))
817                     return FALSE;
818 
819           for (i = 0; debug_strings[i]; i++)
820                     if (os_strcmp(debug_strings[i], str) == 0) {
821                               val = i;
822                               break;
823                     }
824 
825           if (val < 0 ||
826               wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
827                                                       wpa_debug_show_keys)) {
828                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
829                                              "wrong debug level value");
830                     return FALSE;
831           }
832 
833           return TRUE;
834 }
835 
836 
837 /**
838  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
839  * @iter: Pointer to incoming dbus message iter
840  * @error: Location to store error on failure
841  * @user_data: Function specific data
842  * Returns: TRUE on success, FALSE on failure
843  *
844  * Setter for "DebugTimestamp" property.
845  */
wpas_dbus_setter_debug_timestamp(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)846 dbus_bool_t wpas_dbus_setter_debug_timestamp(
847           const struct wpa_dbus_property_desc *property_desc,
848           DBusMessageIter *iter, DBusError *error, void *user_data)
849 {
850           struct wpa_global *global = user_data;
851           dbus_bool_t val;
852 
853           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
854                                                         &val))
855                     return FALSE;
856 
857           wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
858                                                   wpa_debug_show_keys);
859           return TRUE;
860 }
861 
862 
863 /**
864  * wpas_dbus_setter_debug_show_keys - Set debug show keys
865  * @iter: Pointer to incoming dbus message iter
866  * @error: Location to store error on failure
867  * @user_data: Function specific data
868  * Returns: TRUE on success, FALSE on failure
869  *
870  * Setter for "DebugShowKeys" property.
871  */
wpas_dbus_setter_debug_show_keys(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)872 dbus_bool_t wpas_dbus_setter_debug_show_keys(
873           const struct wpa_dbus_property_desc *property_desc,
874           DBusMessageIter *iter, DBusError *error, void *user_data)
875 {
876           struct wpa_global *global = user_data;
877           dbus_bool_t val;
878 
879           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
880                                                         &val))
881                     return FALSE;
882 
883           wpa_supplicant_set_debug_params(global, wpa_debug_level,
884                                                   wpa_debug_timestamp,
885                                                   val ? 1 : 0);
886           return TRUE;
887 }
888 
889 
890 /**
891  * wpas_dbus_getter_interfaces - Request registered interfaces list
892  * @iter: Pointer to incoming dbus message iter
893  * @error: Location to store error on failure
894  * @user_data: Function specific data
895  * Returns: TRUE on success, FALSE on failure
896  *
897  * Getter for "Interfaces" property. Handles requests
898  * by dbus clients to return list of registered interfaces objects
899  * paths
900  */
wpas_dbus_getter_interfaces(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)901 dbus_bool_t wpas_dbus_getter_interfaces(
902           const struct wpa_dbus_property_desc *property_desc,
903           DBusMessageIter *iter, DBusError *error, void *user_data)
904 {
905           struct wpa_global *global = user_data;
906           struct wpa_supplicant *wpa_s;
907           const char **paths;
908           unsigned int i = 0, num = 0;
909           dbus_bool_t success;
910 
911           for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
912                     if (wpa_s->dbus_new_path)
913                               num++;
914           }
915 
916           paths = os_calloc(num, sizeof(char *));
917           if (!paths) {
918                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
919                     return FALSE;
920           }
921 
922           for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
923                     if (wpa_s->dbus_new_path)
924                               paths[i++] = wpa_s->dbus_new_path;
925           }
926 
927           success = wpas_dbus_simple_array_property_getter(iter,
928                                                                        DBUS_TYPE_OBJECT_PATH,
929                                                                        paths, num, error);
930 
931           os_free(paths);
932           return success;
933 }
934 
935 
936 /**
937  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
938  * @iter: Pointer to incoming dbus message iter
939  * @error: Location to store error on failure
940  * @user_data: Function specific data
941  * Returns: TRUE on success, FALSE on failure
942  *
943  * Getter for "EapMethods" property. Handles requests
944  * by dbus clients to return list of strings with supported EAP methods
945  */
wpas_dbus_getter_eap_methods(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)946 dbus_bool_t wpas_dbus_getter_eap_methods(
947           const struct wpa_dbus_property_desc *property_desc,
948           DBusMessageIter *iter, DBusError *error, void *user_data)
949 {
950           char **eap_methods;
951           size_t num_items = 0;
952           dbus_bool_t success;
953 
954           eap_methods = eap_get_names_as_string_array(&num_items);
955           if (!eap_methods) {
956                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
957                     return FALSE;
958           }
959 
960           success = wpas_dbus_simple_array_property_getter(iter,
961                                                                        DBUS_TYPE_STRING,
962                                                                        eap_methods,
963                                                                        num_items, error);
964 
965           while (num_items)
966                     os_free(eap_methods[--num_items]);
967           os_free(eap_methods);
968           return success;
969 }
970 
971 
972 /**
973  * wpas_dbus_getter_global_capabilities - Request supported global capabilities
974  * @iter: Pointer to incoming dbus message iter
975  * @error: Location to store error on failure
976  * @user_data: Function specific data
977  * Returns: TRUE on success, FALSE on failure
978  *
979  * Getter for "Capabilities" property. Handles requests by dbus clients to
980  * return a list of strings with supported capabilities like AP, RSN IBSS,
981  * and P2P that are determined at compile time.
982  */
wpas_dbus_getter_global_capabilities(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)983 dbus_bool_t wpas_dbus_getter_global_capabilities(
984           const struct wpa_dbus_property_desc *property_desc,
985           DBusMessageIter *iter, DBusError *error, void *user_data)
986 {
987           const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
988                                                   NULL, NULL, NULL, NULL };
989           size_t num_items = 0;
990 #ifdef CONFIG_FILS
991           struct wpa_global *global = user_data;
992           struct wpa_supplicant *wpa_s;
993           int fils_supported = 0, fils_sk_pfs_supported = 0;
994 
995           for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
996                     if (wpa_is_fils_supported(wpa_s))
997                               fils_supported = 1;
998                     if (wpa_is_fils_sk_pfs_supported(wpa_s))
999                               fils_sk_pfs_supported = 1;
1000           }
1001 #endif /* CONFIG_FILS */
1002 
1003 #ifdef CONFIG_AP
1004           capabilities[num_items++] = "ap";
1005 #endif /* CONFIG_AP */
1006 #ifdef CONFIG_IBSS_RSN
1007           capabilities[num_items++] = "ibss-rsn";
1008 #endif /* CONFIG_IBSS_RSN */
1009 #ifdef CONFIG_P2P
1010           capabilities[num_items++] = "p2p";
1011 #endif /* CONFIG_P2P */
1012 #ifdef CONFIG_INTERWORKING
1013           capabilities[num_items++] = "interworking";
1014 #endif /* CONFIG_INTERWORKING */
1015 #ifdef CONFIG_IEEE80211W
1016           capabilities[num_items++] = "pmf";
1017 #endif /* CONFIG_IEEE80211W */
1018 #ifdef CONFIG_MESH
1019           capabilities[num_items++] = "mesh";
1020 #endif /* CONFIG_MESH */
1021 #ifdef CONFIG_FILS
1022           if (fils_supported)
1023                     capabilities[num_items++] = "fils";
1024           if (fils_sk_pfs_supported)
1025                     capabilities[num_items++] = "fils_sk_pfs";
1026 #endif /* CONFIG_FILS */
1027 #ifdef CONFIG_IEEE80211R
1028           capabilities[num_items++] = "ft";
1029 #endif /* CONFIG_IEEE80211R */
1030 #ifdef CONFIG_SHA384
1031           capabilities[num_items++] = "sha384";
1032 #endif /* CONFIG_SHA384 */
1033 
1034           return wpas_dbus_simple_array_property_getter(iter,
1035                                                                   DBUS_TYPE_STRING,
1036                                                                   capabilities,
1037                                                                   num_items, error);
1038 }
1039 
1040 
wpas_dbus_get_scan_type(DBusMessage * message,DBusMessageIter * var,char ** type,DBusMessage ** reply)1041 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
1042                                            char **type, DBusMessage **reply)
1043 {
1044           if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
1045                     wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
1046                                  __func__);
1047                     *reply = wpas_dbus_error_invalid_args(
1048                               message, "Wrong Type value type. String required");
1049                     return -1;
1050           }
1051           dbus_message_iter_get_basic(var, type);
1052           return 0;
1053 }
1054 
1055 
wpas_dbus_get_scan_ssids(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1056 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var,
1057                                             struct wpa_driver_scan_params *params,
1058                                             DBusMessage **reply)
1059 {
1060           struct wpa_driver_scan_ssid *ssids = params->ssids;
1061           size_t ssids_num = 0;
1062           u8 *ssid;
1063           DBusMessageIter array_iter, sub_array_iter;
1064           char *val;
1065           int len;
1066 
1067           if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1068                     wpa_printf(MSG_DEBUG,
1069                                  "%s[dbus]: ssids must be an array of arrays of bytes",
1070                                  __func__);
1071                     *reply = wpas_dbus_error_invalid_args(
1072                               message,
1073                               "Wrong SSIDs value type. Array of arrays of bytes required");
1074                     return -1;
1075           }
1076 
1077           dbus_message_iter_recurse(var, &array_iter);
1078 
1079           if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1080               dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1081                     wpa_printf(MSG_DEBUG,
1082                                  "%s[dbus]: ssids must be an array of arrays of bytes",
1083                                  __func__);
1084                     *reply = wpas_dbus_error_invalid_args(
1085                               message,
1086                               "Wrong SSIDs value type. Array of arrays of bytes required");
1087                     return -1;
1088           }
1089 
1090           while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1091                     if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
1092                               wpa_printf(MSG_DEBUG,
1093                                            "%s[dbus]: Too many ssids specified on scan dbus call",
1094                                            __func__);
1095                               *reply = wpas_dbus_error_invalid_args(
1096                                         message,
1097                                         "Too many ssids specified. Specify at most four");
1098                               return -1;
1099                     }
1100 
1101                     dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1102 
1103                     dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1104 
1105                     if (len > SSID_MAX_LEN) {
1106                               wpa_printf(MSG_DEBUG,
1107                                            "%s[dbus]: SSID too long (len=%d max_len=%d)",
1108                                            __func__, len, SSID_MAX_LEN);
1109                               *reply = wpas_dbus_error_invalid_args(
1110                                         message, "Invalid SSID: too long");
1111                               return -1;
1112                     }
1113 
1114                     if (len != 0) {
1115                               ssid = os_memdup(val, len);
1116                               if (ssid == NULL) {
1117                                         *reply = wpas_dbus_error_no_memory(message);
1118                                         return -1;
1119                               }
1120                     } else {
1121                               /* Allow zero-length SSIDs */
1122                               ssid = NULL;
1123                     }
1124 
1125                     ssids[ssids_num].ssid = ssid;
1126                     ssids[ssids_num].ssid_len = len;
1127 
1128                     dbus_message_iter_next(&array_iter);
1129                     ssids_num++;
1130           }
1131 
1132           params->num_ssids = ssids_num;
1133           return 0;
1134 }
1135 
1136 
wpas_dbus_get_scan_ies(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1137 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var,
1138                                           struct wpa_driver_scan_params *params,
1139                                           DBusMessage **reply)
1140 {
1141           u8 *ies = NULL, *nies;
1142           int ies_len = 0;
1143           DBusMessageIter array_iter, sub_array_iter;
1144           char *val;
1145           int len;
1146 
1147           if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1148                     wpa_printf(MSG_DEBUG,
1149                                  "%s[dbus]: ies must be an array of arrays of bytes",
1150                                  __func__);
1151                     *reply = wpas_dbus_error_invalid_args(
1152                               message,
1153                               "Wrong IEs value type. Array of arrays of bytes required");
1154                     return -1;
1155           }
1156 
1157           dbus_message_iter_recurse(var, &array_iter);
1158 
1159           if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
1160               dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
1161                     wpa_printf(MSG_DEBUG,
1162                                  "%s[dbus]: ies must be an array of arrays of bytes",
1163                                  __func__);
1164                     *reply = wpas_dbus_error_invalid_args(
1165                               message, "Wrong IEs value type. Array required");
1166                     return -1;
1167           }
1168 
1169           while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
1170                     dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1171 
1172                     dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
1173                     if (len == 0) {
1174                               dbus_message_iter_next(&array_iter);
1175                               continue;
1176                     }
1177 
1178                     nies = os_realloc(ies, ies_len + len);
1179                     if (nies == NULL) {
1180                               os_free(ies);
1181                               *reply = wpas_dbus_error_no_memory(message);
1182                               return -1;
1183                     }
1184                     ies = nies;
1185                     os_memcpy(ies + ies_len, val, len);
1186                     ies_len += len;
1187 
1188                     dbus_message_iter_next(&array_iter);
1189           }
1190 
1191           params->extra_ies = ies;
1192           params->extra_ies_len = ies_len;
1193           return 0;
1194 }
1195 
1196 
wpas_dbus_get_scan_channels(DBusMessage * message,DBusMessageIter * var,struct wpa_driver_scan_params * params,DBusMessage ** reply)1197 static int wpas_dbus_get_scan_channels(DBusMessage *message,
1198                                                DBusMessageIter *var,
1199                                                struct wpa_driver_scan_params *params,
1200                                                DBusMessage **reply)
1201 {
1202           DBusMessageIter array_iter, sub_array_iter;
1203           int *freqs = NULL, *nfreqs;
1204           int freqs_num = 0;
1205 
1206           if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
1207                     wpa_printf(MSG_DEBUG,
1208                                  "%s[dbus]: Channels must be an array of structs",
1209                                  __func__);
1210                     *reply = wpas_dbus_error_invalid_args(
1211                               message,
1212                               "Wrong Channels value type. Array of structs required");
1213                     return -1;
1214           }
1215 
1216           dbus_message_iter_recurse(var, &array_iter);
1217 
1218           if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
1219                     wpa_printf(MSG_DEBUG,
1220                                  "%s[dbus]: Channels must be an array of structs",
1221                                  __func__);
1222                     *reply = wpas_dbus_error_invalid_args(
1223                               message,
1224                               "Wrong Channels value type. Array of structs required");
1225                     return -1;
1226           }
1227 
1228           while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT)
1229           {
1230                     int freq, width;
1231 
1232                     dbus_message_iter_recurse(&array_iter, &sub_array_iter);
1233 
1234                     if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
1235                         DBUS_TYPE_UINT32) {
1236                               wpa_printf(MSG_DEBUG,
1237                                            "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
1238                                            __func__,
1239                                            dbus_message_iter_get_arg_type(
1240                                                      &sub_array_iter));
1241                               *reply = wpas_dbus_error_invalid_args(
1242                                         message,
1243                                         "Wrong Channel struct. Two UINT32s required");
1244                               os_free(freqs);
1245                               return -1;
1246                     }
1247                     dbus_message_iter_get_basic(&sub_array_iter, &freq);
1248 
1249                     if (!dbus_message_iter_next(&sub_array_iter) ||
1250                         dbus_message_iter_get_arg_type(&sub_array_iter) !=
1251                         DBUS_TYPE_UINT32) {
1252                               wpa_printf(MSG_DEBUG,
1253                                            "%s[dbus]: Channel must by specified by struct of two UINT32s",
1254                                            __func__);
1255                               *reply = wpas_dbus_error_invalid_args(
1256                                         message,
1257                                         "Wrong Channel struct. Two UINT32s required");
1258                               os_free(freqs);
1259                               return -1;
1260                     }
1261 
1262                     dbus_message_iter_get_basic(&sub_array_iter, &width);
1263 
1264 #define FREQS_ALLOC_CHUNK 32
1265                     if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
1266                               nfreqs = os_realloc_array(
1267                                         freqs, freqs_num + FREQS_ALLOC_CHUNK,
1268                                         sizeof(int));
1269                               if (nfreqs == NULL)
1270                                         os_free(freqs);
1271                               freqs = nfreqs;
1272                     }
1273                     if (freqs == NULL) {
1274                               *reply = wpas_dbus_error_no_memory(message);
1275                               return -1;
1276                     }
1277 
1278                     freqs[freqs_num] = freq;
1279 
1280                     freqs_num++;
1281                     dbus_message_iter_next(&array_iter);
1282           }
1283 
1284           nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
1285           if (nfreqs == NULL)
1286                     os_free(freqs);
1287           freqs = nfreqs;
1288           if (freqs == NULL) {
1289                     *reply = wpas_dbus_error_no_memory(message);
1290                     return -1;
1291           }
1292           freqs[freqs_num] = 0;
1293 
1294           params->freqs = freqs;
1295           return 0;
1296 }
1297 
1298 
wpas_dbus_get_scan_allow_roam(DBusMessage * message,DBusMessageIter * var,dbus_bool_t * allow,DBusMessage ** reply)1299 static int wpas_dbus_get_scan_allow_roam(DBusMessage *message,
1300                                                    DBusMessageIter *var,
1301                                                    dbus_bool_t *allow,
1302                                                    DBusMessage **reply)
1303 {
1304           if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
1305                     wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
1306                                  __func__);
1307                     *reply = wpas_dbus_error_invalid_args(
1308                               message, "Wrong Type value type. Boolean required");
1309                     return -1;
1310           }
1311           dbus_message_iter_get_basic(var, allow);
1312           return 0;
1313 }
1314 
1315 
1316 /**
1317  * wpas_dbus_handler_scan - Request a wireless scan on an interface
1318  * @message: Pointer to incoming dbus message
1319  * @wpa_s: wpa_supplicant structure for a network interface
1320  * Returns: NULL indicating success or DBus error message on failure
1321  *
1322  * Handler function for "Scan" method call of a network device. Requests
1323  * that wpa_supplicant perform a wireless scan as soon as possible
1324  * on a particular wireless interface.
1325  */
wpas_dbus_handler_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)1326 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
1327                                              struct wpa_supplicant *wpa_s)
1328 {
1329           DBusMessage *reply = NULL;
1330           DBusMessageIter iter, dict_iter, entry_iter, variant_iter;
1331           char *key = NULL, *type = NULL;
1332           struct wpa_driver_scan_params params;
1333           size_t i;
1334           dbus_bool_t allow_roam = 1;
1335 
1336           os_memset(&params, 0, sizeof(params));
1337 
1338           dbus_message_iter_init(message, &iter);
1339 
1340           dbus_message_iter_recurse(&iter, &dict_iter);
1341 
1342           while (dbus_message_iter_get_arg_type(&dict_iter) ==
1343                  DBUS_TYPE_DICT_ENTRY) {
1344                     dbus_message_iter_recurse(&dict_iter, &entry_iter);
1345                     dbus_message_iter_get_basic(&entry_iter, &key);
1346                     dbus_message_iter_next(&entry_iter);
1347                     dbus_message_iter_recurse(&entry_iter, &variant_iter);
1348 
1349                     if (os_strcmp(key, "Type") == 0) {
1350                               if (wpas_dbus_get_scan_type(message, &variant_iter,
1351                                                                 &type, &reply) < 0)
1352                                         goto out;
1353                     } else if (os_strcmp(key, "SSIDs") == 0) {
1354                               if (wpas_dbus_get_scan_ssids(message, &variant_iter,
1355                                                                  &params, &reply) < 0)
1356                                         goto out;
1357                     } else if (os_strcmp(key, "IEs") == 0) {
1358                               if (wpas_dbus_get_scan_ies(message, &variant_iter,
1359                                                                &params, &reply) < 0)
1360                                         goto out;
1361                     } else if (os_strcmp(key, "Channels") == 0) {
1362                               if (wpas_dbus_get_scan_channels(message, &variant_iter,
1363                                                                       &params, &reply) < 0)
1364                                         goto out;
1365                     } else if (os_strcmp(key, "AllowRoam") == 0) {
1366                               if (wpas_dbus_get_scan_allow_roam(message,
1367                                                                         &variant_iter,
1368                                                                         &allow_roam,
1369                                                                         &reply) < 0)
1370                                         goto out;
1371                     } else {
1372                               wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
1373                                            __func__, key);
1374                               reply = wpas_dbus_error_invalid_args(message, key);
1375                               goto out;
1376                     }
1377 
1378                     dbus_message_iter_next(&dict_iter);
1379           }
1380 
1381           if (!type) {
1382                     wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
1383                                  __func__);
1384                     reply = wpas_dbus_error_invalid_args(message, key);
1385                     goto out;
1386           }
1387 
1388           if (os_strcmp(type, "passive") == 0) {
1389                     if (params.num_ssids || params.extra_ies_len) {
1390                               wpa_printf(MSG_DEBUG,
1391                                            "%s[dbus]: SSIDs or IEs specified for passive scan.",
1392                                            __func__);
1393                               reply = wpas_dbus_error_invalid_args(
1394                                         message,
1395                                         "You can specify only Channels in passive scan");
1396                               goto out;
1397                     } else {
1398                               if (wpa_s->sched_scanning) {
1399                                         wpa_printf(MSG_DEBUG,
1400                                                      "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1401                                                      __func__);
1402                                         wpa_supplicant_cancel_sched_scan(wpa_s);
1403                               }
1404 
1405                               if (params.freqs && params.freqs[0]) {
1406                                         wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1407                                         if (wpa_supplicant_trigger_scan(wpa_s,
1408                                                                                 &params)) {
1409                                                   reply = wpas_dbus_error_scan_error(
1410                                                             message,
1411                                                             "Scan request rejected");
1412                                         }
1413                               } else {
1414                                         wpa_s->scan_req = MANUAL_SCAN_REQ;
1415                                         wpa_supplicant_req_scan(wpa_s, 0, 0);
1416                               }
1417                     }
1418           } else if (os_strcmp(type, "active") == 0) {
1419                     if (!params.num_ssids) {
1420                               /* Add wildcard ssid */
1421                               params.num_ssids++;
1422                     }
1423 #ifdef CONFIG_AUTOSCAN
1424                     autoscan_deinit(wpa_s);
1425 #endif /* CONFIG_AUTOSCAN */
1426                     if (wpa_s->sched_scanning) {
1427                               wpa_printf(MSG_DEBUG,
1428                                            "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed",
1429                                            __func__);
1430                               wpa_supplicant_cancel_sched_scan(wpa_s);
1431                     }
1432 
1433                     wpa_s->last_scan_req = MANUAL_SCAN_REQ;
1434                     if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
1435                               reply = wpas_dbus_error_scan_error(
1436                                         message, "Scan request rejected");
1437                     }
1438           } else {
1439                     wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
1440                                  __func__, type);
1441                     reply = wpas_dbus_error_invalid_args(message,
1442                                                                  "Wrong scan type");
1443                     goto out;
1444           }
1445 
1446           if (!allow_roam)
1447                     wpa_s->scan_res_handler = scan_only_handler;
1448 
1449 out:
1450           for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++)
1451                     os_free((u8 *) params.ssids[i].ssid);
1452           os_free((u8 *) params.extra_ies);
1453           os_free(params.freqs);
1454           return reply;
1455 }
1456 
1457 
1458 /*
1459  * wpas_dbus_handler_abort_scan - Request an ongoing scan to be aborted
1460  * @message: Pointer to incoming dbus message
1461  * @wpa_s: wpa_supplicant structure for a network interface
1462  * Returns: Abort failed or no scan in progress DBus error message on failure
1463  * or NULL otherwise.
1464  *
1465  * Handler function for "AbortScan" method call of network interface.
1466  */
wpas_dbus_handler_abort_scan(DBusMessage * message,struct wpa_supplicant * wpa_s)1467 DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
1468                                                      struct wpa_supplicant *wpa_s)
1469 {
1470           if (wpas_abort_ongoing_scan(wpa_s) < 0)
1471                     return dbus_message_new_error(
1472                               message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
1473                               "Abort failed or no scan in progress");
1474 
1475           return NULL;
1476 }
1477 
1478 
1479 /**
1480  * wpas_dbus_handler_signal_poll - Request immediate signal properties
1481  * @message: Pointer to incoming dbus message
1482  * @wpa_s: wpa_supplicant structure for a network interface
1483  * Returns: NULL indicating success or DBus error message on failure
1484  *
1485  * Handler function for "SignalPoll" method call of a network device. Requests
1486  * that wpa_supplicant read signal properties like RSSI, noise, and link
1487  * speed and return them.
1488  */
wpas_dbus_handler_signal_poll(DBusMessage * message,struct wpa_supplicant * wpa_s)1489 DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message,
1490                                                       struct wpa_supplicant *wpa_s)
1491 {
1492           struct wpa_signal_info si;
1493           DBusMessage *reply = NULL;
1494           DBusMessageIter iter, iter_dict, variant_iter;
1495           int ret;
1496 
1497           ret = wpa_drv_signal_poll(wpa_s, &si);
1498           if (ret) {
1499                     return dbus_message_new_error(message, DBUS_ERROR_FAILED,
1500                                                         "Failed to read signal");
1501           }
1502 
1503           reply = dbus_message_new_method_return(message);
1504           if (reply == NULL)
1505                     goto nomem;
1506 
1507           dbus_message_iter_init_append(reply, &iter);
1508 
1509           if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1510                                                         "a{sv}", &variant_iter) ||
1511               !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
1512               !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
1513                                                   si.current_signal) ||
1514               !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
1515                                                   si.current_txrate / 1000) ||
1516               !wpa_dbus_dict_append_int32(&iter_dict, "noise",
1517                                                   si.current_noise) ||
1518               !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
1519                                                    si.frequency) ||
1520               (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
1521                !wpa_dbus_dict_append_string(
1522                          &iter_dict, "width",
1523                          channel_width_to_string(si.chanwidth))) ||
1524               (si.center_frq1 > 0 && si.center_frq2 > 0 &&
1525                (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
1526                                                     si.center_frq1) ||
1527                 !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
1528                                                     si.center_frq2))) ||
1529               (si.avg_signal &&
1530                !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
1531                                                    si.avg_signal)) ||
1532               !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
1533               !dbus_message_iter_close_container(&iter, &variant_iter))
1534                     goto nomem;
1535 
1536           return reply;
1537 
1538 nomem:
1539           if (reply)
1540                     dbus_message_unref(reply);
1541           return wpas_dbus_error_no_memory(message);
1542 }
1543 
1544 
1545 /*
1546  * wpas_dbus_handler_disconnect - Terminate the current connection
1547  * @message: Pointer to incoming dbus message
1548  * @wpa_s: wpa_supplicant structure for a network interface
1549  * Returns: NotConnected DBus error message if already not connected
1550  * or NULL otherwise.
1551  *
1552  * Handler function for "Disconnect" method call of network interface.
1553  */
wpas_dbus_handler_disconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)1554 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
1555                                                      struct wpa_supplicant *wpa_s)
1556 {
1557           if (wpa_s->current_ssid != NULL) {
1558                     wpas_request_disconnection(wpa_s);
1559                     return NULL;
1560           }
1561 
1562           return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1563                                               "This interface is not connected");
1564 }
1565 
1566 
1567 /**
1568  * wpas_dbus_new_iface_add_network - Add a new configured network
1569  * @message: Pointer to incoming dbus message
1570  * @wpa_s: wpa_supplicant structure for a network interface
1571  * Returns: A dbus message containing the object path of the new network
1572  *
1573  * Handler function for "AddNetwork" method call of a network interface.
1574  */
wpas_dbus_handler_add_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1575 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
1576                                                       struct wpa_supplicant *wpa_s)
1577 {
1578           DBusMessage *reply = NULL;
1579           DBusMessageIter     iter;
1580           struct wpa_ssid *ssid = NULL;
1581           char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1582           DBusError error;
1583 
1584           dbus_message_iter_init(message, &iter);
1585 
1586           if (wpa_s->dbus_new_path)
1587                     ssid = wpa_supplicant_add_network(wpa_s);
1588           if (ssid == NULL) {
1589                     wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
1590                                  __func__);
1591                     reply = wpas_dbus_error_unknown_error(
1592                               message,
1593                               "wpa_supplicant could not add a network on this interface.");
1594                     goto err;
1595           }
1596 
1597           dbus_error_init(&error);
1598           if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1599                     wpa_printf(MSG_DEBUG,
1600                                  "%s[dbus]: control interface couldn't set network properties",
1601                                  __func__);
1602                     reply = wpas_dbus_reply_new_from_error(message, &error,
1603                                                                    DBUS_ERROR_INVALID_ARGS,
1604                                                                    "Failed to add network");
1605                     dbus_error_free(&error);
1606                     goto err;
1607           }
1608 
1609           /* Construct the object path for this network. */
1610           os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1611                         "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
1612                         wpa_s->dbus_new_path, ssid->id);
1613 
1614           reply = dbus_message_new_method_return(message);
1615           if (reply == NULL) {
1616                     reply = wpas_dbus_error_no_memory(message);
1617                     goto err;
1618           }
1619           if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1620                                               DBUS_TYPE_INVALID)) {
1621                     dbus_message_unref(reply);
1622                     reply = wpas_dbus_error_no_memory(message);
1623                     goto err;
1624           }
1625 
1626           return reply;
1627 
1628 err:
1629           if (ssid) {
1630                     wpas_notify_network_removed(wpa_s, ssid);
1631                     wpa_config_remove_network(wpa_s->conf, ssid->id);
1632           }
1633           return reply;
1634 }
1635 
1636 
1637 /**
1638  * wpas_dbus_handler_reassociate - Reassociate
1639  * @message: Pointer to incoming dbus message
1640  * @wpa_s: wpa_supplicant structure for a network interface
1641  * Returns: InterfaceDisabled DBus error message if disabled
1642  * or NULL otherwise.
1643  *
1644  * Handler function for "Reassociate" method call of network interface.
1645  */
wpas_dbus_handler_reassociate(DBusMessage * message,struct wpa_supplicant * wpa_s)1646 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
1647                                                       struct wpa_supplicant *wpa_s)
1648 {
1649           if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) {
1650                     wpas_request_connection(wpa_s);
1651                     return NULL;
1652           }
1653 
1654           return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED,
1655                                               "This interface is disabled");
1656 }
1657 
1658 
1659 /**
1660  * wpas_dbus_handler_expect_disconnect - ExpectDisconnect
1661  * @message: Pointer to incoming dbus message
1662  * @global: %wpa_supplicant global data structure
1663  * Returns: NULL
1664  *
1665  * Handler function for notifying system there will be a expected disconnect.
1666  * This will prevent wpa_supplicant from adding blacklists upon next disconnect..
1667  */
wpas_dbus_handler_expect_disconnect(DBusMessage * message,struct wpa_global * global)1668 DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message,
1669                                                               struct wpa_global *global)
1670 {
1671           struct wpa_supplicant *wpa_s = global->ifaces;
1672 
1673           for (; wpa_s; wpa_s = wpa_s->next)
1674                     if (wpa_s->wpa_state >= WPA_ASSOCIATED)
1675                               wpa_s->own_disconnect_req = 1;
1676           return NULL;
1677 }
1678 
1679 
1680 /**
1681  * wpas_dbus_handler_reattach - Reattach to current AP
1682  * @message: Pointer to incoming dbus message
1683  * @wpa_s: wpa_supplicant structure for a network interface
1684  * Returns: NotConnected DBus error message if not connected
1685  * or NULL otherwise.
1686  *
1687  * Handler function for "Reattach" method call of network interface.
1688  */
wpas_dbus_handler_reattach(DBusMessage * message,struct wpa_supplicant * wpa_s)1689 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
1690                                                    struct wpa_supplicant *wpa_s)
1691 {
1692           if (wpa_s->current_ssid != NULL) {
1693                     wpa_s->reattach = 1;
1694                     wpas_request_connection(wpa_s);
1695                     return NULL;
1696           }
1697 
1698           return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
1699                                               "This interface is not connected");
1700 }
1701 
1702 
1703 /**
1704  * wpas_dbus_handler_reconnect - Reconnect if disconnected
1705  * @message: Pointer to incoming dbus message
1706  * @wpa_s: wpa_supplicant structure for a network interface
1707  * Returns: InterfaceDisabled DBus error message if disabled
1708  * or NULL otherwise.
1709  *
1710  * Handler function for "Reconnect" method call of network interface.
1711  */
wpas_dbus_handler_reconnect(DBusMessage * message,struct wpa_supplicant * wpa_s)1712 DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
1713                     struct wpa_supplicant *wpa_s)
1714 {
1715           if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
1716                     return dbus_message_new_error(message,
1717                                                         WPAS_DBUS_ERROR_IFACE_DISABLED,
1718                                                         "This interface is disabled");
1719           }
1720 
1721           if (wpa_s->disconnected)
1722                     wpas_request_connection(wpa_s);
1723           return NULL;
1724 }
1725 
1726 
1727 /**
1728  * wpas_dbus_handler_remove_network - Remove a configured network
1729  * @message: Pointer to incoming dbus message
1730  * @wpa_s: wpa_supplicant structure for a network interface
1731  * Returns: NULL on success or dbus error on failure
1732  *
1733  * Handler function for "RemoveNetwork" method call of a network interface.
1734  */
wpas_dbus_handler_remove_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1735 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
1736                                                          struct wpa_supplicant *wpa_s)
1737 {
1738           DBusMessage *reply = NULL;
1739           const char *op;
1740           char *iface, *net_id;
1741           int id;
1742           int result;
1743 
1744           dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1745                                     DBUS_TYPE_INVALID);
1746 
1747           /* Extract the network ID and ensure the network */
1748           /* is actually a child of this interface */
1749           iface = wpas_dbus_new_decompose_object_path(op,
1750                                                                 WPAS_DBUS_NEW_NETWORKS_PART,
1751                                                                 &net_id);
1752           if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1753               os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1754                     reply = wpas_dbus_error_invalid_args(message, op);
1755                     goto out;
1756           }
1757 
1758           errno = 0;
1759           id = strtoul(net_id, NULL, 10);
1760           if (errno != 0) {
1761                     reply = wpas_dbus_error_invalid_args(message, op);
1762                     goto out;
1763           }
1764 
1765           result = wpa_supplicant_remove_network(wpa_s, id);
1766           if (result == -1) {
1767                     reply = wpas_dbus_error_network_unknown(message);
1768                     goto out;
1769           }
1770           if (result == -2) {
1771                     wpa_printf(MSG_ERROR,
1772                                  "%s[dbus]: error occurred when removing network %d",
1773                                  __func__, id);
1774                     reply = wpas_dbus_error_unknown_error(
1775                               message,
1776                               "error removing the specified network on is interface.");
1777                     goto out;
1778           }
1779 
1780 out:
1781           os_free(iface);
1782           return reply;
1783 }
1784 
1785 
remove_network(void * arg,struct wpa_ssid * ssid)1786 static void remove_network(void *arg, struct wpa_ssid *ssid)
1787 {
1788           struct wpa_supplicant *wpa_s = arg;
1789 
1790           wpas_notify_network_removed(wpa_s, ssid);
1791 
1792           if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1793                     wpa_printf(MSG_ERROR,
1794                                  "%s[dbus]: error occurred when removing network %d",
1795                                  __func__, ssid->id);
1796                     return;
1797           }
1798 
1799           if (ssid == wpa_s->current_ssid)
1800                     wpa_supplicant_deauthenticate(wpa_s,
1801                                                         WLAN_REASON_DEAUTH_LEAVING);
1802 }
1803 
1804 
1805 /**
1806  * wpas_dbus_handler_remove_all_networks - Remove all configured networks
1807  * @message: Pointer to incoming dbus message
1808  * @wpa_s: wpa_supplicant structure for a network interface
1809  * Returns: NULL on success or dbus error on failure
1810  *
1811  * Handler function for "RemoveAllNetworks" method call of a network interface.
1812  */
wpas_dbus_handler_remove_all_networks(DBusMessage * message,struct wpa_supplicant * wpa_s)1813 DBusMessage * wpas_dbus_handler_remove_all_networks(
1814           DBusMessage *message, struct wpa_supplicant *wpa_s)
1815 {
1816           if (wpa_s->sched_scanning)
1817                     wpa_supplicant_cancel_sched_scan(wpa_s);
1818 
1819           /* NB: could check for failure and return an error */
1820           wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
1821           return NULL;
1822 }
1823 
1824 
1825 /**
1826  * wpas_dbus_handler_select_network - Attempt association with a network
1827  * @message: Pointer to incoming dbus message
1828  * @wpa_s: wpa_supplicant structure for a network interface
1829  * Returns: NULL on success or dbus error on failure
1830  *
1831  * Handler function for "SelectNetwork" method call of network interface.
1832  */
wpas_dbus_handler_select_network(DBusMessage * message,struct wpa_supplicant * wpa_s)1833 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
1834                                                          struct wpa_supplicant *wpa_s)
1835 {
1836           DBusMessage *reply = NULL;
1837           const char *op;
1838           char *iface, *net_id;
1839           int id;
1840           struct wpa_ssid *ssid;
1841 
1842           dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1843                                     DBUS_TYPE_INVALID);
1844 
1845           /* Extract the network ID and ensure the network */
1846           /* is actually a child of this interface */
1847           iface = wpas_dbus_new_decompose_object_path(op,
1848                                                                 WPAS_DBUS_NEW_NETWORKS_PART,
1849                                                                 &net_id);
1850           if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1851               os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1852                     reply = wpas_dbus_error_invalid_args(message, op);
1853                     goto out;
1854           }
1855 
1856           errno = 0;
1857           id = strtoul(net_id, NULL, 10);
1858           if (errno != 0) {
1859                     reply = wpas_dbus_error_invalid_args(message, op);
1860                     goto out;
1861           }
1862 
1863           ssid = wpa_config_get_network(wpa_s->conf, id);
1864           if (ssid == NULL) {
1865                     reply = wpas_dbus_error_network_unknown(message);
1866                     goto out;
1867           }
1868 
1869           /* Finally, associate with the network */
1870           wpa_supplicant_select_network(wpa_s, ssid);
1871 
1872 out:
1873           os_free(iface);
1874           return reply;
1875 }
1876 
1877 
1878 /**
1879  * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
1880  * @message: Pointer to incoming dbus message
1881  * @wpa_s: wpa_supplicant structure for a network interface
1882  * Returns: NULL on success or dbus error on failure
1883  *
1884  * Handler function for "NetworkReply" method call of network interface.
1885  */
wpas_dbus_handler_network_reply(DBusMessage * message,struct wpa_supplicant * wpa_s)1886 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
1887                                                         struct wpa_supplicant *wpa_s)
1888 {
1889 #ifdef IEEE8021X_EAPOL
1890           DBusMessage *reply = NULL;
1891           const char *op, *field, *value;
1892           char *iface, *net_id;
1893           int id;
1894           struct wpa_ssid *ssid;
1895 
1896           if (!dbus_message_get_args(message, NULL,
1897                                            DBUS_TYPE_OBJECT_PATH, &op,
1898                                            DBUS_TYPE_STRING, &field,
1899                                            DBUS_TYPE_STRING, &value,
1900                                            DBUS_TYPE_INVALID))
1901                     return wpas_dbus_error_invalid_args(message, NULL);
1902 
1903           /* Extract the network ID and ensure the network */
1904           /* is actually a child of this interface */
1905           iface = wpas_dbus_new_decompose_object_path(op,
1906                                                                 WPAS_DBUS_NEW_NETWORKS_PART,
1907                                                                 &net_id);
1908           if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path ||
1909               os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1910                     reply = wpas_dbus_error_invalid_args(message, op);
1911                     goto out;
1912           }
1913 
1914           errno = 0;
1915           id = strtoul(net_id, NULL, 10);
1916           if (errno != 0) {
1917                     reply = wpas_dbus_error_invalid_args(message, net_id);
1918                     goto out;
1919           }
1920 
1921           ssid = wpa_config_get_network(wpa_s->conf, id);
1922           if (ssid == NULL) {
1923                     reply = wpas_dbus_error_network_unknown(message);
1924                     goto out;
1925           }
1926 
1927           if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
1928                                                                   field, value) < 0)
1929                     reply = wpas_dbus_error_invalid_args(message, field);
1930           else {
1931                     /* Tell EAP to retry immediately */
1932                     eapol_sm_notify_ctrl_response(wpa_s->eapol);
1933           }
1934 
1935 out:
1936           os_free(iface);
1937           return reply;
1938 #else /* IEEE8021X_EAPOL */
1939           wpa_printf(MSG_DEBUG, "dbus: 802.1X not included");
1940           return wpas_dbus_error_unknown_error(message, "802.1X not included");
1941 #endif /* IEEE8021X_EAPOL */
1942 }
1943 
1944 
1945 #ifndef CONFIG_NO_CONFIG_BLOBS
1946 
1947 /**
1948  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
1949  * @message: Pointer to incoming dbus message
1950  * @wpa_s: %wpa_supplicant data structure
1951  * Returns: A dbus message containing an error on failure or NULL on success
1952  *
1953  * Asks wpa_supplicant to internally store a binary blobs.
1954  */
wpas_dbus_handler_add_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)1955 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
1956                                                    struct wpa_supplicant *wpa_s)
1957 {
1958           DBusMessage *reply = NULL;
1959           DBusMessageIter     iter, array_iter;
1960 
1961           char *blob_name;
1962           u8 *blob_data;
1963           int blob_len;
1964           struct wpa_config_blob *blob = NULL;
1965 
1966           dbus_message_iter_init(message, &iter);
1967           dbus_message_iter_get_basic(&iter, &blob_name);
1968 
1969           if (wpa_config_get_blob(wpa_s->conf, blob_name)) {
1970                     return dbus_message_new_error(message,
1971                                                         WPAS_DBUS_ERROR_BLOB_EXISTS,
1972                                                         NULL);
1973           }
1974 
1975           dbus_message_iter_next(&iter);
1976           dbus_message_iter_recurse(&iter, &array_iter);
1977 
1978           dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len);
1979 
1980           blob = os_zalloc(sizeof(*blob));
1981           if (!blob) {
1982                     reply = wpas_dbus_error_no_memory(message);
1983                     goto err;
1984           }
1985 
1986           blob->data = os_memdup(blob_data, blob_len);
1987           blob->name = os_strdup(blob_name);
1988           if (!blob->data || !blob->name) {
1989                     reply = wpas_dbus_error_no_memory(message);
1990                     goto err;
1991           }
1992           blob->len = blob_len;
1993 
1994           wpa_config_set_blob(wpa_s->conf, blob);
1995           wpas_notify_blob_added(wpa_s, blob->name);
1996 
1997           return reply;
1998 
1999 err:
2000           if (blob) {
2001                     os_free(blob->name);
2002                     os_free(blob->data);
2003                     os_free(blob);
2004           }
2005           return reply;
2006 }
2007 
2008 
2009 /**
2010  * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates)
2011  * @message: Pointer to incoming dbus message
2012  * @wpa_s: %wpa_supplicant data structure
2013  * Returns: A dbus message containing array of bytes (blob)
2014  *
2015  * Gets one wpa_supplicant's binary blobs.
2016  */
wpas_dbus_handler_get_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)2017 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message,
2018                                                    struct wpa_supplicant *wpa_s)
2019 {
2020           DBusMessage *reply = NULL;
2021           DBusMessageIter     iter, array_iter;
2022 
2023           char *blob_name;
2024           const struct wpa_config_blob *blob;
2025 
2026           dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
2027                                     DBUS_TYPE_INVALID);
2028 
2029           blob = wpa_config_get_blob(wpa_s->conf, blob_name);
2030           if (!blob) {
2031                     return dbus_message_new_error(message,
2032                                                         WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2033                                                         "Blob id not set");
2034           }
2035 
2036           reply = dbus_message_new_method_return(message);
2037           if (!reply)
2038                     return wpas_dbus_error_no_memory(message);
2039 
2040           dbus_message_iter_init_append(reply, &iter);
2041 
2042           if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
2043                                                         DBUS_TYPE_BYTE_AS_STRING,
2044                                                         &array_iter) ||
2045               !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
2046                                                               &(blob->data), blob->len) ||
2047               !dbus_message_iter_close_container(&iter, &array_iter)) {
2048                     dbus_message_unref(reply);
2049                     reply = wpas_dbus_error_no_memory(message);
2050           }
2051 
2052           return reply;
2053 }
2054 
2055 
2056 /**
2057  * wpas_remove_handler_remove_blob - Remove named binary blob
2058  * @message: Pointer to incoming dbus message
2059  * @wpa_s: %wpa_supplicant data structure
2060  * Returns: NULL on success or dbus error
2061  *
2062  * Asks wpa_supplicant to internally remove a binary blobs.
2063  */
wpas_dbus_handler_remove_blob(DBusMessage * message,struct wpa_supplicant * wpa_s)2064 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message,
2065                                                       struct wpa_supplicant *wpa_s)
2066 {
2067           DBusMessage *reply = NULL;
2068           char *blob_name;
2069 
2070           dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name,
2071                                     DBUS_TYPE_INVALID);
2072 
2073           if (wpa_config_remove_blob(wpa_s->conf, blob_name)) {
2074                     return dbus_message_new_error(message,
2075                                                         WPAS_DBUS_ERROR_BLOB_UNKNOWN,
2076                                                         "Blob id not set");
2077           }
2078           wpas_notify_blob_removed(wpa_s, blob_name);
2079 
2080           return reply;
2081 
2082 }
2083 
2084 #endif /* CONFIG_NO_CONFIG_BLOBS */
2085 
2086 
2087 /*
2088  * wpas_dbus_handler_flush_bss - Flush the BSS cache
2089  * @message: Pointer to incoming dbus message
2090  * @wpa_s: wpa_supplicant structure for a network interface
2091  * Returns: NULL
2092  *
2093  * Handler function for "FlushBSS" method call of network interface.
2094  */
wpas_dbus_handler_flush_bss(DBusMessage * message,struct wpa_supplicant * wpa_s)2095 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
2096                                                     struct wpa_supplicant *wpa_s)
2097 {
2098           dbus_uint32_t age;
2099 
2100           dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age,
2101                                     DBUS_TYPE_INVALID);
2102 
2103           if (age == 0)
2104                     wpa_bss_flush(wpa_s);
2105           else
2106                     wpa_bss_flush_by_age(wpa_s, age);
2107 
2108           return NULL;
2109 }
2110 
2111 
2112 #ifdef CONFIG_AUTOSCAN
2113 /**
2114  * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface
2115  * @message: Pointer to incoming dbus message
2116  * @wpa_s: wpa_supplicant structure for a network interface
2117  * Returns: NULL
2118  *
2119  * Handler function for "AutoScan" method call of network interface.
2120  */
wpas_dbus_handler_autoscan(DBusMessage * message,struct wpa_supplicant * wpa_s)2121 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message,
2122                                                    struct wpa_supplicant *wpa_s)
2123 {
2124           DBusMessage *reply = NULL;
2125           enum wpa_states state = wpa_s->wpa_state;
2126           char *arg;
2127 
2128           dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg,
2129                                     DBUS_TYPE_INVALID);
2130 
2131           if (arg != NULL && os_strlen(arg) > 0) {
2132                     char *tmp;
2133 
2134                     tmp = os_strdup(arg);
2135                     if (tmp == NULL) {
2136                               reply = wpas_dbus_error_no_memory(message);
2137                     } else {
2138                               os_free(wpa_s->conf->autoscan);
2139                               wpa_s->conf->autoscan = tmp;
2140                               if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
2141                                         autoscan_init(wpa_s, 1);
2142                               else if (state == WPA_SCANNING)
2143                                         wpa_supplicant_reinit_autoscan(wpa_s);
2144                     }
2145           } else if (arg != NULL && os_strlen(arg) == 0) {
2146                     os_free(wpa_s->conf->autoscan);
2147                     wpa_s->conf->autoscan = NULL;
2148                     autoscan_deinit(wpa_s);
2149           } else
2150                     reply = dbus_message_new_error(message,
2151                                                          DBUS_ERROR_INVALID_ARGS,
2152                                                          NULL);
2153 
2154           return reply;
2155 }
2156 #endif /* CONFIG_AUTOSCAN */
2157 
2158 
2159 /*
2160  * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff
2161  * @message: Pointer to incoming dbus message
2162  * @wpa_s: wpa_supplicant structure for a network interface
2163  * Returns: NULL
2164  *
2165  * Handler function for "EAPLogoff" method call of network interface.
2166  */
wpas_dbus_handler_eap_logoff(DBusMessage * message,struct wpa_supplicant * wpa_s)2167 DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
2168                                                      struct wpa_supplicant *wpa_s)
2169 {
2170           eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
2171           return NULL;
2172 }
2173 
2174 
2175 /*
2176  * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon
2177  * @message: Pointer to incoming dbus message
2178  * @wpa_s: wpa_supplicant structure for a network interface
2179  * Returns: NULL
2180  *
2181  * Handler function for "EAPLogin" method call of network interface.
2182  */
wpas_dbus_handler_eap_logon(DBusMessage * message,struct wpa_supplicant * wpa_s)2183 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
2184                                                     struct wpa_supplicant *wpa_s)
2185 {
2186           eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
2187           return NULL;
2188 }
2189 
2190 
2191 #ifdef CONFIG_TDLS
2192 
get_peer_hwaddr_helper(DBusMessage * message,const char * func_name,u8 * peer_address,DBusMessage ** error)2193 static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name,
2194                                           u8 *peer_address, DBusMessage **error)
2195 {
2196           const char *peer_string;
2197 
2198           *error = NULL;
2199 
2200           if (!dbus_message_get_args(message, NULL,
2201                                            DBUS_TYPE_STRING, &peer_string,
2202                                            DBUS_TYPE_INVALID)) {
2203                     *error = wpas_dbus_error_invalid_args(message, NULL);
2204                     return -1;
2205           }
2206 
2207           if (hwaddr_aton(peer_string, peer_address)) {
2208                     wpa_printf(MSG_DEBUG, "%s: invalid address '%s'",
2209                                  func_name, peer_string);
2210                     *error = wpas_dbus_error_invalid_args(
2211                               message, "Invalid hardware address format");
2212                     return -1;
2213           }
2214 
2215           return 0;
2216 }
2217 
2218 
2219 /*
2220  * wpas_dbus_handler_tdls_discover - Discover TDLS peer
2221  * @message: Pointer to incoming dbus message
2222  * @wpa_s: wpa_supplicant structure for a network interface
2223  * Returns: NULL indicating success or DBus error message on failure
2224  *
2225  * Handler function for "TDLSDiscover" method call of network interface.
2226  */
wpas_dbus_handler_tdls_discover(DBusMessage * message,struct wpa_supplicant * wpa_s)2227 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
2228                                                         struct wpa_supplicant *wpa_s)
2229 {
2230           u8 peer[ETH_ALEN];
2231           DBusMessage *error_reply;
2232           int ret;
2233 
2234           if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2235                     return error_reply;
2236 
2237           wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer));
2238 
2239           if (wpa_tdls_is_external_setup(wpa_s->wpa))
2240                     ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
2241           else
2242                     ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
2243 
2244           if (ret) {
2245                     return wpas_dbus_error_unknown_error(
2246                               message, "error performing TDLS discovery");
2247           }
2248 
2249           return NULL;
2250 }
2251 
2252 
2253 /*
2254  * wpas_dbus_handler_tdls_setup - Setup TDLS session
2255  * @message: Pointer to incoming dbus message
2256  * @wpa_s: wpa_supplicant structure for a network interface
2257  * Returns: NULL indicating success or DBus error message on failure
2258  *
2259  * Handler function for "TDLSSetup" method call of network interface.
2260  */
wpas_dbus_handler_tdls_setup(DBusMessage * message,struct wpa_supplicant * wpa_s)2261 DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
2262                                                      struct wpa_supplicant *wpa_s)
2263 {
2264           u8 peer[ETH_ALEN];
2265           DBusMessage *error_reply;
2266           int ret;
2267 
2268           if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2269                     return error_reply;
2270 
2271           wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer));
2272 
2273           wpa_tdls_remove(wpa_s->wpa, peer);
2274           if (wpa_tdls_is_external_setup(wpa_s->wpa))
2275                     ret = wpa_tdls_start(wpa_s->wpa, peer);
2276           else
2277                     ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
2278 
2279           if (ret) {
2280                     return wpas_dbus_error_unknown_error(
2281                               message, "error performing TDLS setup");
2282           }
2283 
2284           return NULL;
2285 }
2286 
2287 
2288 /*
2289  * wpas_dbus_handler_tdls_status - Return TDLS session status
2290  * @message: Pointer to incoming dbus message
2291  * @wpa_s: wpa_supplicant structure for a network interface
2292  * Returns: A string representing the state of the link to this TDLS peer
2293  *
2294  * Handler function for "TDLSStatus" method call of network interface.
2295  */
wpas_dbus_handler_tdls_status(DBusMessage * message,struct wpa_supplicant * wpa_s)2296 DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
2297                                                       struct wpa_supplicant *wpa_s)
2298 {
2299           u8 peer[ETH_ALEN];
2300           DBusMessage *reply;
2301           const char *tdls_status;
2302 
2303           if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0)
2304                     return reply;
2305 
2306           wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer));
2307 
2308           tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer);
2309 
2310           reply = dbus_message_new_method_return(message);
2311           dbus_message_append_args(reply, DBUS_TYPE_STRING,
2312                                          &tdls_status, DBUS_TYPE_INVALID);
2313           return reply;
2314 }
2315 
2316 
2317 /*
2318  * wpas_dbus_handler_tdls_teardown - Teardown TDLS session
2319  * @message: Pointer to incoming dbus message
2320  * @wpa_s: wpa_supplicant structure for a network interface
2321  * Returns: NULL indicating success or DBus error message on failure
2322  *
2323  * Handler function for "TDLSTeardown" method call of network interface.
2324  */
wpas_dbus_handler_tdls_teardown(DBusMessage * message,struct wpa_supplicant * wpa_s)2325 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
2326                                                         struct wpa_supplicant *wpa_s)
2327 {
2328           u8 peer[ETH_ALEN];
2329           DBusMessage *error_reply;
2330           int ret;
2331 
2332           if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2333                     return error_reply;
2334 
2335           wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer));
2336 
2337           if (wpa_tdls_is_external_setup(wpa_s->wpa))
2338                     ret = wpa_tdls_teardown_link(
2339                               wpa_s->wpa, peer,
2340                               WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
2341           else
2342                     ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
2343 
2344           if (ret) {
2345                     return wpas_dbus_error_unknown_error(
2346                               message, "error performing TDLS teardown");
2347           }
2348 
2349           return NULL;
2350 }
2351 
2352 /*
2353  * wpas_dbus_handler_tdls_channel_switch - Enable channel switching with TDLS peer
2354  * @message: Pointer to incoming dbus message
2355  * @wpa_s: wpa_supplicant structure for a network interface
2356  * Returns: NULL indicating success or DBus error message on failure
2357  *
2358  * Handler function for "TDLSChannelSwitch" method call of network interface.
2359  */
2360 DBusMessage *
wpas_dbus_handler_tdls_channel_switch(DBusMessage * message,struct wpa_supplicant * wpa_s)2361 wpas_dbus_handler_tdls_channel_switch(DBusMessage *message,
2362                                               struct wpa_supplicant *wpa_s)
2363 {
2364           DBusMessageIter     iter, iter_dict;
2365           struct wpa_dbus_dict_entry entry;
2366           u8 peer[ETH_ALEN];
2367           struct hostapd_freq_params freq_params;
2368           u8 oper_class = 0;
2369           int ret;
2370           int is_peer_present = 0;
2371 
2372           if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
2373                     wpa_printf(MSG_INFO,
2374                                  "tdls_chanswitch: Only supported with external setup");
2375                     return wpas_dbus_error_unknown_error(message, "TDLS is not using external setup");
2376           }
2377 
2378           os_memset(&freq_params, 0, sizeof(freq_params));
2379 
2380           dbus_message_iter_init(message, &iter);
2381 
2382           if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2383                     return wpas_dbus_error_invalid_args(message, NULL);
2384 
2385           while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2386                     if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2387                               return wpas_dbus_error_invalid_args(message, NULL);
2388 
2389                     if (os_strcmp(entry.key, "PeerAddress") == 0 &&
2390                         entry.type == DBUS_TYPE_STRING) {
2391                               if (hwaddr_aton(entry.str_value, peer)) {
2392                                         wpa_printf(MSG_DEBUG,
2393                                                      "tdls_chanswitch: Invalid address '%s'",
2394                                                      entry.str_value);
2395                                         wpa_dbus_dict_entry_clear(&entry);
2396                                         return wpas_dbus_error_invalid_args(message,
2397                                                                                     NULL);
2398                               }
2399 
2400                               is_peer_present = 1;
2401                     } else if (os_strcmp(entry.key, "OperClass") == 0 &&
2402                                  entry.type == DBUS_TYPE_BYTE) {
2403                               oper_class = entry.byte_value;
2404                     } else if (os_strcmp(entry.key, "Frequency") == 0 &&
2405                                  entry.type == DBUS_TYPE_UINT32) {
2406                               freq_params.freq = entry.uint32_value;
2407                     } else if (os_strcmp(entry.key, "SecChannelOffset") == 0 &&
2408                                  entry.type == DBUS_TYPE_UINT32) {
2409                               freq_params.sec_channel_offset = entry.uint32_value;
2410                     } else if (os_strcmp(entry.key, "CenterFrequency1") == 0 &&
2411                                  entry.type == DBUS_TYPE_UINT32) {
2412                               freq_params.center_freq1 = entry.uint32_value;
2413                     } else if (os_strcmp(entry.key, "CenterFrequency2") == 0 &&
2414                                  entry.type == DBUS_TYPE_UINT32) {
2415                               freq_params.center_freq2 = entry.uint32_value;
2416                     } else if (os_strcmp(entry.key, "Bandwidth") == 0 &&
2417                                  entry.type == DBUS_TYPE_UINT32) {
2418                               freq_params.bandwidth = entry.uint32_value;
2419                     } else if (os_strcmp(entry.key, "HT") == 0 &&
2420                                  entry.type == DBUS_TYPE_BOOLEAN) {
2421                               freq_params.ht_enabled = entry.bool_value;
2422                     } else if (os_strcmp(entry.key, "VHT") == 0 &&
2423                                  entry.type == DBUS_TYPE_BOOLEAN) {
2424                               freq_params.vht_enabled = entry.bool_value;
2425                     } else {
2426                               wpa_dbus_dict_entry_clear(&entry);
2427                               return wpas_dbus_error_invalid_args(message, NULL);
2428                     }
2429 
2430                     wpa_dbus_dict_entry_clear(&entry);
2431           }
2432 
2433           if (oper_class == 0) {
2434                     wpa_printf(MSG_INFO,
2435                                  "tdls_chanswitch: Invalid op class provided");
2436                     return wpas_dbus_error_invalid_args(
2437                               message, "Invalid op class provided");
2438           }
2439 
2440           if (freq_params.freq == 0) {
2441                     wpa_printf(MSG_INFO,
2442                                  "tdls_chanswitch: Invalid freq provided");
2443                     return wpas_dbus_error_invalid_args(message,
2444                                                                 "Invalid freq provided");
2445           }
2446 
2447           if (is_peer_present == 0) {
2448                     wpa_printf(MSG_DEBUG,
2449                                  "tdls_chanswitch: peer address not provided");
2450                     return wpas_dbus_error_invalid_args(
2451                               message, "peer address not provided");
2452           }
2453 
2454           wpa_printf(MSG_DEBUG, "dbus: TDLS_CHAN_SWITCH " MACSTR
2455                        " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
2456                        MAC2STR(peer), oper_class, freq_params.freq,
2457                        freq_params.center_freq1, freq_params.center_freq2,
2458                        freq_params.bandwidth, freq_params.sec_channel_offset,
2459                        freq_params.ht_enabled ? " HT" : "",
2460                        freq_params.vht_enabled ? " VHT" : "");
2461 
2462           ret = wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
2463                                                     &freq_params);
2464           if (ret)
2465                     return wpas_dbus_error_unknown_error(
2466                               message, "error processing TDLS channel switch");
2467 
2468           return NULL;
2469 }
2470 
2471 /*
2472  * wpas_dbus_handler_tdls_cancel_channel_switch - Disable channel switching with TDLS peer
2473  * @message: Pointer to incoming dbus message
2474  * @wpa_s: wpa_supplicant structure for a network interface
2475  * Returns: NULL indicating success or DBus error message on failure
2476  *
2477  * Handler function for "TDLSCancelChannelSwitch" method call of network
2478  * interface.
2479  */
2480 DBusMessage *
wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage * message,struct wpa_supplicant * wpa_s)2481 wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message,
2482                                                        struct wpa_supplicant *wpa_s)
2483 {
2484           u8 peer[ETH_ALEN];
2485           DBusMessage *error_reply;
2486           int ret;
2487 
2488           if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0)
2489                     return error_reply;
2490 
2491           wpa_printf(MSG_DEBUG, "dbus: TDLS_CANCEL_CHAN_SWITCH " MACSTR,
2492                        MAC2STR(peer));
2493 
2494           ret = wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
2495           if (ret)
2496                     return wpas_dbus_error_unknown_error(
2497                               message, "error canceling TDLS channel switch");
2498 
2499           return NULL;
2500 }
2501 
2502 #endif /* CONFIG_TDLS */
2503 
2504 
2505 #ifndef CONFIG_NO_CONFIG_WRITE
2506 /**
2507  * wpas_dbus_handler_save_config - Save configuration to configuration file
2508  * @message: Pointer to incoming dbus message
2509  * @wpa_s: wpa_supplicant structure for a network interface
2510  * Returns: NULL on Success, Otherwise errror message
2511  *
2512  * Handler function for "SaveConfig" method call of network interface.
2513  */
wpas_dbus_handler_save_config(DBusMessage * message,struct wpa_supplicant * wpa_s)2514 DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
2515                                                       struct wpa_supplicant *wpa_s)
2516 {
2517           int ret;
2518 
2519           if (!wpa_s->conf->update_config) {
2520                     return wpas_dbus_error_unknown_error(
2521                               message,
2522                               "Not allowed to update configuration (update_config=0)");
2523           }
2524 
2525           ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
2526           if (ret)
2527                     return wpas_dbus_error_unknown_error(
2528                               message, "Failed to update configuration");
2529           return NULL;
2530 }
2531 #endif /* CONFIG_NO_CONFIG_WRITE */
2532 
2533 
2534 /**
2535  * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
2536  * @message: Pointer to incoming dbus message
2537  * @wpa_s: %wpa_supplicant data structure
2538  * Returns: A dbus message containing an error on failure or NULL on success
2539  *
2540  * Sets the PKCS #11 engine and module path.
2541  */
wpas_dbus_handler_set_pkcs11_engine_and_module_path(DBusMessage * message,struct wpa_supplicant * wpa_s)2542 DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path(
2543           DBusMessage *message, struct wpa_supplicant *wpa_s)
2544 {
2545           DBusMessageIter iter;
2546           char *value = NULL;
2547           char *pkcs11_engine_path = NULL;
2548           char *pkcs11_module_path = NULL;
2549 
2550           dbus_message_iter_init(message, &iter);
2551           dbus_message_iter_get_basic(&iter, &value);
2552           if (value == NULL) {
2553                     return dbus_message_new_error(
2554                               message, DBUS_ERROR_INVALID_ARGS,
2555                               "Invalid pkcs11_engine_path argument");
2556           }
2557           /* Empty path defaults to NULL */
2558           if (os_strlen(value))
2559                     pkcs11_engine_path = value;
2560 
2561           dbus_message_iter_next(&iter);
2562           dbus_message_iter_get_basic(&iter, &value);
2563           if (value == NULL) {
2564                     os_free(pkcs11_engine_path);
2565                     return dbus_message_new_error(
2566                               message, DBUS_ERROR_INVALID_ARGS,
2567                               "Invalid pkcs11_module_path argument");
2568           }
2569           /* Empty path defaults to NULL */
2570           if (os_strlen(value))
2571                     pkcs11_module_path = value;
2572 
2573           if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path,
2574                                                                pkcs11_module_path))
2575                     return dbus_message_new_error(
2576                               message, DBUS_ERROR_FAILED,
2577                               "Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
2578 
2579           if (wpa_s->dbus_new_path) {
2580                     wpa_dbus_mark_property_changed(
2581                               wpa_s->global->dbus, wpa_s->dbus_new_path,
2582                               WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath");
2583                     wpa_dbus_mark_property_changed(
2584                               wpa_s->global->dbus, wpa_s->dbus_new_path,
2585                               WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath");
2586           }
2587 
2588           return NULL;
2589 }
2590 
2591 
2592 /**
2593  * wpas_dbus_getter_capabilities - Return interface capabilities
2594  * @iter: Pointer to incoming dbus message iter
2595  * @error: Location to store error on failure
2596  * @user_data: Function specific data
2597  * Returns: TRUE on success, FALSE on failure
2598  *
2599  * Getter for "Capabilities" property of an interface.
2600  */
wpas_dbus_getter_capabilities(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)2601 dbus_bool_t wpas_dbus_getter_capabilities(
2602           const struct wpa_dbus_property_desc *property_desc,
2603           DBusMessageIter *iter, DBusError *error, void *user_data)
2604 {
2605           struct wpa_supplicant *wpa_s = user_data;
2606           struct wpa_driver_capa capa;
2607           int res;
2608           DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
2609                     variant_iter;
2610           const char *scans[] = { "active", "passive", "ssid" };
2611 
2612           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
2613                                                         "a{sv}", &variant_iter) ||
2614               !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
2615                     goto nomem;
2616 
2617           res = wpa_drv_get_capa(wpa_s, &capa);
2618 
2619           /***** pairwise cipher */
2620           if (res < 0) {
2621                     const char *args[] = {"ccmp", "tkip", "none"};
2622 
2623                     if (!wpa_dbus_dict_append_string_array(
2624                                   &iter_dict, "Pairwise", args,
2625                                   ARRAY_SIZE(args)))
2626                               goto nomem;
2627           } else {
2628                     if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
2629                                                                   &iter_dict_entry,
2630                                                                   &iter_dict_val,
2631                                                                   &iter_array) ||
2632                         ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2633                          !wpa_dbus_dict_string_array_add_element(
2634                                    &iter_array, "ccmp-256")) ||
2635                         ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2636                          !wpa_dbus_dict_string_array_add_element(
2637                                    &iter_array, "gcmp-256")) ||
2638                         ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2639                          !wpa_dbus_dict_string_array_add_element(
2640                                    &iter_array, "ccmp")) ||
2641                         ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2642                          !wpa_dbus_dict_string_array_add_element(
2643                                    &iter_array, "gcmp")) ||
2644                         ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2645                          !wpa_dbus_dict_string_array_add_element(
2646                                    &iter_array, "tkip")) ||
2647                         ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2648                          !wpa_dbus_dict_string_array_add_element(
2649                                    &iter_array, "none")) ||
2650                         !wpa_dbus_dict_end_string_array(&iter_dict,
2651                                                                 &iter_dict_entry,
2652                                                                 &iter_dict_val,
2653                                                                 &iter_array))
2654                               goto nomem;
2655           }
2656 
2657           /***** group cipher */
2658           if (res < 0) {
2659                     const char *args[] = {
2660                               "ccmp", "tkip", "wep104", "wep40"
2661                     };
2662 
2663                     if (!wpa_dbus_dict_append_string_array(
2664                                   &iter_dict, "Group", args,
2665                                   ARRAY_SIZE(args)))
2666                               goto nomem;
2667           } else {
2668                     if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
2669                                                                   &iter_dict_entry,
2670                                                                   &iter_dict_val,
2671                                                                   &iter_array) ||
2672                         ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
2673                          !wpa_dbus_dict_string_array_add_element(
2674                                    &iter_array, "ccmp-256")) ||
2675                         ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
2676                          !wpa_dbus_dict_string_array_add_element(
2677                                    &iter_array, "gcmp-256")) ||
2678                         ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
2679                          !wpa_dbus_dict_string_array_add_element(
2680                                    &iter_array, "ccmp")) ||
2681                         ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
2682                          !wpa_dbus_dict_string_array_add_element(
2683                                    &iter_array, "gcmp")) ||
2684                         ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
2685                          !wpa_dbus_dict_string_array_add_element(
2686                                    &iter_array, "tkip")) ||
2687                         ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
2688                          !wpa_dbus_dict_string_array_add_element(
2689                                    &iter_array, "wep104")) ||
2690                         ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
2691                          !wpa_dbus_dict_string_array_add_element(
2692                                    &iter_array, "wep40")) ||
2693                         !wpa_dbus_dict_end_string_array(&iter_dict,
2694                                                                 &iter_dict_entry,
2695                                                                 &iter_dict_val,
2696                                                                 &iter_array))
2697                               goto nomem;
2698           }
2699 
2700           if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt",
2701                                                         &iter_dict_entry,
2702                                                         &iter_dict_val,
2703                                                         &iter_array) ||
2704               (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) &&
2705                !wpa_dbus_dict_string_array_add_element(
2706                          &iter_array, "aes-128-cmac")) ||
2707               (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) &&
2708                !wpa_dbus_dict_string_array_add_element(
2709                          &iter_array, "bip-gmac-128")) ||
2710               (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) &&
2711                !wpa_dbus_dict_string_array_add_element(
2712                          &iter_array, "bip-gmac-256")) ||
2713               (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) &&
2714                !wpa_dbus_dict_string_array_add_element(
2715                          &iter_array, "bip-cmac-256")) ||
2716               !wpa_dbus_dict_end_string_array(&iter_dict,
2717                                                       &iter_dict_entry,
2718                                                       &iter_dict_val,
2719                                                       &iter_array))
2720                     goto nomem;
2721 
2722           /***** key management */
2723           if (res < 0) {
2724                     const char *args[] = {
2725                               "wpa-psk", "wpa-eap", "ieee8021x", "wpa-none",
2726 #ifdef CONFIG_WPS
2727                               "wps",
2728 #endif /* CONFIG_WPS */
2729                               "none"
2730                     };
2731                     if (!wpa_dbus_dict_append_string_array(
2732                                   &iter_dict, "KeyMgmt", args,
2733                                   ARRAY_SIZE(args)))
2734                               goto nomem;
2735           } else {
2736                     if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
2737                                                                   &iter_dict_entry,
2738                                                                   &iter_dict_val,
2739                                                                   &iter_array) ||
2740                         !wpa_dbus_dict_string_array_add_element(&iter_array,
2741                                                                           "none") ||
2742                         !wpa_dbus_dict_string_array_add_element(&iter_array,
2743                                                                           "ieee8021x"))
2744                               goto nomem;
2745 
2746                     if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2747                                              WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
2748                               if (!wpa_dbus_dict_string_array_add_element(
2749                                             &iter_array, "wpa-eap") ||
2750                                   ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
2751                                    !wpa_dbus_dict_string_array_add_element(
2752                                              &iter_array, "wpa-ft-eap")))
2753                                         goto nomem;
2754 
2755 /* TODO: Ensure that driver actually supports sha256 encryption. */
2756 #ifdef CONFIG_IEEE80211W
2757                               if (!wpa_dbus_dict_string_array_add_element(
2758                                             &iter_array, "wpa-eap-sha256"))
2759                                         goto nomem;
2760 #endif /* CONFIG_IEEE80211W */
2761                     }
2762 
2763                     if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
2764                                              WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
2765                               if (!wpa_dbus_dict_string_array_add_element(
2766                                             &iter_array, "wpa-psk") ||
2767                                   ((capa.key_mgmt &
2768                                     WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
2769                                    !wpa_dbus_dict_string_array_add_element(
2770                                              &iter_array, "wpa-ft-psk")))
2771                                         goto nomem;
2772 
2773 /* TODO: Ensure that driver actually supports sha256 encryption. */
2774 #ifdef CONFIG_IEEE80211W
2775                               if (!wpa_dbus_dict_string_array_add_element(
2776                                             &iter_array, "wpa-psk-sha256"))
2777                                         goto nomem;
2778 #endif /* CONFIG_IEEE80211W */
2779                     }
2780 
2781                     if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
2782                         !wpa_dbus_dict_string_array_add_element(&iter_array,
2783                                                                           "wpa-none"))
2784                               goto nomem;
2785 
2786 
2787 #ifdef CONFIG_WPS
2788                     if (!wpa_dbus_dict_string_array_add_element(&iter_array,
2789                                                                           "wps"))
2790                               goto nomem;
2791 #endif /* CONFIG_WPS */
2792 
2793                     if (!wpa_dbus_dict_end_string_array(&iter_dict,
2794                                                                 &iter_dict_entry,
2795                                                                 &iter_dict_val,
2796                                                                 &iter_array))
2797                               goto nomem;
2798           }
2799 
2800           /***** WPA protocol */
2801           if (res < 0) {
2802                     const char *args[] = { "rsn", "wpa" };
2803 
2804                     if (!wpa_dbus_dict_append_string_array(
2805                                   &iter_dict, "Protocol", args,
2806                                   ARRAY_SIZE(args)))
2807                               goto nomem;
2808           } else {
2809                     if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
2810                                                                   &iter_dict_entry,
2811                                                                   &iter_dict_val,
2812                                                                   &iter_array) ||
2813                         ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
2814                                                WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
2815                          !wpa_dbus_dict_string_array_add_element(
2816                                    &iter_array, "rsn")) ||
2817                         ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
2818                                                WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
2819                          !wpa_dbus_dict_string_array_add_element(
2820                                    &iter_array, "wpa")) ||
2821                         !wpa_dbus_dict_end_string_array(&iter_dict,
2822                                                                 &iter_dict_entry,
2823                                                                 &iter_dict_val,
2824                                                                 &iter_array))
2825                               goto nomem;
2826           }
2827 
2828           /***** auth alg */
2829           if (res < 0) {
2830                     const char *args[] = { "open", "shared", "leap" };
2831 
2832                     if (!wpa_dbus_dict_append_string_array(
2833                                   &iter_dict, "AuthAlg", args,
2834                                   ARRAY_SIZE(args)))
2835                               goto nomem;
2836           } else {
2837                     if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
2838                                                                   &iter_dict_entry,
2839                                                                   &iter_dict_val,
2840                                                                   &iter_array))
2841                               goto nomem;
2842 
2843                     if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
2844                          !wpa_dbus_dict_string_array_add_element(
2845                                    &iter_array, "open")) ||
2846                         ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
2847                          !wpa_dbus_dict_string_array_add_element(
2848                                    &iter_array, "shared")) ||
2849                         ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
2850                          !wpa_dbus_dict_string_array_add_element(
2851                                    &iter_array, "leap")) ||
2852                         !wpa_dbus_dict_end_string_array(&iter_dict,
2853                                                                 &iter_dict_entry,
2854                                                                 &iter_dict_val,
2855                                                                 &iter_array))
2856                               goto nomem;
2857           }
2858 
2859           /***** Scan */
2860           if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
2861                                                          ARRAY_SIZE(scans)))
2862                     goto nomem;
2863 
2864           /***** Modes */
2865           if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
2866                                                         &iter_dict_entry,
2867                                                         &iter_dict_val,
2868                                                         &iter_array) ||
2869               !wpa_dbus_dict_string_array_add_element(
2870                         &iter_array, "infrastructure") ||
2871               (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
2872                !wpa_dbus_dict_string_array_add_element(
2873                          &iter_array, "ad-hoc")) ||
2874               (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
2875                !wpa_dbus_dict_string_array_add_element(
2876                          &iter_array, "ap")) ||
2877               (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
2878                !wpa_s->conf->p2p_disabled &&
2879                !wpa_dbus_dict_string_array_add_element(
2880                          &iter_array, "p2p")) ||
2881 #ifdef CONFIG_MESH
2882               (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_MESH) &&
2883                !wpa_dbus_dict_string_array_add_element(
2884                          &iter_array, "mesh")) ||
2885 #endif /* CONFIG_MESH */
2886               !wpa_dbus_dict_end_string_array(&iter_dict,
2887                                                       &iter_dict_entry,
2888                                                       &iter_dict_val,
2889                                                       &iter_array))
2890                     goto nomem;
2891           /***** Modes end */
2892 
2893           if (res >= 0) {
2894                     dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
2895 
2896                     if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
2897                                                             max_scan_ssid))
2898                               goto nomem;
2899           }
2900 
2901           if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
2902               !dbus_message_iter_close_container(iter, &variant_iter))
2903                     goto nomem;
2904 
2905           return TRUE;
2906 
2907 nomem:
2908           dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2909           return FALSE;
2910 }
2911 
2912 
2913 /**
2914  * wpas_dbus_getter_state - Get interface state
2915  * @iter: Pointer to incoming dbus message iter
2916  * @error: Location to store error on failure
2917  * @user_data: Function specific data
2918  * Returns: TRUE on success, FALSE on failure
2919  *
2920  * Getter for "State" property.
2921  */
wpas_dbus_getter_state(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)2922 dbus_bool_t wpas_dbus_getter_state(
2923           const struct wpa_dbus_property_desc *property_desc,
2924           DBusMessageIter *iter, DBusError *error, void *user_data)
2925 {
2926           struct wpa_supplicant *wpa_s = user_data;
2927           const char *str_state;
2928           char *state_ls, *tmp;
2929           dbus_bool_t success = FALSE;
2930 
2931           str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
2932 
2933           /* make state string lowercase to fit new DBus API convention
2934            */
2935           state_ls = tmp = os_strdup(str_state);
2936           if (!tmp) {
2937                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
2938                     return FALSE;
2939           }
2940           while (*tmp) {
2941                     *tmp = tolower(*tmp);
2942                     tmp++;
2943           }
2944 
2945           success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
2946                                                                &state_ls, error);
2947 
2948           os_free(state_ls);
2949 
2950           return success;
2951 }
2952 
2953 
2954 /**
2955  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
2956  * @iter: Pointer to incoming dbus message iter
2957  * @error: Location to store error on failure
2958  * @user_data: Function specific data
2959  * Returns: TRUE on success, FALSE on failure
2960  *
2961  * Getter for "scanning" property.
2962  */
wpas_dbus_getter_scanning(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)2963 dbus_bool_t wpas_dbus_getter_scanning(
2964           const struct wpa_dbus_property_desc *property_desc,
2965           DBusMessageIter *iter, DBusError *error, void *user_data)
2966 {
2967           struct wpa_supplicant *wpa_s = user_data;
2968           dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
2969 
2970           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
2971                                                             &scanning, error);
2972 }
2973 
2974 
2975 /**
2976  * wpas_dbus_getter_ap_scan - Control roaming mode
2977  * @iter: Pointer to incoming dbus message iter
2978  * @error: Location to store error on failure
2979  * @user_data: Function specific data
2980  * Returns: TRUE on success, FALSE on failure
2981  *
2982  * Getter function for "ApScan" property.
2983  */
wpas_dbus_getter_ap_scan(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)2984 dbus_bool_t wpas_dbus_getter_ap_scan(
2985           const struct wpa_dbus_property_desc *property_desc,
2986           DBusMessageIter *iter, DBusError *error, void *user_data)
2987 {
2988           struct wpa_supplicant *wpa_s = user_data;
2989           dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
2990 
2991           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
2992                                                             &ap_scan, error);
2993 }
2994 
2995 
2996 /**
2997  * wpas_dbus_setter_ap_scan - Control roaming mode
2998  * @iter: Pointer to incoming dbus message iter
2999  * @error: Location to store error on failure
3000  * @user_data: Function specific data
3001  * Returns: TRUE on success, FALSE on failure
3002  *
3003  * Setter function for "ApScan" property.
3004  */
wpas_dbus_setter_ap_scan(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3005 dbus_bool_t wpas_dbus_setter_ap_scan(
3006           const struct wpa_dbus_property_desc *property_desc,
3007           DBusMessageIter *iter, DBusError *error, void *user_data)
3008 {
3009           struct wpa_supplicant *wpa_s = user_data;
3010           dbus_uint32_t ap_scan;
3011 
3012           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3013                                                         &ap_scan))
3014                     return FALSE;
3015 
3016           if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
3017                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
3018                                              "ap_scan must be 0, 1, or 2");
3019                     return FALSE;
3020           }
3021           return TRUE;
3022 }
3023 
3024 
3025 /**
3026  * wpas_dbus_getter_fast_reauth - Control fast
3027  * reauthentication (TLS session resumption)
3028  * @iter: Pointer to incoming dbus message iter
3029  * @error: Location to store error on failure
3030  * @user_data: Function specific data
3031  * Returns: TRUE on success, FALSE on failure
3032  *
3033  * Getter function for "FastReauth" property.
3034  */
wpas_dbus_getter_fast_reauth(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3035 dbus_bool_t wpas_dbus_getter_fast_reauth(
3036           const struct wpa_dbus_property_desc *property_desc,
3037           DBusMessageIter *iter, DBusError *error, void *user_data)
3038 {
3039           struct wpa_supplicant *wpa_s = user_data;
3040           dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE;
3041 
3042           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3043                                                             &fast_reauth, error);
3044 }
3045 
3046 
3047 /**
3048  * wpas_dbus_setter_fast_reauth - Control fast
3049  * reauthentication (TLS session resumption)
3050  * @iter: Pointer to incoming dbus message iter
3051  * @error: Location to store error on failure
3052  * @user_data: Function specific data
3053  * Returns: TRUE on success, FALSE on failure
3054  *
3055  * Setter function for "FastReauth" property.
3056  */
wpas_dbus_setter_fast_reauth(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3057 dbus_bool_t wpas_dbus_setter_fast_reauth(
3058           const struct wpa_dbus_property_desc *property_desc,
3059           DBusMessageIter *iter, DBusError *error, void *user_data)
3060 {
3061           struct wpa_supplicant *wpa_s = user_data;
3062           dbus_bool_t fast_reauth;
3063 
3064           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
3065                                                         &fast_reauth))
3066                     return FALSE;
3067 
3068           wpa_s->conf->fast_reauth = fast_reauth;
3069           return TRUE;
3070 }
3071 
3072 
3073 /**
3074  * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect
3075  * @iter: Pointer to incoming dbus message iter
3076  * @error: Location to store error on failure
3077  * @user_data: Function specific data
3078  * Returns: TRUE on success, FALSE on failure
3079  *
3080  * Getter for "DisconnectReason" property.  The reason is negative if it is
3081  * locally generated.
3082  */
wpas_dbus_getter_disconnect_reason(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3083 dbus_bool_t wpas_dbus_getter_disconnect_reason(
3084           const struct wpa_dbus_property_desc *property_desc,
3085           DBusMessageIter *iter, DBusError *error, void *user_data)
3086 {
3087           struct wpa_supplicant *wpa_s = user_data;
3088           dbus_int32_t reason = wpa_s->disconnect_reason;
3089 
3090           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3091                                                             &reason, error);
3092 }
3093 
3094 
3095 /**
3096  * wpas_dbus_getter_auth_status_code - Get most recent auth status code
3097  * @iter: Pointer to incoming dbus message iter
3098  * @error: Location to store error on failure
3099  * @user_data: Function specific data
3100  * Returns: TRUE on success, FALSE on failure
3101  *
3102  * Getter for "AuthStatusCode" property.
3103  */
wpas_dbus_getter_auth_status_code(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3104 dbus_bool_t wpas_dbus_getter_auth_status_code(
3105           const struct wpa_dbus_property_desc *property_desc,
3106           DBusMessageIter *iter, DBusError *error, void *user_data)
3107 {
3108           struct wpa_supplicant *wpa_s = user_data;
3109           dbus_int32_t reason = wpa_s->auth_status_code;
3110 
3111           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3112                                                             &reason, error);
3113 }
3114 
3115 
3116 /**
3117  * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
3118  * @iter: Pointer to incoming dbus message iter
3119  * @error: Location to store error on failure
3120  * @user_data: Function specific data
3121  * Returns: TRUE on success, FALSE on failure
3122  *
3123  * Getter for "AssocStatusCode" property.
3124  */
wpas_dbus_getter_assoc_status_code(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3125 dbus_bool_t wpas_dbus_getter_assoc_status_code(
3126           const struct wpa_dbus_property_desc *property_desc,
3127           DBusMessageIter *iter, DBusError *error, void *user_data)
3128 {
3129           struct wpa_supplicant *wpa_s = user_data;
3130           dbus_int32_t status_code = wpa_s->assoc_status_code;
3131 
3132           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3133                                                             &status_code, error);
3134 }
3135 
3136 
3137 /**
3138  * wpas_dbus_getter_roam_time - Get most recent roam time
3139  * @iter: Pointer to incoming dbus message iter
3140  * @error: Location to store error on failure
3141  * @user_data: Function specific data
3142  * Returns: TRUE on success, FALSE on failure
3143  *
3144  * Getter for "RoamTime" property.
3145  */
wpas_dbus_getter_roam_time(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3146 dbus_bool_t wpas_dbus_getter_roam_time(
3147           const struct wpa_dbus_property_desc *property_desc,
3148           DBusMessageIter *iter, DBusError *error, void *user_data)
3149 {
3150           struct wpa_supplicant *wpa_s = user_data;
3151           dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 +
3152                     wpa_s->roam_time.usec / 1000;
3153 
3154           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3155                                                             &roam_time, error);
3156 }
3157 
3158 
3159 /**
3160  * wpas_dbus_getter_roam_complete - Get most recent roam success or failure
3161  * @iter: Pointer to incoming dbus message iter
3162  * @error: Location to store error on failure
3163  * @user_data: Function specific data
3164  * Returns: TRUE on success, FALSE on failure
3165  *
3166  * Getter for "RoamComplete" property.
3167  */
wpas_dbus_getter_roam_complete(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3168 dbus_bool_t wpas_dbus_getter_roam_complete(
3169           const struct wpa_dbus_property_desc *property_desc,
3170           DBusMessageIter *iter, DBusError *error, void *user_data)
3171 {
3172           struct wpa_supplicant *wpa_s = user_data;
3173           dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time);
3174 
3175           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
3176                                                             &roam_complete, error);
3177 }
3178 
3179 
3180 /**
3181  * wpas_dbus_getter_session_length - Get most recent BSS session length
3182  * @iter: Pointer to incoming dbus message iter
3183  * @error: Location to store error on failure
3184  * @user_data: Function specific data
3185  * Returns: TRUE on success, FALSE on failure
3186  *
3187  * Getter for "SessionLength" property.
3188  */
wpas_dbus_getter_session_length(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3189 dbus_bool_t wpas_dbus_getter_session_length(
3190           const struct wpa_dbus_property_desc *property_desc,
3191           DBusMessageIter *iter, DBusError *error, void *user_data)
3192 {
3193           struct wpa_supplicant *wpa_s = user_data;
3194           dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 +
3195                     wpa_s->session_length.usec / 1000;
3196 
3197           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3198                                                             &session_length, error);
3199 }
3200 
3201 
3202 /**
3203  * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request
3204  * status code
3205  * @iter: Pointer to incoming dbus message iter
3206  * @error: Location to store error on failure
3207  * @user_data: Function specific data
3208  * Returns: TRUE on success, FALSE on failure
3209  *
3210  * Getter for "BSSTMStatus" property.
3211  */
wpas_dbus_getter_bss_tm_status(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3212 dbus_bool_t wpas_dbus_getter_bss_tm_status(
3213           const struct wpa_dbus_property_desc *property_desc,
3214           DBusMessageIter *iter, DBusError *error, void *user_data)
3215 {
3216 #ifdef CONFIG_WNM
3217           struct wpa_supplicant *wpa_s = user_data;
3218           dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status;
3219 #else /* CONFIG_WNM */
3220           dbus_uint32_t bss_tm_status = 0;
3221 #endif /* CONFIG_WNM */
3222 
3223           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3224                                                             &bss_tm_status, error);
3225 }
3226 
3227 
3228 /**
3229  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
3230  * @iter: Pointer to incoming dbus message iter
3231  * @error: Location to store error on failure
3232  * @user_data: Function specific data
3233  * Returns: TRUE on success, FALSE on failure
3234  *
3235  * Getter function for "BSSExpireAge" property.
3236  */
wpas_dbus_getter_bss_expire_age(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3237 dbus_bool_t wpas_dbus_getter_bss_expire_age(
3238           const struct wpa_dbus_property_desc *property_desc,
3239           DBusMessageIter *iter, DBusError *error, void *user_data)
3240 {
3241           struct wpa_supplicant *wpa_s = user_data;
3242           dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
3243 
3244           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3245                                                             &expire_age, error);
3246 }
3247 
3248 
3249 /**
3250  * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
3251  * @iter: Pointer to incoming dbus message iter
3252  * @error: Location to store error on failure
3253  * @user_data: Function specific data
3254  * Returns: TRUE on success, FALSE on failure
3255  *
3256  * Setter function for "BSSExpireAge" property.
3257  */
wpas_dbus_setter_bss_expire_age(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3258 dbus_bool_t wpas_dbus_setter_bss_expire_age(
3259           const struct wpa_dbus_property_desc *property_desc,
3260           DBusMessageIter *iter, DBusError *error, void *user_data)
3261 {
3262           struct wpa_supplicant *wpa_s = user_data;
3263           dbus_uint32_t expire_age;
3264 
3265           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3266                                                         &expire_age))
3267                     return FALSE;
3268 
3269           if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
3270                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
3271                                              "BSSExpireAge must be >= 10");
3272                     return FALSE;
3273           }
3274           return TRUE;
3275 }
3276 
3277 
3278 /**
3279  * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
3280  * @iter: Pointer to incoming dbus message iter
3281  * @error: Location to store error on failure
3282  * @user_data: Function specific data
3283  * Returns: TRUE on success, FALSE on failure
3284  *
3285  * Getter function for "BSSExpireCount" property.
3286  */
wpas_dbus_getter_bss_expire_count(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3287 dbus_bool_t wpas_dbus_getter_bss_expire_count(
3288           const struct wpa_dbus_property_desc *property_desc,
3289           DBusMessageIter *iter, DBusError *error, void *user_data)
3290 {
3291           struct wpa_supplicant *wpa_s = user_data;
3292           dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
3293 
3294           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
3295                                                             &expire_count, error);
3296 }
3297 
3298 
3299 /**
3300  * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
3301  * @iter: Pointer to incoming dbus message iter
3302  * @error: Location to store error on failure
3303  * @user_data: Function specific data
3304  * Returns: TRUE on success, FALSE on failure
3305  *
3306  * Setter function for "BSSExpireCount" property.
3307  */
wpas_dbus_setter_bss_expire_count(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3308 dbus_bool_t wpas_dbus_setter_bss_expire_count(
3309           const struct wpa_dbus_property_desc *property_desc,
3310           DBusMessageIter *iter, DBusError *error, void *user_data)
3311 {
3312           struct wpa_supplicant *wpa_s = user_data;
3313           dbus_uint32_t expire_count;
3314 
3315           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
3316                                                         &expire_count))
3317                     return FALSE;
3318 
3319           if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
3320                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
3321                                              "BSSExpireCount must be > 0");
3322                     return FALSE;
3323           }
3324           return TRUE;
3325 }
3326 
3327 
3328 /**
3329  * wpas_dbus_getter_country - Control country code
3330  * @iter: Pointer to incoming dbus message iter
3331  * @error: Location to store error on failure
3332  * @user_data: Function specific data
3333  * Returns: TRUE on success, FALSE on failure
3334  *
3335  * Getter function for "Country" property.
3336  */
wpas_dbus_getter_country(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3337 dbus_bool_t wpas_dbus_getter_country(
3338           const struct wpa_dbus_property_desc *property_desc,
3339           DBusMessageIter *iter, DBusError *error, void *user_data)
3340 {
3341           struct wpa_supplicant *wpa_s = user_data;
3342           char country[3];
3343           char *str = country;
3344 
3345           country[0] = wpa_s->conf->country[0];
3346           country[1] = wpa_s->conf->country[1];
3347           country[2] = '\0';
3348 
3349           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3350                                                             &str, error);
3351 }
3352 
3353 
3354 /**
3355  * wpas_dbus_setter_country - Control country code
3356  * @iter: Pointer to incoming dbus message iter
3357  * @error: Location to store error on failure
3358  * @user_data: Function specific data
3359  * Returns: TRUE on success, FALSE on failure
3360  *
3361  * Setter function for "Country" property.
3362  */
wpas_dbus_setter_country(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3363 dbus_bool_t wpas_dbus_setter_country(
3364           const struct wpa_dbus_property_desc *property_desc,
3365           DBusMessageIter *iter, DBusError *error, void *user_data)
3366 {
3367           struct wpa_supplicant *wpa_s = user_data;
3368           const char *country;
3369 
3370           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
3371                                                         &country))
3372                     return FALSE;
3373 
3374           if (!country[0] || !country[1]) {
3375                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
3376                                              "invalid country code");
3377                     return FALSE;
3378           }
3379 
3380           if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
3381                     wpa_printf(MSG_DEBUG, "Failed to set country");
3382                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
3383                                              "failed to set country code");
3384                     return FALSE;
3385           }
3386 
3387           wpa_s->conf->country[0] = country[0];
3388           wpa_s->conf->country[1] = country[1];
3389           return TRUE;
3390 }
3391 
3392 
3393 /**
3394  * wpas_dbus_getter_scan_interval - Get scan interval
3395  * @iter: Pointer to incoming dbus message iter
3396  * @error: Location to store error on failure
3397  * @user_data: Function specific data
3398  * Returns: TRUE on success, FALSE on failure
3399  *
3400  * Getter function for "ScanInterval" property.
3401  */
wpas_dbus_getter_scan_interval(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3402 dbus_bool_t wpas_dbus_getter_scan_interval(
3403           const struct wpa_dbus_property_desc *property_desc,
3404           DBusMessageIter *iter, DBusError *error, void *user_data)
3405 {
3406           struct wpa_supplicant *wpa_s = user_data;
3407           dbus_int32_t scan_interval = wpa_s->scan_interval;
3408 
3409           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
3410                                                             &scan_interval, error);
3411 }
3412 
3413 
3414 /**
3415  * wpas_dbus_setter_scan_interval - Control scan interval
3416  * @iter: Pointer to incoming dbus message iter
3417  * @error: Location to store error on failure
3418  * @user_data: Function specific data
3419  * Returns: TRUE on success, FALSE on failure
3420  *
3421  * Setter function for "ScanInterval" property.
3422  */
wpas_dbus_setter_scan_interval(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3423 dbus_bool_t wpas_dbus_setter_scan_interval(
3424           const struct wpa_dbus_property_desc *property_desc,
3425           DBusMessageIter *iter, DBusError *error, void *user_data)
3426 {
3427           struct wpa_supplicant *wpa_s = user_data;
3428           dbus_int32_t scan_interval;
3429 
3430           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32,
3431                                                         &scan_interval))
3432                     return FALSE;
3433 
3434           if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) {
3435                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
3436                                              "scan_interval must be >= 0");
3437                     return FALSE;
3438           }
3439           return TRUE;
3440 }
3441 
3442 
3443 /**
3444  * wpas_dbus_getter_ifname - Get interface name
3445  * @iter: Pointer to incoming dbus message iter
3446  * @error: Location to store error on failure
3447  * @user_data: Function specific data
3448  * Returns: TRUE on success, FALSE on failure
3449  *
3450  * Getter for "Ifname" property.
3451  */
wpas_dbus_getter_ifname(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3452 dbus_bool_t wpas_dbus_getter_ifname(
3453           const struct wpa_dbus_property_desc *property_desc,
3454           DBusMessageIter *iter, DBusError *error, void *user_data)
3455 {
3456           struct wpa_supplicant *wpa_s = user_data;
3457 
3458           return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error);
3459 }
3460 
3461 
3462 /**
3463  * wpas_dbus_getter_driver - Get interface name
3464  * @iter: Pointer to incoming dbus message iter
3465  * @error: Location to store error on failure
3466  * @user_data: Function specific data
3467  * Returns: TRUE on success, FALSE on failure
3468  *
3469  * Getter for "Driver" property.
3470  */
wpas_dbus_getter_driver(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3471 dbus_bool_t wpas_dbus_getter_driver(
3472           const struct wpa_dbus_property_desc *property_desc,
3473           DBusMessageIter *iter, DBusError *error, void *user_data)
3474 {
3475           struct wpa_supplicant *wpa_s = user_data;
3476 
3477           if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
3478                     wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
3479                                  __func__);
3480                     dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
3481                                      __func__);
3482                     return FALSE;
3483           }
3484 
3485           return wpas_dbus_string_property_getter(iter, wpa_s->driver->name,
3486                                                             error);
3487 }
3488 
3489 
3490 /**
3491  * wpas_dbus_getter_current_bss - Get current bss object path
3492  * @iter: Pointer to incoming dbus message iter
3493  * @error: Location to store error on failure
3494  * @user_data: Function specific data
3495  * Returns: TRUE on success, FALSE on failure
3496  *
3497  * Getter for "CurrentBSS" property.
3498  */
wpas_dbus_getter_current_bss(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3499 dbus_bool_t wpas_dbus_getter_current_bss(
3500           const struct wpa_dbus_property_desc *property_desc,
3501           DBusMessageIter *iter, DBusError *error, void *user_data)
3502 {
3503           struct wpa_supplicant *wpa_s = user_data;
3504           char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
3505 
3506           if (wpa_s->current_bss && wpa_s->dbus_new_path)
3507                     os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3508                                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3509                                   wpa_s->dbus_new_path, wpa_s->current_bss->id);
3510           else
3511                     os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3512 
3513           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3514                                                             &bss_obj_path, error);
3515 }
3516 
3517 
3518 /**
3519  * wpas_dbus_getter_current_network - Get current network object path
3520  * @iter: Pointer to incoming dbus message iter
3521  * @error: Location to store error on failure
3522  * @user_data: Function specific data
3523  * Returns: TRUE on success, FALSE on failure
3524  *
3525  * Getter for "CurrentNetwork" property.
3526  */
wpas_dbus_getter_current_network(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3527 dbus_bool_t wpas_dbus_getter_current_network(
3528           const struct wpa_dbus_property_desc *property_desc,
3529           DBusMessageIter *iter, DBusError *error, void *user_data)
3530 {
3531           struct wpa_supplicant *wpa_s = user_data;
3532           char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
3533 
3534           if (wpa_s->current_ssid && wpa_s->dbus_new_path)
3535                     os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
3536                                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
3537                                   wpa_s->dbus_new_path, wpa_s->current_ssid->id);
3538           else
3539                     os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
3540 
3541           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
3542                                                             &net_obj_path, error);
3543 }
3544 
3545 
3546 /**
3547  * wpas_dbus_getter_current_auth_mode - Get current authentication type
3548  * @iter: Pointer to incoming dbus message iter
3549  * @error: Location to store error on failure
3550  * @user_data: Function specific data
3551  * Returns: TRUE on success, FALSE on failure
3552  *
3553  * Getter for "CurrentAuthMode" property.
3554  */
wpas_dbus_getter_current_auth_mode(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3555 dbus_bool_t wpas_dbus_getter_current_auth_mode(
3556           const struct wpa_dbus_property_desc *property_desc,
3557           DBusMessageIter *iter, DBusError *error, void *user_data)
3558 {
3559           struct wpa_supplicant *wpa_s = user_data;
3560           const char *eap_mode;
3561           const char *auth_mode;
3562           char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
3563 
3564           if (wpa_s->wpa_state != WPA_COMPLETED) {
3565                     auth_mode = "INACTIVE";
3566           } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
3567               wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3568                     eap_mode = wpa_supplicant_get_eap_mode(wpa_s);
3569                     os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX,
3570                                   "EAP-%s", eap_mode);
3571                     auth_mode = eap_mode_buf;
3572 
3573           } else if (wpa_s->current_ssid) {
3574                     auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
3575                                                        wpa_s->current_ssid->proto);
3576           } else {
3577                     auth_mode = "UNKNOWN";
3578           }
3579 
3580           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
3581                                                             &auth_mode, error);
3582 }
3583 
3584 
3585 /**
3586  * wpas_dbus_getter_bridge_ifname - Get interface name
3587  * @iter: Pointer to incoming dbus message iter
3588  * @error: Location to store error on failure
3589  * @user_data: Function specific data
3590  * Returns: TRUE on success, FALSE on failure
3591  *
3592  * Getter for "BridgeIfname" property.
3593  */
wpas_dbus_getter_bridge_ifname(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3594 dbus_bool_t wpas_dbus_getter_bridge_ifname(
3595           const struct wpa_dbus_property_desc *property_desc,
3596           DBusMessageIter *iter, DBusError *error, void *user_data)
3597 {
3598           struct wpa_supplicant *wpa_s = user_data;
3599 
3600           return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname,
3601                                                             error);
3602 }
3603 
3604 
3605 /**
3606  * wpas_dbus_getter_config_file - Get interface configuration file path
3607  * @iter: Pointer to incoming dbus message iter
3608  * @error: Location to store error on failure
3609  * @user_data: Function specific data
3610  * Returns: TRUE on success, FALSE on failure
3611  *
3612  * Getter for "ConfigFile" property.
3613  */
wpas_dbus_getter_config_file(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3614 dbus_bool_t wpas_dbus_getter_config_file(
3615           const struct wpa_dbus_property_desc *property_desc,
3616           DBusMessageIter *iter, DBusError *error, void *user_data)
3617 {
3618           struct wpa_supplicant *wpa_s = user_data;
3619 
3620           return wpas_dbus_string_property_getter(iter, wpa_s->confname, error);
3621 }
3622 
3623 
3624 /**
3625  * wpas_dbus_getter_bsss - Get array of BSSs objects
3626  * @iter: Pointer to incoming dbus message iter
3627  * @error: Location to store error on failure
3628  * @user_data: Function specific data
3629  * Returns: TRUE on success, FALSE on failure
3630  *
3631  * Getter for "BSSs" property.
3632  */
wpas_dbus_getter_bsss(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3633 dbus_bool_t wpas_dbus_getter_bsss(
3634           const struct wpa_dbus_property_desc *property_desc,
3635           DBusMessageIter *iter, DBusError *error, void *user_data)
3636 {
3637           struct wpa_supplicant *wpa_s = user_data;
3638           struct wpa_bss *bss;
3639           char **paths;
3640           unsigned int i = 0;
3641           dbus_bool_t success = FALSE;
3642 
3643           if (!wpa_s->dbus_new_path) {
3644                     dbus_set_error(error, DBUS_ERROR_FAILED,
3645                                      "%s: no D-Bus interface", __func__);
3646                     return FALSE;
3647           }
3648 
3649           paths = os_calloc(wpa_s->num_bss, sizeof(char *));
3650           if (!paths) {
3651                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3652                     return FALSE;
3653           }
3654 
3655           /* Loop through scan results and append each result's object path */
3656           dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
3657                     paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3658                     if (paths[i] == NULL) {
3659                               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3660                                                        "no memory");
3661                               goto out;
3662                     }
3663                     /* Construct the object path for this BSS. */
3664                     os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3665                                   "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u",
3666                                   wpa_s->dbus_new_path, bss->id);
3667           }
3668 
3669           success = wpas_dbus_simple_array_property_getter(iter,
3670                                                                        DBUS_TYPE_OBJECT_PATH,
3671                                                                        paths, wpa_s->num_bss,
3672                                                                        error);
3673 
3674 out:
3675           while (i)
3676                     os_free(paths[--i]);
3677           os_free(paths);
3678           return success;
3679 }
3680 
3681 
3682 /**
3683  * wpas_dbus_getter_networks - Get array of networks objects
3684  * @iter: Pointer to incoming dbus message iter
3685  * @error: Location to store error on failure
3686  * @user_data: Function specific data
3687  * Returns: TRUE on success, FALSE on failure
3688  *
3689  * Getter for "Networks" property.
3690  */
wpas_dbus_getter_networks(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3691 dbus_bool_t wpas_dbus_getter_networks(
3692           const struct wpa_dbus_property_desc *property_desc,
3693           DBusMessageIter *iter, DBusError *error, void *user_data)
3694 {
3695           struct wpa_supplicant *wpa_s = user_data;
3696           struct wpa_ssid *ssid;
3697           char **paths;
3698           unsigned int i = 0, num = 0;
3699           dbus_bool_t success = FALSE;
3700 
3701           if (!wpa_s->dbus_new_path) {
3702                     dbus_set_error(error, DBUS_ERROR_FAILED,
3703                                      "%s: no D-Bus interface", __func__);
3704                     return FALSE;
3705           }
3706 
3707           for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
3708                     if (!network_is_persistent_group(ssid))
3709                               num++;
3710 
3711           paths = os_calloc(num, sizeof(char *));
3712           if (!paths) {
3713                     dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
3714                     return FALSE;
3715           }
3716 
3717           /* Loop through configured networks and append object path of each */
3718           for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
3719                     if (network_is_persistent_group(ssid))
3720                               continue;
3721                     paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3722                     if (paths[i] == NULL) {
3723                               dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
3724                                                "no memory");
3725                               goto out;
3726                     }
3727 
3728                     /* Construct the object path for this network. */
3729                     os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3730                                   "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
3731                                   wpa_s->dbus_new_path, ssid->id);
3732           }
3733 
3734           success = wpas_dbus_simple_array_property_getter(iter,
3735                                                                        DBUS_TYPE_OBJECT_PATH,
3736                                                                        paths, num, error);
3737 
3738 out:
3739           while (i)
3740                     os_free(paths[--i]);
3741           os_free(paths);
3742           return success;
3743 }
3744 
3745 
3746 /**
3747  * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path
3748  * @iter: Pointer to incoming dbus message iter
3749  * @error: Location to store error on failure
3750  * @user_data: Function specific data
3751  * Returns: A dbus message containing the PKCS #11 engine path
3752  *
3753  * Getter for "PKCS11EnginePath" property.
3754  */
wpas_dbus_getter_pkcs11_engine_path(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3755 dbus_bool_t wpas_dbus_getter_pkcs11_engine_path(
3756           const struct wpa_dbus_property_desc *property_desc,
3757           DBusMessageIter *iter, DBusError *error, void *user_data)
3758 {
3759           struct wpa_supplicant *wpa_s = user_data;
3760 
3761           return wpas_dbus_string_property_getter(iter,
3762                                                             wpa_s->conf->pkcs11_engine_path,
3763                                                             error);
3764 }
3765 
3766 
3767 /**
3768  * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path
3769  * @iter: Pointer to incoming dbus message iter
3770  * @error: Location to store error on failure
3771  * @user_data: Function specific data
3772  * Returns: A dbus message containing the PKCS #11 module path
3773  *
3774  * Getter for "PKCS11ModulePath" property.
3775  */
wpas_dbus_getter_pkcs11_module_path(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3776 dbus_bool_t wpas_dbus_getter_pkcs11_module_path(
3777           const struct wpa_dbus_property_desc *property_desc,
3778           DBusMessageIter *iter, DBusError *error, void *user_data)
3779 {
3780           struct wpa_supplicant *wpa_s = user_data;
3781 
3782           return wpas_dbus_string_property_getter(iter,
3783                                                             wpa_s->conf->pkcs11_module_path,
3784                                                             error);
3785 }
3786 
3787 
3788 /**
3789  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
3790  * @iter: Pointer to incoming dbus message iter
3791  * @error: Location to store error on failure
3792  * @user_data: Function specific data
3793  * Returns: TRUE on success, FALSE on failure
3794  *
3795  * Getter for "Blobs" property.
3796  */
wpas_dbus_getter_blobs(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3797 dbus_bool_t wpas_dbus_getter_blobs(
3798           const struct wpa_dbus_property_desc *property_desc,
3799           DBusMessageIter *iter, DBusError *error, void *user_data)
3800 {
3801           struct wpa_supplicant *wpa_s = user_data;
3802           DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
3803           struct wpa_config_blob *blob;
3804 
3805           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
3806                                                         "a{say}", &variant_iter) ||
3807               !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
3808                                                         "{say}", &dict_iter)) {
3809                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3810                     return FALSE;
3811           }
3812 
3813           blob = wpa_s->conf->blobs;
3814           while (blob) {
3815                     if (!dbus_message_iter_open_container(&dict_iter,
3816                                                                   DBUS_TYPE_DICT_ENTRY,
3817                                                                   NULL, &entry_iter) ||
3818                         !dbus_message_iter_append_basic(&entry_iter,
3819                                                                 DBUS_TYPE_STRING,
3820                                                                 &(blob->name)) ||
3821                         !dbus_message_iter_open_container(&entry_iter,
3822                                                                   DBUS_TYPE_ARRAY,
3823                                                                   DBUS_TYPE_BYTE_AS_STRING,
3824                                                                   &array_iter) ||
3825                         !dbus_message_iter_append_fixed_array(&array_iter,
3826                                                                         DBUS_TYPE_BYTE,
3827                                                                         &(blob->data),
3828                                                                         blob->len) ||
3829                         !dbus_message_iter_close_container(&entry_iter,
3830                                                                    &array_iter) ||
3831                         !dbus_message_iter_close_container(&dict_iter,
3832                                                                    &entry_iter)) {
3833                               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3834                                                        "no memory");
3835                               return FALSE;
3836                     }
3837 
3838                     blob = blob->next;
3839           }
3840 
3841           if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
3842               !dbus_message_iter_close_container(iter, &variant_iter)) {
3843                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3844                     return FALSE;
3845           }
3846 
3847           return TRUE;
3848 }
3849 
3850 
wpas_dbus_getter_iface_global(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3851 dbus_bool_t wpas_dbus_getter_iface_global(
3852           const struct wpa_dbus_property_desc *property_desc,
3853           DBusMessageIter *iter, DBusError *error, void *user_data)
3854 {
3855           struct wpa_supplicant *wpa_s = user_data;
3856           int ret;
3857           char buf[250];
3858           char *p = buf;
3859 
3860           if (!property_desc->data) {
3861                     dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
3862                                      "Unhandled interface property %s",
3863                                      property_desc->dbus_property);
3864                     return FALSE;
3865           }
3866 
3867           ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf,
3868                                            sizeof(buf));
3869           if (ret < 0)
3870                     *p = '\0';
3871 
3872           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p,
3873                                                             error);
3874 }
3875 
3876 
wpas_dbus_setter_iface_global(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3877 dbus_bool_t wpas_dbus_setter_iface_global(
3878           const struct wpa_dbus_property_desc *property_desc,
3879           DBusMessageIter *iter, DBusError *error, void *user_data)
3880 {
3881           struct wpa_supplicant *wpa_s = user_data;
3882           const char *new_value = NULL;
3883           char buf[250];
3884           size_t combined_len;
3885           int ret;
3886 
3887           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
3888                                                         &new_value))
3889                     return FALSE;
3890 
3891           combined_len = os_strlen(property_desc->data) + os_strlen(new_value) +
3892                     3;
3893           if (combined_len >= sizeof(buf)) {
3894                     dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
3895                                      "Interface property %s value too large",
3896                                      property_desc->dbus_property);
3897                     return FALSE;
3898           }
3899 
3900           if (!new_value[0])
3901                     new_value = "NULL";
3902 
3903           ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
3904                                 new_value);
3905           if (os_snprintf_error(combined_len, ret)) {
3906                     dbus_set_error(error,  WPAS_DBUS_ERROR_UNKNOWN_ERROR,
3907                                      "Failed to construct new interface property %s",
3908                                      property_desc->dbus_property);
3909                     return FALSE;
3910           }
3911 
3912           if (wpa_config_process_global(wpa_s->conf, buf, -1)) {
3913                     dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
3914                                      "Failed to set interface property %s",
3915                                      property_desc->dbus_property);
3916                     return FALSE;
3917           }
3918 
3919           wpa_supplicant_update_config(wpa_s);
3920           return TRUE;
3921 }
3922 
3923 
3924 /**
3925  * wpas_dbus_getter_stas - Get connected stations for an interface
3926  * @iter: Pointer to incoming dbus message iter
3927  * @error: Location to store error on failure
3928  * @user_data: Function specific data
3929  * Returns: a list of stations
3930  *
3931  * Getter for "Stations" property.
3932  */
wpas_dbus_getter_stas(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)3933 dbus_bool_t wpas_dbus_getter_stas(
3934           const struct wpa_dbus_property_desc *property_desc,
3935           DBusMessageIter *iter, DBusError *error, void *user_data)
3936 {
3937           struct wpa_supplicant *wpa_s = user_data;
3938           struct sta_info *sta = NULL;
3939           char **paths = NULL;
3940           unsigned int i = 0, num = 0;
3941           dbus_bool_t success = FALSE;
3942 
3943           if (!wpa_s->dbus_new_path) {
3944                     dbus_set_error(error, DBUS_ERROR_FAILED,
3945                                      "%s: no D-Bus interface", __func__);
3946                     return FALSE;
3947           }
3948 
3949 #ifdef CONFIG_AP
3950           if (wpa_s->ap_iface) {
3951                     struct hostapd_data *hapd;
3952 
3953                     hapd = wpa_s->ap_iface->bss[0];
3954                     sta = hapd->sta_list;
3955                     num = hapd->num_sta;
3956           }
3957 #endif /* CONFIG_AP */
3958 
3959           paths = os_calloc(num, sizeof(char *));
3960           if (!paths) {
3961                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
3962                     return FALSE;
3963           }
3964 
3965           /* Loop through scan results and append each result's object path */
3966           for (; sta; sta = sta->next) {
3967                     paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
3968                     if (!paths[i]) {
3969                               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
3970                                                        "no memory");
3971                               goto out;
3972                     }
3973                     /* Construct the object path for this BSS. */
3974                     os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
3975                                   "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
3976                                   wpa_s->dbus_new_path, MAC2STR(sta->addr));
3977           }
3978 
3979           success = wpas_dbus_simple_array_property_getter(iter,
3980                                                                        DBUS_TYPE_OBJECT_PATH,
3981                                                                        paths, num,
3982                                                                        error);
3983 
3984 out:
3985           while (i)
3986                     os_free(paths[--i]);
3987           os_free(paths);
3988           return success;
3989 }
3990 
3991 
3992 /**
3993  * wpas_dbus_getter_sta_address - Return the address of a connected station
3994  * @iter: Pointer to incoming dbus message iter
3995  * @error: Location to store error on failure
3996  * @user_data: Function specific data
3997  * Returns: TRUE on success, FALSE on failure
3998  *
3999  * Getter for "Address" property.
4000  */
wpas_dbus_getter_sta_address(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4001 dbus_bool_t wpas_dbus_getter_sta_address(
4002           const struct wpa_dbus_property_desc *property_desc,
4003           DBusMessageIter *iter, DBusError *error, void *user_data)
4004 {
4005 #ifdef CONFIG_AP
4006           struct sta_handler_args *args = user_data;
4007           struct sta_info *sta;
4008 
4009           sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4010           if (!sta)
4011                     return FALSE;
4012 
4013           return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4014                                                                   sta->addr, ETH_ALEN,
4015                                                                   error);
4016 #else /* CONFIG_AP */
4017     return FALSE;
4018 #endif /* CONFIG_AP */
4019 }
4020 
4021 
4022 /**
4023  * wpas_dbus_getter_sta_aid - Return the AID of a connected station
4024  * @iter: Pointer to incoming dbus message iter
4025  * @error: Location to store error on failure
4026  * @user_data: Function specific data
4027  * Returns: TRUE on success, FALSE on failure
4028  *
4029  * Getter for "AID" property.
4030  */
wpas_dbus_getter_sta_aid(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4031 dbus_bool_t wpas_dbus_getter_sta_aid(
4032           const struct wpa_dbus_property_desc *property_desc,
4033           DBusMessageIter *iter, DBusError *error, void *user_data)
4034 {
4035 #ifdef CONFIG_AP
4036           struct sta_handler_args *args = user_data;
4037           struct sta_info *sta;
4038 
4039           sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4040           if (!sta)
4041                     return FALSE;
4042 
4043           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4044                                                             &sta->aid,
4045                                                             error);
4046 #else /* CONFIG_AP */
4047     return FALSE;
4048 #endif /* CONFIG_AP */
4049 }
4050 
4051 
4052 /**
4053  * wpas_dbus_getter_sta_caps - Return the capabilities of a station
4054  * @iter: Pointer to incoming dbus message iter
4055  * @error: Location to store error on failure
4056  * @user_data: Function specific data
4057  * Returns: TRUE on success, FALSE on failure
4058  *
4059  * Getter for "Capabilities" property.
4060  */
wpas_dbus_getter_sta_caps(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4061 dbus_bool_t wpas_dbus_getter_sta_caps(
4062           const struct wpa_dbus_property_desc *property_desc,
4063           DBusMessageIter *iter, DBusError *error, void *user_data)
4064 {
4065 #ifdef CONFIG_AP
4066           struct sta_handler_args *args = user_data;
4067           struct sta_info *sta;
4068 
4069           sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
4070           if (!sta)
4071                     return FALSE;
4072 
4073           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4074                                                             &sta->capability,
4075                                                             error);
4076 #else /* CONFIG_AP */
4077     return FALSE;
4078 #endif /* CONFIG_AP */
4079 }
4080 
4081 
4082 /**
4083  * wpas_dbus_getter_rx_packets - Return the received packets for a station
4084  * @iter: Pointer to incoming dbus message iter
4085  * @error: Location to store error on failure
4086  * @user_data: Function specific data
4087  * Returns: TRUE on success, FALSE on failure
4088  *
4089  * Getter for "RxPackets" property.
4090  */
wpas_dbus_getter_sta_rx_packets(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4091 dbus_bool_t wpas_dbus_getter_sta_rx_packets(
4092           const struct wpa_dbus_property_desc *property_desc,
4093           DBusMessageIter *iter, DBusError *error, void *user_data)
4094 {
4095 #ifdef CONFIG_AP
4096           struct sta_handler_args *args = user_data;
4097           struct sta_info *sta;
4098           struct hostap_sta_driver_data data;
4099           struct hostapd_data *hapd;
4100 
4101           if (!args->wpa_s->ap_iface)
4102                     return FALSE;
4103 
4104           hapd = args->wpa_s->ap_iface->bss[0];
4105           sta = ap_get_sta(hapd, args->sta);
4106           if (!sta)
4107                     return FALSE;
4108 
4109           if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4110                     return FALSE;
4111 
4112           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4113                                                             &data.rx_packets,
4114                                                             error);
4115 #else /* CONFIG_AP */
4116     return FALSE;
4117 #endif /* CONFIG_AP */
4118 }
4119 
4120 
4121 /**
4122  * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station
4123  * @iter: Pointer to incoming dbus message iter
4124  * @error: Location to store error on failure
4125  * @user_data: Function specific data
4126  * Returns: TRUE on success, FALSE on failure
4127  *
4128  * Getter for "TxPackets" property.
4129  */
wpas_dbus_getter_sta_tx_packets(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4130 dbus_bool_t wpas_dbus_getter_sta_tx_packets(
4131           const struct wpa_dbus_property_desc *property_desc,
4132           DBusMessageIter *iter, DBusError *error, void *user_data)
4133 {
4134 #ifdef CONFIG_AP
4135           struct sta_handler_args *args = user_data;
4136           struct sta_info *sta;
4137           struct hostap_sta_driver_data data;
4138           struct hostapd_data *hapd;
4139 
4140           if (!args->wpa_s->ap_iface)
4141                     return FALSE;
4142 
4143           hapd = args->wpa_s->ap_iface->bss[0];
4144           sta = ap_get_sta(hapd, args->sta);
4145           if (!sta)
4146                     return FALSE;
4147 
4148           if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4149                     return FALSE;
4150 
4151           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4152                                                             &data.tx_packets,
4153                                                             error);
4154 #else /* CONFIG_AP */
4155     return FALSE;
4156 #endif /* CONFIG_AP */
4157 }
4158 
4159 
4160 /**
4161  * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station
4162  * @iter: Pointer to incoming dbus message iter
4163  * @error: Location to store error on failure
4164  * @user_data: Function specific data
4165  * Returns: TRUE on success, FALSE on failure
4166  *
4167  * Getter for "TxBytes" property.
4168  */
wpas_dbus_getter_sta_tx_bytes(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4169 dbus_bool_t wpas_dbus_getter_sta_tx_bytes(
4170           const struct wpa_dbus_property_desc *property_desc,
4171           DBusMessageIter *iter, DBusError *error, void *user_data)
4172 {
4173 #ifdef CONFIG_AP
4174           struct sta_handler_args *args = user_data;
4175           struct sta_info *sta;
4176           struct hostap_sta_driver_data data;
4177           struct hostapd_data *hapd;
4178 
4179           if (!args->wpa_s->ap_iface)
4180                     return FALSE;
4181 
4182           hapd = args->wpa_s->ap_iface->bss[0];
4183           sta = ap_get_sta(hapd, args->sta);
4184           if (!sta)
4185                     return FALSE;
4186 
4187           if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4188                     return FALSE;
4189 
4190           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4191                                                             &data.tx_bytes,
4192                                                             error);
4193 #else /* CONFIG_AP */
4194     return FALSE;
4195 #endif /* CONFIG_AP */
4196 }
4197 
4198 
4199 /**
4200  * wpas_dbus_getter_rx_bytes - Return the received bytes for a station
4201  * @iter: Pointer to incoming dbus message iter
4202  * @error: Location to store error on failure
4203  * @user_data: Function specific data
4204  * Returns: TRUE on success, FALSE on failure
4205  *
4206  * Getter for "RxBytes" property.
4207  */
wpas_dbus_getter_sta_rx_bytes(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4208 dbus_bool_t wpas_dbus_getter_sta_rx_bytes(
4209           const struct wpa_dbus_property_desc *property_desc,
4210           DBusMessageIter *iter, DBusError *error, void *user_data)
4211 {
4212 #ifdef CONFIG_AP
4213           struct sta_handler_args *args = user_data;
4214           struct sta_info *sta;
4215           struct hostap_sta_driver_data data;
4216           struct hostapd_data *hapd;
4217 
4218           if (!args->wpa_s->ap_iface)
4219                     return FALSE;
4220 
4221           hapd = args->wpa_s->ap_iface->bss[0];
4222           sta = ap_get_sta(hapd, args->sta);
4223           if (!sta)
4224                     return FALSE;
4225 
4226           if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
4227                     return FALSE;
4228 
4229           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
4230                                                             &data.rx_bytes,
4231                                                             error);
4232 #else /* CONFIG_AP */
4233     return FALSE;
4234 #endif /* CONFIG_AP */
4235 }
4236 
4237 
get_bss_helper(struct bss_handler_args * args,DBusError * error,const char * func_name)4238 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
4239                                                DBusError *error, const char *func_name)
4240 {
4241           struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
4242 
4243           if (!res) {
4244                     wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
4245                                  func_name, args->id);
4246                     dbus_set_error(error, DBUS_ERROR_FAILED,
4247                                      "%s: BSS %d not found",
4248                                      func_name, args->id);
4249           }
4250 
4251           return res;
4252 }
4253 
4254 
4255 /**
4256  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
4257  * @iter: Pointer to incoming dbus message iter
4258  * @error: Location to store error on failure
4259  * @user_data: Function specific data
4260  * Returns: TRUE on success, FALSE on failure
4261  *
4262  * Getter for "BSSID" property.
4263  */
wpas_dbus_getter_bss_bssid(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4264 dbus_bool_t wpas_dbus_getter_bss_bssid(
4265           const struct wpa_dbus_property_desc *property_desc,
4266           DBusMessageIter *iter, DBusError *error, void *user_data)
4267 {
4268           struct bss_handler_args *args = user_data;
4269           struct wpa_bss *res;
4270 
4271           res = get_bss_helper(args, error, __func__);
4272           if (!res)
4273                     return FALSE;
4274 
4275           return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4276                                                                   res->bssid, ETH_ALEN,
4277                                                                   error);
4278 }
4279 
4280 
4281 /**
4282  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
4283  * @iter: Pointer to incoming dbus message iter
4284  * @error: Location to store error on failure
4285  * @user_data: Function specific data
4286  * Returns: TRUE on success, FALSE on failure
4287  *
4288  * Getter for "SSID" property.
4289  */
wpas_dbus_getter_bss_ssid(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4290 dbus_bool_t wpas_dbus_getter_bss_ssid(
4291           const struct wpa_dbus_property_desc *property_desc,
4292           DBusMessageIter *iter, DBusError *error, void *user_data)
4293 {
4294           struct bss_handler_args *args = user_data;
4295           struct wpa_bss *res;
4296 
4297           res = get_bss_helper(args, error, __func__);
4298           if (!res)
4299                     return FALSE;
4300 
4301           return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4302                                                                   res->ssid, res->ssid_len,
4303                                                                   error);
4304 }
4305 
4306 
4307 /**
4308  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
4309  * @iter: Pointer to incoming dbus message iter
4310  * @error: Location to store error on failure
4311  * @user_data: Function specific data
4312  * Returns: TRUE on success, FALSE on failure
4313  *
4314  * Getter for "Privacy" property.
4315  */
wpas_dbus_getter_bss_privacy(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4316 dbus_bool_t wpas_dbus_getter_bss_privacy(
4317           const struct wpa_dbus_property_desc *property_desc,
4318           DBusMessageIter *iter, DBusError *error, void *user_data)
4319 {
4320           struct bss_handler_args *args = user_data;
4321           struct wpa_bss *res;
4322           dbus_bool_t privacy;
4323 
4324           res = get_bss_helper(args, error, __func__);
4325           if (!res)
4326                     return FALSE;
4327 
4328           privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
4329           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
4330                                                             &privacy, error);
4331 }
4332 
4333 
4334 /**
4335  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
4336  * @iter: Pointer to incoming dbus message iter
4337  * @error: Location to store error on failure
4338  * @user_data: Function specific data
4339  * Returns: TRUE on success, FALSE on failure
4340  *
4341  * Getter for "Mode" property.
4342  */
wpas_dbus_getter_bss_mode(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4343 dbus_bool_t wpas_dbus_getter_bss_mode(
4344           const struct wpa_dbus_property_desc *property_desc,
4345           DBusMessageIter *iter, DBusError *error, void *user_data)
4346 {
4347           struct bss_handler_args *args = user_data;
4348           struct wpa_bss *res;
4349           const char *mode;
4350           const u8 *mesh;
4351 
4352           res = get_bss_helper(args, error, __func__);
4353           if (!res)
4354                     return FALSE;
4355           if (bss_is_dmg(res)) {
4356                     switch (res->caps & IEEE80211_CAP_DMG_MASK) {
4357                     case IEEE80211_CAP_DMG_PBSS:
4358                     case IEEE80211_CAP_DMG_IBSS:
4359                               mode = "ad-hoc";
4360                               break;
4361                     case IEEE80211_CAP_DMG_AP:
4362                               mode = "infrastructure";
4363                               break;
4364                     default:
4365                               mode = "";
4366                               break;
4367                     }
4368           } else {
4369                     mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID);
4370                     if (mesh)
4371                               mode = "mesh";
4372                     else if (res->caps & IEEE80211_CAP_IBSS)
4373                               mode = "ad-hoc";
4374                     else
4375                               mode = "infrastructure";
4376           }
4377 
4378           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
4379                                                             &mode, error);
4380 }
4381 
4382 
4383 /**
4384  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
4385  * @iter: Pointer to incoming dbus message iter
4386  * @error: Location to store error on failure
4387  * @user_data: Function specific data
4388  * Returns: TRUE on success, FALSE on failure
4389  *
4390  * Getter for "Level" property.
4391  */
wpas_dbus_getter_bss_signal(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4392 dbus_bool_t wpas_dbus_getter_bss_signal(
4393           const struct wpa_dbus_property_desc *property_desc,
4394           DBusMessageIter *iter, DBusError *error, void *user_data)
4395 {
4396           struct bss_handler_args *args = user_data;
4397           struct wpa_bss *res;
4398           s16 level;
4399 
4400           res = get_bss_helper(args, error, __func__);
4401           if (!res)
4402                     return FALSE;
4403 
4404           level = (s16) res->level;
4405           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
4406                                                             &level, error);
4407 }
4408 
4409 
4410 /**
4411  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
4412  * @iter: Pointer to incoming dbus message iter
4413  * @error: Location to store error on failure
4414  * @user_data: Function specific data
4415  * Returns: TRUE on success, FALSE on failure
4416  *
4417  * Getter for "Frequency" property.
4418  */
wpas_dbus_getter_bss_frequency(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4419 dbus_bool_t wpas_dbus_getter_bss_frequency(
4420           const struct wpa_dbus_property_desc *property_desc,
4421           DBusMessageIter *iter, DBusError *error, void *user_data)
4422 {
4423           struct bss_handler_args *args = user_data;
4424           struct wpa_bss *res;
4425           u16 freq;
4426 
4427           res = get_bss_helper(args, error, __func__);
4428           if (!res)
4429                     return FALSE;
4430 
4431           freq = (u16) res->freq;
4432           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
4433                                                             &freq, error);
4434 }
4435 
4436 
cmp_u8s_desc(const void * a,const void * b)4437 static int cmp_u8s_desc(const void *a, const void *b)
4438 {
4439           return (*(u8 *) b - *(u8 *) a);
4440 }
4441 
4442 
4443 /**
4444  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
4445  * @iter: Pointer to incoming dbus message iter
4446  * @error: Location to store error on failure
4447  * @user_data: Function specific data
4448  * Returns: TRUE on success, FALSE on failure
4449  *
4450  * Getter for "Rates" property.
4451  */
wpas_dbus_getter_bss_rates(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4452 dbus_bool_t wpas_dbus_getter_bss_rates(
4453           const struct wpa_dbus_property_desc *property_desc,
4454           DBusMessageIter *iter, DBusError *error, void *user_data)
4455 {
4456           struct bss_handler_args *args = user_data;
4457           struct wpa_bss *res;
4458           u8 *ie_rates = NULL;
4459           u32 *real_rates;
4460           int rates_num, i;
4461           dbus_bool_t success = FALSE;
4462 
4463           res = get_bss_helper(args, error, __func__);
4464           if (!res)
4465                     return FALSE;
4466 
4467           rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
4468           if (rates_num < 0)
4469                     return FALSE;
4470 
4471           qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
4472 
4473           real_rates = os_malloc(sizeof(u32) * rates_num);
4474           if (!real_rates) {
4475                     os_free(ie_rates);
4476                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4477                     return FALSE;
4478           }
4479 
4480           for (i = 0; i < rates_num; i++)
4481                     real_rates[i] = ie_rates[i] * 500000;
4482 
4483           success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
4484                                                                        real_rates, rates_num,
4485                                                                        error);
4486 
4487           os_free(ie_rates);
4488           os_free(real_rates);
4489           return success;
4490 }
4491 
4492 
wpas_dbus_get_bss_security_prop(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,struct wpa_ie_data * ie_data,DBusError * error)4493 static dbus_bool_t wpas_dbus_get_bss_security_prop(
4494           const struct wpa_dbus_property_desc *property_desc,
4495           DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error)
4496 {
4497           DBusMessageIter iter_dict, variant_iter;
4498           const char *group;
4499           const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
4500           const char *key_mgmt[15]; /* max 15 key managements may be supported */
4501           int n;
4502 
4503           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
4504                                                         "a{sv}", &variant_iter))
4505                     goto nomem;
4506 
4507           if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
4508                     goto nomem;
4509 
4510           /*
4511            * KeyMgmt
4512            *
4513            * When adding a new entry here, please take care to extend key_mgmt[]
4514            * and keep documentation in doc/dbus.doxygen up to date.
4515            */
4516           n = 0;
4517           if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
4518                     key_mgmt[n++] = "wpa-psk";
4519           if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK)
4520                     key_mgmt[n++] = "wpa-ft-psk";
4521           if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
4522                     key_mgmt[n++] = "wpa-psk-sha256";
4523           if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X)
4524                     key_mgmt[n++] = "wpa-eap";
4525           if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
4526                     key_mgmt[n++] = "wpa-ft-eap";
4527           if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
4528                     key_mgmt[n++] = "wpa-eap-sha256";
4529 #ifdef CONFIG_SUITEB
4530           if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
4531                     key_mgmt[n++] = "wpa-eap-suite-b";
4532 #endif /* CONFIG_SUITEB */
4533 #ifdef CONFIG_SUITEB192
4534           if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
4535                     key_mgmt[n++] = "wpa-eap-suite-b-192";
4536 #endif /* CONFIG_SUITEB192 */
4537 #ifdef CONFIG_FILS
4538           if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
4539                     key_mgmt[n++] = "wpa-fils-sha256";
4540           if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
4541                     key_mgmt[n++] = "wpa-fils-sha384";
4542           if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
4543                     key_mgmt[n++] = "wpa-ft-fils-sha256";
4544           if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
4545                     key_mgmt[n++] = "wpa-ft-fils-sha384";
4546 #endif /* CONFIG_FILS */
4547 #ifdef CONFIG_SAE
4548           if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
4549                     key_mgmt[n++] = "sae";
4550           if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
4551                     key_mgmt[n++] = "ft-sae";
4552 #endif /* CONFIG_SAE */
4553           if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
4554                     key_mgmt[n++] = "wpa-none";
4555 
4556           if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt",
4557                                                          key_mgmt, n))
4558                     goto nomem;
4559 
4560           /* Group */
4561           switch (ie_data->group_cipher) {
4562           case WPA_CIPHER_WEP40:
4563                     group = "wep40";
4564                     break;
4565           case WPA_CIPHER_TKIP:
4566                     group = "tkip";
4567                     break;
4568           case WPA_CIPHER_CCMP:
4569                     group = "ccmp";
4570                     break;
4571           case WPA_CIPHER_GCMP:
4572                     group = "gcmp";
4573                     break;
4574           case WPA_CIPHER_WEP104:
4575                     group = "wep104";
4576                     break;
4577           case WPA_CIPHER_CCMP_256:
4578                     group = "ccmp-256";
4579                     break;
4580           case WPA_CIPHER_GCMP_256:
4581                     group = "gcmp-256";
4582                     break;
4583           default:
4584                     group = "";
4585                     break;
4586           }
4587 
4588           if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group))
4589                     goto nomem;
4590 
4591           /* Pairwise */
4592           n = 0;
4593           if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP)
4594                     pairwise[n++] = "tkip";
4595           if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
4596                     pairwise[n++] = "ccmp";
4597           if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
4598                     pairwise[n++] = "gcmp";
4599           if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256)
4600                     pairwise[n++] = "ccmp-256";
4601           if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256)
4602                     pairwise[n++] = "gcmp-256";
4603 
4604           if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
4605                                                          pairwise, n))
4606                     goto nomem;
4607 
4608           /* Management group (RSN only) */
4609           if (ie_data->proto == WPA_PROTO_RSN) {
4610                     switch (ie_data->mgmt_group_cipher) {
4611 #ifdef CONFIG_IEEE80211W
4612                     case WPA_CIPHER_AES_128_CMAC:
4613                               group = "aes128cmac";
4614                               break;
4615 #endif /* CONFIG_IEEE80211W */
4616                     default:
4617                               group = "";
4618                               break;
4619                     }
4620 
4621                     if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup",
4622                                                              group))
4623                               goto nomem;
4624           }
4625 
4626           if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
4627               !dbus_message_iter_close_container(iter, &variant_iter))
4628                     goto nomem;
4629 
4630           return TRUE;
4631 
4632 nomem:
4633           dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4634           return FALSE;
4635 }
4636 
4637 
4638 /**
4639  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
4640  * @iter: Pointer to incoming dbus message iter
4641  * @error: Location to store error on failure
4642  * @user_data: Function specific data
4643  * Returns: TRUE on success, FALSE on failure
4644  *
4645  * Getter for "WPA" property.
4646  */
wpas_dbus_getter_bss_wpa(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4647 dbus_bool_t wpas_dbus_getter_bss_wpa(
4648           const struct wpa_dbus_property_desc *property_desc,
4649           DBusMessageIter *iter, DBusError *error, void *user_data)
4650 {
4651           struct bss_handler_args *args = user_data;
4652           struct wpa_bss *res;
4653           struct wpa_ie_data wpa_data;
4654           const u8 *ie;
4655 
4656           res = get_bss_helper(args, error, __func__);
4657           if (!res)
4658                     return FALSE;
4659 
4660           os_memset(&wpa_data, 0, sizeof(wpa_data));
4661           ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
4662           if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
4663                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
4664                                              "failed to parse WPA IE");
4665                     return FALSE;
4666           }
4667 
4668           return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
4669 }
4670 
4671 
4672 /**
4673  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
4674  * @iter: Pointer to incoming dbus message iter
4675  * @error: Location to store error on failure
4676  * @user_data: Function specific data
4677  * Returns: TRUE on success, FALSE on failure
4678  *
4679  * Getter for "RSN" property.
4680  */
wpas_dbus_getter_bss_rsn(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4681 dbus_bool_t wpas_dbus_getter_bss_rsn(
4682           const struct wpa_dbus_property_desc *property_desc,
4683           DBusMessageIter *iter, DBusError *error, void *user_data)
4684 {
4685           struct bss_handler_args *args = user_data;
4686           struct wpa_bss *res;
4687           struct wpa_ie_data wpa_data;
4688           const u8 *ie;
4689 
4690           res = get_bss_helper(args, error, __func__);
4691           if (!res)
4692                     return FALSE;
4693 
4694           os_memset(&wpa_data, 0, sizeof(wpa_data));
4695           ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
4696           if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
4697                     dbus_set_error_const(error, DBUS_ERROR_FAILED,
4698                                              "failed to parse RSN IE");
4699                     return FALSE;
4700           }
4701 
4702           return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error);
4703 }
4704 
4705 
4706 /**
4707  * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
4708  * @iter: Pointer to incoming dbus message iter
4709  * @error: Location to store error on failure
4710  * @user_data: Function specific data
4711  * Returns: TRUE on success, FALSE on failure
4712  *
4713  * Getter for "WPS" property.
4714  */
wpas_dbus_getter_bss_wps(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4715 dbus_bool_t wpas_dbus_getter_bss_wps(
4716           const struct wpa_dbus_property_desc *property_desc,
4717           DBusMessageIter *iter, DBusError *error, void *user_data)
4718 {
4719           struct bss_handler_args *args = user_data;
4720           struct wpa_bss *res;
4721 #ifdef CONFIG_WPS
4722           struct wpabuf *wps_ie;
4723 #endif /* CONFIG_WPS */
4724           DBusMessageIter iter_dict, variant_iter;
4725           int wps_support = 0;
4726           const char *type = "";
4727 
4728           res = get_bss_helper(args, error, __func__);
4729           if (!res)
4730                     return FALSE;
4731 
4732           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
4733                                                         "a{sv}", &variant_iter) ||
4734               !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
4735                     goto nomem;
4736 
4737 #ifdef CONFIG_WPS
4738           wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
4739           if (wps_ie) {
4740                     wps_support = 1;
4741                     if (wps_is_selected_pbc_registrar(wps_ie))
4742                               type = "pbc";
4743                     else if (wps_is_selected_pin_registrar(wps_ie))
4744                               type = "pin";
4745 
4746                     wpabuf_free(wps_ie);
4747           }
4748 #endif /* CONFIG_WPS */
4749 
4750           if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) ||
4751               !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
4752               !dbus_message_iter_close_container(iter, &variant_iter))
4753                     goto nomem;
4754 
4755           return TRUE;
4756 
4757 nomem:
4758           dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4759           return FALSE;
4760 }
4761 
4762 
4763 /**
4764  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
4765  * @iter: Pointer to incoming dbus message iter
4766  * @error: Location to store error on failure
4767  * @user_data: Function specific data
4768  * Returns: TRUE on success, FALSE on failure
4769  *
4770  * Getter for "IEs" property.
4771  */
wpas_dbus_getter_bss_ies(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4772 dbus_bool_t wpas_dbus_getter_bss_ies(
4773           const struct wpa_dbus_property_desc *property_desc,
4774           DBusMessageIter *iter, DBusError *error, void *user_data)
4775 {
4776           struct bss_handler_args *args = user_data;
4777           struct wpa_bss *res;
4778 
4779           res = get_bss_helper(args, error, __func__);
4780           if (!res)
4781                     return FALSE;
4782 
4783           return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
4784                                                                   res + 1, res->ie_len,
4785                                                                   error);
4786 }
4787 
4788 
4789 /**
4790  * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen
4791  * @iter: Pointer to incoming dbus message iter
4792  * @error: Location to store error on failure
4793  * @user_data: Function specific data
4794  * Returns: TRUE on success, FALSE on failure
4795  *
4796  * Getter for BSS age
4797  */
wpas_dbus_getter_bss_age(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4798 dbus_bool_t wpas_dbus_getter_bss_age(
4799           const struct wpa_dbus_property_desc *property_desc,
4800           DBusMessageIter *iter, DBusError *error, void *user_data)
4801 {
4802           struct bss_handler_args *args = user_data;
4803           struct wpa_bss *res;
4804           struct os_reltime now, diff = { 0, 0 };
4805           u32 age;
4806 
4807           res = get_bss_helper(args, error, __func__);
4808           if (!res)
4809                     return FALSE;
4810 
4811           os_get_reltime(&now);
4812           os_reltime_sub(&now, &res->last_update, &diff);
4813           age = diff.sec > 0 ? diff.sec : 0;
4814           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age,
4815                                                             error);
4816 }
4817 
4818 
4819 /**
4820  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
4821  * @iter: Pointer to incoming dbus message iter
4822  * @error: Location to store error on failure
4823  * @user_data: Function specific data
4824  * Returns: TRUE on success, FALSE on failure
4825  *
4826  * Getter for "enabled" property of a configured network.
4827  */
wpas_dbus_getter_enabled(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4828 dbus_bool_t wpas_dbus_getter_enabled(
4829           const struct wpa_dbus_property_desc *property_desc,
4830           DBusMessageIter *iter, DBusError *error, void *user_data)
4831 {
4832           struct network_handler_args *net = user_data;
4833           dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
4834 
4835           return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
4836                                                             &enabled, error);
4837 }
4838 
4839 
4840 /**
4841  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
4842  * @iter: Pointer to incoming dbus message iter
4843  * @error: Location to store error on failure
4844  * @user_data: Function specific data
4845  * Returns: TRUE on success, FALSE on failure
4846  *
4847  * Setter for "Enabled" property of a configured network.
4848  */
wpas_dbus_setter_enabled(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4849 dbus_bool_t wpas_dbus_setter_enabled(
4850           const struct wpa_dbus_property_desc *property_desc,
4851           DBusMessageIter *iter, DBusError *error, void *user_data)
4852 {
4853           struct network_handler_args *net = user_data;
4854           struct wpa_supplicant *wpa_s;
4855           struct wpa_ssid *ssid;
4856           dbus_bool_t enable;
4857 
4858           if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
4859                                                         &enable))
4860                     return FALSE;
4861 
4862           wpa_s = net->wpa_s;
4863           ssid = net->ssid;
4864 
4865           if (enable)
4866                     wpa_supplicant_enable_network(wpa_s, ssid);
4867           else
4868                     wpa_supplicant_disable_network(wpa_s, ssid);
4869 
4870           return TRUE;
4871 }
4872 
4873 
4874 /**
4875  * wpas_dbus_getter_network_properties - Get options for a configured network
4876  * @iter: Pointer to incoming dbus message iter
4877  * @error: Location to store error on failure
4878  * @user_data: Function specific data
4879  * Returns: TRUE on success, FALSE on failure
4880  *
4881  * Getter for "Properties" property of a configured network.
4882  */
wpas_dbus_getter_network_properties(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4883 dbus_bool_t wpas_dbus_getter_network_properties(
4884           const struct wpa_dbus_property_desc *property_desc,
4885           DBusMessageIter *iter, DBusError *error, void *user_data)
4886 {
4887           struct network_handler_args *net = user_data;
4888           DBusMessageIter     variant_iter, dict_iter;
4889           char **iterator;
4890           char **props = wpa_config_get_all(net->ssid, 1);
4891           dbus_bool_t success = FALSE;
4892 
4893           if (!props) {
4894                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4895                     return FALSE;
4896           }
4897 
4898           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
4899                                                         &variant_iter) ||
4900               !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
4901                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4902                     goto out;
4903           }
4904 
4905           iterator = props;
4906           while (*iterator) {
4907                     if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
4908                                                              *(iterator + 1))) {
4909                               dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
4910                                                        "no memory");
4911                               goto out;
4912                     }
4913                     iterator += 2;
4914           }
4915 
4916 
4917           if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
4918               !dbus_message_iter_close_container(iter, &variant_iter)) {
4919                     dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
4920                     goto out;
4921           }
4922 
4923           success = TRUE;
4924 
4925 out:
4926           iterator = props;
4927           while (*iterator) {
4928                     os_free(*iterator);
4929                     iterator++;
4930           }
4931           os_free(props);
4932           return success;
4933 }
4934 
4935 
4936 /**
4937  * wpas_dbus_setter_network_properties - Set options for a configured network
4938  * @iter: Pointer to incoming dbus message iter
4939  * @error: Location to store error on failure
4940  * @user_data: Function specific data
4941  * Returns: TRUE on success, FALSE on failure
4942  *
4943  * Setter for "Properties" property of a configured network.
4944  */
wpas_dbus_setter_network_properties(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)4945 dbus_bool_t wpas_dbus_setter_network_properties(
4946           const struct wpa_dbus_property_desc *property_desc,
4947           DBusMessageIter *iter, DBusError *error, void *user_data)
4948 {
4949           struct network_handler_args *net = user_data;
4950           struct wpa_ssid *ssid = net->ssid;
4951           DBusMessageIter     variant_iter;
4952 
4953           dbus_message_iter_recurse(iter, &variant_iter);
4954           return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
4955 }
4956 
4957 
4958 #ifdef CONFIG_AP
4959 
wpas_dbus_handler_subscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)4960 DBusMessage * wpas_dbus_handler_subscribe_preq(
4961           DBusMessage *message, struct wpa_supplicant *wpa_s)
4962 {
4963           struct wpas_dbus_priv *priv = wpa_s->global->dbus;
4964           char *name;
4965 
4966           if (wpa_s->preq_notify_peer != NULL) {
4967                     if (os_strcmp(dbus_message_get_sender(message),
4968                                     wpa_s->preq_notify_peer) == 0)
4969                               return NULL;
4970 
4971                     return dbus_message_new_error(message,
4972                               WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE,
4973                               "Another application is already subscribed");
4974           }
4975 
4976           name = os_strdup(dbus_message_get_sender(message));
4977           if (!name)
4978                     return wpas_dbus_error_no_memory(message);
4979 
4980           wpa_s->preq_notify_peer = name;
4981 
4982           /* Subscribe to clean up if application closes socket */
4983           wpas_dbus_subscribe_noc(priv);
4984 
4985           /*
4986            * Double-check it's still alive to make sure that we didn't
4987            * miss the NameOwnerChanged signal, e.g. while strdup'ing.
4988            */
4989           if (!dbus_bus_name_has_owner(priv->con, name, NULL)) {
4990                     /*
4991                      * Application no longer exists, clean up.
4992                      * The return value is irrelevant now.
4993                      *
4994                      * Need to check if the NameOwnerChanged handling
4995                      * already cleaned up because we have processed
4996                      * DBus messages while checking if the name still
4997                      * has an owner.
4998                      */
4999                     if (!wpa_s->preq_notify_peer)
5000                               return NULL;
5001                     os_free(wpa_s->preq_notify_peer);
5002                     wpa_s->preq_notify_peer = NULL;
5003                     wpas_dbus_unsubscribe_noc(priv);
5004           }
5005 
5006           return NULL;
5007 }
5008 
5009 
wpas_dbus_handler_unsubscribe_preq(DBusMessage * message,struct wpa_supplicant * wpa_s)5010 DBusMessage * wpas_dbus_handler_unsubscribe_preq(
5011           DBusMessage *message, struct wpa_supplicant *wpa_s)
5012 {
5013           struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5014 
5015           if (!wpa_s->preq_notify_peer)
5016                     return dbus_message_new_error(message,
5017                               WPAS_DBUS_ERROR_NO_SUBSCRIPTION,
5018                               "Not subscribed");
5019 
5020           if (os_strcmp(wpa_s->preq_notify_peer,
5021                           dbus_message_get_sender(message)))
5022                     return dbus_message_new_error(message,
5023                               WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM,
5024                               "Can't unsubscribe others");
5025 
5026           os_free(wpa_s->preq_notify_peer);
5027           wpa_s->preq_notify_peer = NULL;
5028           wpas_dbus_unsubscribe_noc(priv);
5029           return NULL;
5030 }
5031 
5032 
wpas_dbus_signal_preq(struct wpa_supplicant * wpa_s,const u8 * addr,const u8 * dst,const u8 * bssid,const u8 * ie,size_t ie_len,u32 ssi_signal)5033 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
5034                                  const u8 *addr, const u8 *dst, const u8 *bssid,
5035                                  const u8 *ie, size_t ie_len, u32 ssi_signal)
5036 {
5037           DBusMessage *msg;
5038           DBusMessageIter iter, dict_iter;
5039           struct wpas_dbus_priv *priv = wpa_s->global->dbus;
5040 
5041           /* Do nothing if the control interface is not turned on */
5042           if (priv == NULL || !wpa_s->dbus_new_path)
5043                     return;
5044 
5045           if (wpa_s->preq_notify_peer == NULL)
5046                     return;
5047 
5048           msg = dbus_message_new_signal(wpa_s->dbus_new_path,
5049                                               WPAS_DBUS_NEW_IFACE_INTERFACE,
5050                                               "ProbeRequest");
5051           if (msg == NULL)
5052                     return;
5053 
5054           dbus_message_set_destination(msg, wpa_s->preq_notify_peer);
5055 
5056           dbus_message_iter_init_append(msg, &iter);
5057 
5058           if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
5059               (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
5060                                                                   (const char *) addr,
5061                                                                   ETH_ALEN)) ||
5062               (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
5063                                                                  (const char *) dst,
5064                                                                  ETH_ALEN)) ||
5065               (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
5066                                                                    (const char *) bssid,
5067                                                                    ETH_ALEN)) ||
5068               (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
5069                                                                             (const char *) ie,
5070                                                                             ie_len)) ||
5071               (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
5072                                                                    ssi_signal)) ||
5073               !wpa_dbus_dict_close_write(&iter, &dict_iter))
5074                     goto fail;
5075 
5076           dbus_connection_send(priv->con, msg, NULL);
5077           goto out;
5078 fail:
5079           wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
5080 out:
5081           dbus_message_unref(msg);
5082 }
5083 
5084 #endif /* CONFIG_AP */
5085 
5086 
wpas_dbus_handler_vendor_elem_add(DBusMessage * message,struct wpa_supplicant * wpa_s)5087 DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
5088                                                             struct wpa_supplicant *wpa_s)
5089 {
5090           u8 *ielems;
5091           int len;
5092           struct ieee802_11_elems elems;
5093           dbus_int32_t frame_id;
5094           DBusMessageIter     iter, array;
5095 
5096           dbus_message_iter_init(message, &iter);
5097           dbus_message_iter_get_basic(&iter, &frame_id);
5098           if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5099                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5100                                                         "Invalid ID");
5101           }
5102 
5103           dbus_message_iter_next(&iter);
5104           dbus_message_iter_recurse(&iter, &array);
5105           dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5106           if (!ielems || len == 0) {
5107                     return dbus_message_new_error(
5108                               message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
5109           }
5110 
5111           if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
5112                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5113                                                         "Parse error");
5114           }
5115 
5116           wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5117           if (!wpa_s->vendor_elem[frame_id]) {
5118                     wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
5119                     wpas_vendor_elem_update(wpa_s);
5120                     return NULL;
5121           }
5122 
5123           if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
5124                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5125                                                         "Resize error");
5126           }
5127 
5128           wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
5129           wpas_vendor_elem_update(wpa_s);
5130           return NULL;
5131 }
5132 
5133 
wpas_dbus_handler_vendor_elem_get(DBusMessage * message,struct wpa_supplicant * wpa_s)5134 DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
5135                                                             struct wpa_supplicant *wpa_s)
5136 {
5137           DBusMessage *reply;
5138           DBusMessageIter     iter, array_iter;
5139           dbus_int32_t frame_id;
5140           const u8 *elem;
5141           size_t elem_len;
5142 
5143           dbus_message_iter_init(message, &iter);
5144           dbus_message_iter_get_basic(&iter, &frame_id);
5145 
5146           if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5147                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5148                                                         "Invalid ID");
5149           }
5150 
5151           wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5152           if (!wpa_s->vendor_elem[frame_id]) {
5153                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5154                                                         "ID value does not exist");
5155           }
5156 
5157           reply = dbus_message_new_method_return(message);
5158           if (!reply)
5159                     return wpas_dbus_error_no_memory(message);
5160 
5161           dbus_message_iter_init_append(reply, &iter);
5162 
5163           elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
5164           elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
5165 
5166           if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
5167                                                         DBUS_TYPE_BYTE_AS_STRING,
5168                                                         &array_iter) ||
5169               !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
5170                                                               &elem, elem_len) ||
5171               !dbus_message_iter_close_container(&iter, &array_iter)) {
5172                     dbus_message_unref(reply);
5173                     reply = wpas_dbus_error_no_memory(message);
5174           }
5175 
5176           return reply;
5177 }
5178 
5179 
wpas_dbus_handler_vendor_elem_remove(DBusMessage * message,struct wpa_supplicant * wpa_s)5180 DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
5181                                                                struct wpa_supplicant *wpa_s)
5182 {
5183           u8 *ielems;
5184           int len;
5185           struct ieee802_11_elems elems;
5186           DBusMessageIter     iter, array;
5187           dbus_int32_t frame_id;
5188 
5189           dbus_message_iter_init(message, &iter);
5190           dbus_message_iter_get_basic(&iter, &frame_id);
5191           if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
5192                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5193                                                         "Invalid ID");
5194           }
5195 
5196           dbus_message_iter_next(&iter);
5197           dbus_message_iter_recurse(&iter, &array);
5198           dbus_message_iter_get_fixed_array(&array, &ielems, &len);
5199           if (!ielems || len == 0) {
5200                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5201                                                         "Invalid value");
5202           }
5203 
5204           wpa_s = wpas_vendor_elem(wpa_s, frame_id);
5205 
5206           if (len == 1 && *ielems == '*') {
5207                     wpabuf_free(wpa_s->vendor_elem[frame_id]);
5208                     wpa_s->vendor_elem[frame_id] = NULL;
5209                     wpas_vendor_elem_update(wpa_s);
5210                     return NULL;
5211           }
5212 
5213           if (!wpa_s->vendor_elem[frame_id]) {
5214                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5215                                                         "ID value does not exist");
5216           }
5217 
5218           if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
5219                     return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5220                                                         "Parse error");
5221           }
5222 
5223           if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
5224                     return NULL;
5225 
5226           return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
5227                                               "Not found");
5228 }
5229 
5230 
5231 #ifdef CONFIG_MESH
5232 
5233 /**
5234  * wpas_dbus_getter_mesh_peers - Get connected mesh peers
5235  * @iter: Pointer to incoming dbus message iter
5236  * @error: Location to store error on failure
5237  * @user_data: Function specific data
5238  * Returns: TRUE on success, FALSE on failure
5239  *
5240  * Getter for "MeshPeers" property.
5241  */
wpas_dbus_getter_mesh_peers(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5242 dbus_bool_t wpas_dbus_getter_mesh_peers(
5243           const struct wpa_dbus_property_desc *property_desc,
5244           DBusMessageIter *iter, DBusError *error, void *user_data)
5245 {
5246           struct wpa_supplicant *wpa_s = user_data;
5247           struct hostapd_data *hapd;
5248           struct sta_info *sta;
5249           DBusMessageIter variant_iter, array_iter;
5250           int i;
5251           DBusMessageIter inner_array_iter;
5252 
5253           if (!wpa_s->ifmsh)
5254                     return FALSE;
5255           hapd = wpa_s->ifmsh->bss[0];
5256 
5257           if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
5258                                                         DBUS_TYPE_ARRAY_AS_STRING
5259                                                         DBUS_TYPE_ARRAY_AS_STRING
5260                                                         DBUS_TYPE_BYTE_AS_STRING,
5261                                                         &variant_iter) ||
5262               !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
5263                                                         DBUS_TYPE_ARRAY_AS_STRING
5264                                                         DBUS_TYPE_BYTE_AS_STRING,
5265                                                         &array_iter))
5266                     return FALSE;
5267 
5268           for (sta = hapd->sta_list; sta; sta = sta->next) {
5269                     if (!dbus_message_iter_open_container(
5270                                   &array_iter, DBUS_TYPE_ARRAY,
5271                                   DBUS_TYPE_BYTE_AS_STRING,
5272                                   &inner_array_iter))
5273                               return FALSE;
5274 
5275                     for (i = 0; i < ETH_ALEN; i++) {
5276                               if (!dbus_message_iter_append_basic(&inner_array_iter,
5277                                                                           DBUS_TYPE_BYTE,
5278                                                                           &(sta->addr[i])))
5279                                         return FALSE;
5280                     }
5281 
5282                     if (!dbus_message_iter_close_container(
5283                                   &array_iter, &inner_array_iter))
5284                               return FALSE;
5285           }
5286 
5287           if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
5288               !dbus_message_iter_close_container(iter, &variant_iter))
5289                     return FALSE;
5290 
5291           return TRUE;
5292 }
5293 
5294 
5295 /**
5296  * wpas_dbus_getter_mesh_group - Get mesh group
5297  * @iter: Pointer to incoming dbus message iter
5298  * @error: Location to store error on failure
5299  * @user_data: Function specific data
5300  * Returns: TRUE on success, FALSE on failure
5301  *
5302  * Getter for "MeshGroup" property.
5303  */
wpas_dbus_getter_mesh_group(const struct wpa_dbus_property_desc * property_desc,DBusMessageIter * iter,DBusError * error,void * user_data)5304 dbus_bool_t wpas_dbus_getter_mesh_group(
5305           const struct wpa_dbus_property_desc *property_desc,
5306           DBusMessageIter *iter, DBusError *error, void *user_data)
5307 {
5308           struct wpa_supplicant *wpa_s = user_data;
5309           struct wpa_ssid *ssid = wpa_s->current_ssid;
5310 
5311           if (!wpa_s->ifmsh || !ssid)
5312                     return FALSE;
5313 
5314           if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
5315                                                                 (char *) ssid->ssid,
5316                                                                 ssid->ssid_len, error)) {
5317                     dbus_set_error(error, DBUS_ERROR_FAILED,
5318                                      "%s: error constructing reply", __func__);
5319                     return FALSE;
5320           }
5321 
5322           return TRUE;
5323 }
5324 
5325 #endif /* CONFIG_MESH */
5326