2
* WPA Supplicant / dbus-based control interface
3
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
9
* Alternatively, this software may be distributed under the terms of BSD
12
* See README and COPYING for more details.
19
#include "wpa_supplicant_i.h"
20
#include "ctrl_iface_dbus.h"
21
#include "ctrl_iface_dbus_handlers.h"
22
#include "eap_peer/eap_methods.h"
23
#include "dbus_dict_helpers.h"
24
#include "ieee802_11_defs.h"
28
* wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
29
* @message: Pointer to incoming dbus message this error refers to
30
* Returns: a dbus error message
32
* Convenience function to create and return an invalid options error
34
static DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
39
reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
40
"Did not receive correct message "
43
dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
51
* wpas_dbus_new_success_reply - Return a new success reply message
52
* @message: Pointer to incoming dbus message this reply refers to
53
* Returns: a dbus message containing a single UINT32 that indicates
54
* success (ie, a value of 1)
56
* Convenience function to create and return a success reply message
58
static DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
61
unsigned int success = 1;
63
reply = dbus_message_new_method_return(message);
64
dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
70
static void wpas_dbus_free_wpa_interface(struct wpa_interface *iface)
72
free((char *) iface->driver);
73
free((char *) iface->driver_param);
74
free((char *) iface->confname);
75
free((char *) iface->bridge_ifname);
80
* wpas_dbus_global_add_interface - Request registration of a network interface
81
* @message: Pointer to incoming dbus message
82
* @global: %wpa_supplicant global data structure
83
* Returns: The object path of the new interface object,
84
* or a dbus error message with more information
86
* Handler function for "addInterface" method call. Handles requests
87
* by dbus clients to register a network interface that wpa_supplicant
90
DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
91
struct wpa_global *global)
93
struct wpa_interface iface;
95
DBusMessage *reply = NULL;
98
memset(&iface, 0, sizeof(iface));
100
dbus_message_iter_init(message, &iter);
102
/* First argument: interface name (DBUS_TYPE_STRING)
103
* Required; must be non-zero length
105
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
107
dbus_message_iter_get_basic(&iter, &ifname);
110
iface.ifname = ifname;
112
/* Second argument: dict of options */
113
if (dbus_message_iter_next(&iter)) {
114
DBusMessageIter iter_dict;
115
struct wpa_dbus_dict_entry entry;
117
if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
119
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
120
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
122
if (!strcmp(entry.key, "driver") &&
123
(entry.type == DBUS_TYPE_STRING)) {
124
iface.driver = strdup(entry.str_value);
125
if (iface.driver == NULL)
127
} else if (!strcmp(entry.key, "driver-params") &&
128
(entry.type == DBUS_TYPE_STRING)) {
129
iface.driver_param = strdup(entry.str_value);
130
if (iface.driver_param == NULL)
132
} else if (!strcmp(entry.key, "config-file") &&
133
(entry.type == DBUS_TYPE_STRING)) {
134
iface.confname = strdup(entry.str_value);
135
if (iface.confname == NULL)
137
} else if (!strcmp(entry.key, "bridge-ifname") &&
138
(entry.type == DBUS_TYPE_STRING)) {
139
iface.bridge_ifname = strdup(entry.str_value);
140
if (iface.bridge_ifname == NULL)
143
wpa_dbus_dict_entry_clear(&entry);
146
wpa_dbus_dict_entry_clear(&entry);
151
* Try to get the wpa_supplicant record for this iface, return
152
* an error if we already control it.
154
if (wpa_supplicant_get_iface(global, iface.ifname) != 0) {
155
reply = dbus_message_new_error(message,
156
WPAS_ERROR_EXISTS_ERROR,
157
"wpa_supplicant already "
158
"controls this interface.");
160
struct wpa_supplicant *wpa_s;
161
/* Otherwise, have wpa_supplicant attach to it. */
162
if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
163
const char *path = wpa_supplicant_get_dbus_path(wpa_s);
164
reply = dbus_message_new_method_return(message);
165
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
166
&path, DBUS_TYPE_INVALID);
168
reply = dbus_message_new_error(message,
169
WPAS_ERROR_ADD_ERROR,
171
"couldn't grab this "
175
wpas_dbus_free_wpa_interface(&iface);
179
wpas_dbus_free_wpa_interface(&iface);
180
return wpas_dbus_new_invalid_opts_error(message, NULL);
185
* wpas_dbus_global_remove_interface - Request deregistration of an interface
186
* @message: Pointer to incoming dbus message
187
* @global: wpa_supplicant global data structure
188
* Returns: a dbus message containing a UINT32 indicating success (1) or
189
* failure (0), or returns a dbus error message with more information
191
* Handler function for "removeInterface" method call. Handles requests
192
* by dbus clients to deregister a network interface that wpa_supplicant
195
DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
196
struct wpa_global *global)
198
struct wpa_supplicant *wpa_s;
200
DBusMessage *reply = NULL;
202
if (!dbus_message_get_args(message, NULL,
203
DBUS_TYPE_OBJECT_PATH, &path,
204
DBUS_TYPE_INVALID)) {
205
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
209
wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
211
reply = wpas_dbus_new_invalid_iface_error(message);
215
if (!wpa_supplicant_remove_iface(global, wpa_s)) {
216
reply = wpas_dbus_new_success_reply(message);
218
reply = dbus_message_new_error(message,
219
WPAS_ERROR_REMOVE_ERROR,
220
"wpa_supplicant couldn't "
221
"remove this interface.");
230
* wpas_dbus_global_get_interface - Get the object path for an interface name
231
* @message: Pointer to incoming dbus message
232
* @global: %wpa_supplicant global data structure
233
* Returns: The object path of the interface object,
234
* or a dbus error message with more information
236
* Handler function for "getInterface" method call. Handles requests
237
* by dbus clients for the object path of an specific network interface.
239
DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
240
struct wpa_global *global)
242
DBusMessage *reply = NULL;
245
struct wpa_supplicant *wpa_s;
247
if (!dbus_message_get_args(message, NULL,
248
DBUS_TYPE_STRING, &ifname,
249
DBUS_TYPE_INVALID)) {
250
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
254
wpa_s = wpa_supplicant_get_iface(global, ifname);
256
reply = wpas_dbus_new_invalid_iface_error(message);
260
path = wpa_supplicant_get_dbus_path(wpa_s);
262
reply = dbus_message_new_error(message,
263
WPAS_ERROR_INTERNAL_ERROR,
264
"an internal error occurred "
265
"getting the interface.");
269
reply = dbus_message_new_method_return(message);
270
dbus_message_append_args(reply,
271
DBUS_TYPE_OBJECT_PATH, &path,
280
* wpas_dbus_iface_scan - Request a wireless scan on an interface
281
* @message: Pointer to incoming dbus message
282
* @wpa_s: wpa_supplicant structure for a network interface
283
* Returns: a dbus message containing a UINT32 indicating success (1) or
286
* Handler function for "scan" method call of a network device. Requests
287
* that wpa_supplicant perform a wireless scan as soon as possible
288
* on a particular wireless interface.
290
DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
291
struct wpa_supplicant *wpa_s)
294
wpa_supplicant_req_scan(wpa_s, 0, 0);
295
return wpas_dbus_new_success_reply(message);
300
* wpas_dbus_iface_scan_results - Get the results of a recent scan request
301
* @message: Pointer to incoming dbus message
302
* @wpa_s: wpa_supplicant structure for a network interface
303
* Returns: a dbus message containing a dbus array of objects paths, or returns
304
* a dbus error message if not scan results could be found
306
* Handler function for "scanResults" method call of a network device. Returns
307
* a dbus message containing the object paths of wireless networks found.
309
DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
310
struct wpa_supplicant *wpa_s)
312
DBusMessage *reply = NULL;
313
DBusMessageIter iter;
314
DBusMessageIter sub_iter;
317
/* Ensure we've actually got scan results to return */
318
if (wpa_s->scan_res == NULL &&
319
wpa_supplicant_get_scan_results(wpa_s) < 0) {
320
reply = dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR,
321
"An error ocurred getting scan "
326
/* Create and initialize the return message */
327
reply = dbus_message_new_method_return(message);
328
dbus_message_iter_init_append(reply, &iter);
329
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
330
DBUS_TYPE_OBJECT_PATH_AS_STRING,
333
/* Loop through scan results and append each result's object path */
334
for (i = 0; i < wpa_s->scan_res->num; i++) {
335
struct wpa_scan_res *res = wpa_s->scan_res->res[i];
338
path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
340
perror("wpas_dbus_iface_scan_results[dbus]: out of "
342
wpa_printf(MSG_ERROR, "dbus control interface: not "
343
"enough memory to send scan results "
347
/* Construct the object path for this network. Note that ':'
348
* is not a valid character in dbus object paths.
350
snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
351
"%s/" WPAS_DBUS_BSSIDS_PART "/"
352
WPAS_DBUS_BSSID_FORMAT,
353
wpa_supplicant_get_dbus_path(wpa_s),
354
MAC2STR(res->bssid));
355
dbus_message_iter_append_basic(&sub_iter,
356
DBUS_TYPE_OBJECT_PATH, &path);
360
dbus_message_iter_close_container(&iter, &sub_iter);
368
* wpas_dbus_bssid_properties - Return the properties of a scanned network
369
* @message: Pointer to incoming dbus message
370
* @wpa_s: wpa_supplicant structure for a network interface
371
* @res: wpa_supplicant scan result for which to get properties
372
* Returns: a dbus message containing the properties for the requested network
374
* Handler function for "properties" method call of a scanned network.
375
* Returns a dbus message containing the the properties.
377
DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
378
struct wpa_supplicant *wpa_s,
379
struct wpa_scan_res *res)
381
DBusMessage *reply = NULL;
382
DBusMessageIter iter, iter_dict;
385
/* Dump the properties into a dbus message */
386
reply = dbus_message_new_method_return(message);
388
dbus_message_iter_init_append(reply, &iter);
389
if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
392
if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
393
(const char *) res->bssid,
397
ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
399
if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
400
(const char *) (ie + 2),
405
ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
407
if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
413
ie = wpa_scan_get_ie(res, WLAN_EID_RSN);
415
if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
422
if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
426
if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
429
if (!wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual))
431
if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise))
433
if (!wpa_dbus_dict_append_int32(&iter_dict, "level", res->level))
435
if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
436
wpa_scan_get_max_rate(res)))
439
if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
446
dbus_message_unref(reply);
447
return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
448
"an internal error occurred returning "
449
"BSSID properties.");
454
* wpas_dbus_iface_capabilities - Return interface capabilities
455
* @message: Pointer to incoming dbus message
456
* @wpa_s: wpa_supplicant structure for a network interface
457
* Returns: A dbus message containing a dict of strings
459
* Handler function for "capabilities" method call of an interface.
461
DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
462
struct wpa_supplicant *wpa_s)
464
DBusMessage *reply = NULL;
465
struct wpa_driver_capa capa;
467
DBusMessageIter iter, iter_dict;
470
dbus_bool_t strict = FALSE;
471
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
473
if (!dbus_message_get_args(message, NULL,
474
DBUS_TYPE_BOOLEAN, &strict,
478
reply = dbus_message_new_method_return(message);
480
dbus_message_iter_init_append(reply, &iter);
481
if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
485
eap_methods = eap_get_names_as_string_array(&num_items);
487
dbus_bool_t success = FALSE;
490
success = wpa_dbus_dict_append_string_array(
491
&iter_dict, "eap", (const char **) eap_methods,
494
/* free returned method array */
495
while (eap_methods[i])
496
free(eap_methods[i++]);
503
res = wpa_drv_get_capa(wpa_s, &capa);
505
/***** pairwise cipher */
508
const char *args[] = {"CCMP", "TKIP", "NONE"};
509
if (!wpa_dbus_dict_append_string_array(
510
&iter_dict, "pairwise", args,
511
sizeof(args) / sizeof(char*)))
515
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
521
if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
522
if (!wpa_dbus_dict_string_array_add_element(
523
&iter_array, "CCMP"))
527
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
528
if (!wpa_dbus_dict_string_array_add_element(
529
&iter_array, "TKIP"))
533
if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
534
if (!wpa_dbus_dict_string_array_add_element(
535
&iter_array, "NONE"))
539
if (!wpa_dbus_dict_end_string_array(&iter_dict,
546
/***** group cipher */
549
const char *args[] = {
550
"CCMP", "TKIP", "WEP104", "WEP40"
552
if (!wpa_dbus_dict_append_string_array(
553
&iter_dict, "group", args,
554
sizeof(args) / sizeof(char*)))
558
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
564
if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
565
if (!wpa_dbus_dict_string_array_add_element(
566
&iter_array, "CCMP"))
570
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
571
if (!wpa_dbus_dict_string_array_add_element(
572
&iter_array, "TKIP"))
576
if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
577
if (!wpa_dbus_dict_string_array_add_element(
578
&iter_array, "WEP104"))
582
if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
583
if (!wpa_dbus_dict_string_array_add_element(
584
&iter_array, "WEP40"))
588
if (!wpa_dbus_dict_end_string_array(&iter_dict,
595
/***** key management */
598
const char *args[] = {
599
"WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
602
if (!wpa_dbus_dict_append_string_array(
603
&iter_dict, "key_mgmt", args,
604
sizeof(args) / sizeof(char*)))
608
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
614
if (!wpa_dbus_dict_string_array_add_element(&iter_array,
618
if (!wpa_dbus_dict_string_array_add_element(&iter_array,
622
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
623
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
624
if (!wpa_dbus_dict_string_array_add_element(
625
&iter_array, "WPA-EAP"))
629
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
630
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
631
if (!wpa_dbus_dict_string_array_add_element(
632
&iter_array, "WPA-PSK"))
636
if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
637
if (!wpa_dbus_dict_string_array_add_element(
638
&iter_array, "WPA-NONE"))
642
if (!wpa_dbus_dict_end_string_array(&iter_dict,
649
/***** WPA protocol */
652
const char *args[] = { "RSN", "WPA" };
653
if (!wpa_dbus_dict_append_string_array(
654
&iter_dict, "proto", args,
655
sizeof(args) / sizeof(char*)))
659
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
665
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
666
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
667
if (!wpa_dbus_dict_string_array_add_element(
672
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
673
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
674
if (!wpa_dbus_dict_string_array_add_element(
679
if (!wpa_dbus_dict_end_string_array(&iter_dict,
689
const char *args[] = { "OPEN", "SHARED", "LEAP" };
690
if (!wpa_dbus_dict_append_string_array(
691
&iter_dict, "auth_alg", args,
692
sizeof(args) / sizeof(char*)))
696
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
702
if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
703
if (!wpa_dbus_dict_string_array_add_element(
704
&iter_array, "OPEN"))
708
if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
709
if (!wpa_dbus_dict_string_array_add_element(
710
&iter_array, "SHARED"))
714
if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
715
if (!wpa_dbus_dict_string_array_add_element(
716
&iter_array, "LEAP"))
720
if (!wpa_dbus_dict_end_string_array(&iter_dict,
727
if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
734
dbus_message_unref(reply);
735
return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
736
"an internal error occurred returning "
737
"interface capabilities.");
742
* wpas_dbus_iface_add_network - Add a new configured network
743
* @message: Pointer to incoming dbus message
744
* @wpa_s: wpa_supplicant structure for a network interface
745
* Returns: A dbus message containing the object path of the new network
747
* Handler function for "addNetwork" method call of a network interface.
749
DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
750
struct wpa_supplicant *wpa_s)
752
DBusMessage *reply = NULL;
753
struct wpa_ssid *ssid;
756
path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
758
perror("wpas_dbus_iface_scan_results[dbus]: out of "
760
wpa_printf(MSG_ERROR, "dbus control interface: not "
761
"enough memory to send scan results "
766
ssid = wpa_config_add_network(wpa_s->conf);
768
reply = dbus_message_new_error(message,
769
WPAS_ERROR_ADD_NETWORK_ERROR,
770
"wpa_supplicant could not add "
771
"a network on this interface.");
775
wpa_config_set_network_defaults(ssid);
777
/* Construct the object path for this network. */
778
snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
779
"%s/" WPAS_DBUS_NETWORKS_PART "/%d",
780
wpa_supplicant_get_dbus_path(wpa_s),
783
reply = dbus_message_new_method_return(message);
784
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
785
&path, DBUS_TYPE_INVALID);
794
* wpas_dbus_iface_remove_network - Remove a configured network
795
* @message: Pointer to incoming dbus message
796
* @wpa_s: wpa_supplicant structure for a network interface
797
* Returns: A dbus message containing a UINT32 indicating success (1) or
800
* Handler function for "removeNetwork" method call of a network interface.
802
DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
803
struct wpa_supplicant *wpa_s)
805
DBusMessage *reply = NULL;
807
char *iface = NULL, *net_id = NULL;
809
struct wpa_ssid *ssid;
811
if (!dbus_message_get_args(message, NULL,
812
DBUS_TYPE_OBJECT_PATH, &op,
813
DBUS_TYPE_INVALID)) {
814
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
818
/* Extract the network ID */
819
iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
821
reply = wpas_dbus_new_invalid_network_error(message);
824
/* Ensure the network is actually a child of this interface */
825
if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) {
826
reply = wpas_dbus_new_invalid_network_error(message);
830
id = strtoul(net_id, NULL, 10);
831
ssid = wpa_config_get_network(wpa_s->conf, id);
833
reply = wpas_dbus_new_invalid_network_error(message);
837
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
838
reply = dbus_message_new_error(message,
839
WPAS_ERROR_REMOVE_NETWORK_ERROR,
840
"error removing the specified "
841
"on this interface.");
845
if (ssid == wpa_s->current_ssid)
846
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
847
reply = wpas_dbus_new_success_reply(message);
856
static const char *dont_quote[] = {
857
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
858
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
862
static dbus_bool_t should_quote_opt(const char *key)
865
while (dont_quote[i] != NULL) {
866
if (strcmp(key, dont_quote[i]) == 0)
874
* wpas_dbus_iface_set_network - Set options for a configured network
875
* @message: Pointer to incoming dbus message
876
* @wpa_s: wpa_supplicant structure for a network interface
877
* @ssid: wpa_ssid structure for a configured network
878
* Returns: a dbus message containing a UINT32 indicating success (1) or
881
* Handler function for "set" method call of a configured network.
883
DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
884
struct wpa_supplicant *wpa_s,
885
struct wpa_ssid *ssid)
887
DBusMessage *reply = NULL;
888
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
889
DBusMessageIter iter, iter_dict;
891
dbus_message_iter_init(message, &iter);
893
if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
894
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
898
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
903
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
904
reply = wpas_dbus_new_invalid_opts_error(message,
909
/* Type conversions, since wpa_supplicant wants strings */
910
if (entry.type == DBUS_TYPE_ARRAY &&
911
entry.array_type == DBUS_TYPE_BYTE) {
912
if (entry.array_len <= 0)
915
size = entry.array_len * 2 + 1;
916
value = os_zalloc(size);
919
ret = wpa_snprintf_hex(value, size,
920
(u8 *) entry.bytearray_value,
924
} else if (entry.type == DBUS_TYPE_STRING) {
925
if (should_quote_opt(entry.key)) {
926
size = strlen(entry.str_value);
927
/* Zero-length option check */
930
size += 3; /* For quotes and terminator */
931
value = os_zalloc(size);
934
ret = snprintf(value, size, "\"%s\"",
936
if (ret < 0 || (size_t) ret != (size - 1))
939
value = strdup(entry.str_value);
943
} else if (entry.type == DBUS_TYPE_UINT32) {
944
value = os_zalloc(size);
947
ret = snprintf(value, size, "%u", entry.uint32_value);
950
} else if (entry.type == DBUS_TYPE_INT32) {
951
value = os_zalloc(size);
954
ret = snprintf(value, size, "%d", entry.int32_value);
960
if (wpa_config_set(ssid, entry.key, value, 0) < 0)
963
if ((strcmp(entry.key, "psk") == 0 &&
964
value[0] == '"' && ssid->ssid_len) ||
965
(strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
966
wpa_config_update_psk(ssid);
969
wpa_dbus_dict_entry_clear(&entry);
974
reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
975
wpa_dbus_dict_entry_clear(&entry);
980
reply = wpas_dbus_new_success_reply(message);
988
* wpas_dbus_iface_enable_network - Mark a configured network as enabled
989
* @message: Pointer to incoming dbus message
990
* @wpa_s: wpa_supplicant structure for a network interface
991
* @ssid: wpa_ssid structure for a configured network
992
* Returns: A dbus message containing a UINT32 indicating success (1) or
995
* Handler function for "enable" method call of a configured network.
997
DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
998
struct wpa_supplicant *wpa_s,
999
struct wpa_ssid *ssid)
1001
if (wpa_s->current_ssid == NULL && ssid->disabled) {
1003
* Try to reassociate since there is no current configuration
1004
* and a new network was made available.
1006
wpa_s->reassociate = 1;
1007
wpa_supplicant_req_scan(wpa_s, 0, 0);
1011
return wpas_dbus_new_success_reply(message);
1016
* wpas_dbus_iface_disable_network - Mark a configured network as disabled
1017
* @message: Pointer to incoming dbus message
1018
* @wpa_s: wpa_supplicant structure for a network interface
1019
* @ssid: wpa_ssid structure for a configured network
1020
* Returns: A dbus message containing a UINT32 indicating success (1) or
1023
* Handler function for "disable" method call of a configured network.
1025
DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
1026
struct wpa_supplicant *wpa_s,
1027
struct wpa_ssid *ssid)
1029
if (ssid == wpa_s->current_ssid)
1030
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1033
return wpas_dbus_new_success_reply(message);
1038
* wpas_dbus_iface_select_network - Attempt association with a configured network
1039
* @message: Pointer to incoming dbus message
1040
* @wpa_s: wpa_supplicant structure for a network interface
1041
* Returns: A dbus message containing a UINT32 indicating success (1) or
1044
* Handler function for "selectNetwork" method call of network interface.
1046
DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
1047
struct wpa_supplicant *wpa_s)
1049
DBusMessage *reply = NULL;
1051
struct wpa_ssid *ssid;
1052
char *iface_obj_path = NULL;
1053
char *network = NULL;
1055
if (strlen(dbus_message_get_signature(message)) == 0) {
1057
ssid = wpa_s->conf->ssid;
1062
wpa_s->reassociate = 1;
1063
wpa_supplicant_req_scan(wpa_s, 0, 0);
1065
const char *obj_path;
1068
if (!dbus_message_get_args(message, NULL,
1069
DBUS_TYPE_OBJECT_PATH, &op,
1070
DBUS_TYPE_INVALID)) {
1071
reply = wpas_dbus_new_invalid_opts_error(message,
1076
/* Extract the network number */
1077
iface_obj_path = wpas_dbus_decompose_object_path(op,
1080
if (iface_obj_path == NULL) {
1081
reply = wpas_dbus_new_invalid_iface_error(message);
1084
/* Ensure the object path really points to this interface */
1085
obj_path = wpa_supplicant_get_dbus_path(wpa_s);
1086
if (strcmp(iface_obj_path, obj_path) != 0) {
1087
reply = wpas_dbus_new_invalid_network_error(message);
1091
nid = strtoul(network, NULL, 10);
1092
if (errno == EINVAL) {
1093
reply = wpas_dbus_new_invalid_network_error(message);
1097
ssid = wpa_config_get_network(wpa_s->conf, nid);
1099
reply = wpas_dbus_new_invalid_network_error(message);
1103
/* Finally, associate with the network */
1104
if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
1105
wpa_supplicant_disassociate(
1106
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1108
/* Mark all other networks disabled and trigger reassociation
1110
ssid = wpa_s->conf->ssid;
1112
ssid->disabled = (nid != ssid->id);
1115
wpa_s->disconnected = 0;
1116
wpa_s->reassociate = 1;
1117
wpa_supplicant_req_scan(wpa_s, 0, 0);
1120
reply = wpas_dbus_new_success_reply(message);
1123
free(iface_obj_path);
1130
* wpas_dbus_iface_disconnect - Terminate the current connection
1131
* @message: Pointer to incoming dbus message
1132
* @wpa_s: wpa_supplicant structure for a network interface
1133
* Returns: A dbus message containing a UINT32 indicating success (1) or
1136
* Handler function for "disconnect" method call of network interface.
1138
DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
1139
struct wpa_supplicant *wpa_s)
1141
wpa_s->disconnected = 1;
1142
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1144
return wpas_dbus_new_success_reply(message);
1149
* wpas_dbus_iface_set_ap_scan - Control roaming mode
1150
* @message: Pointer to incoming dbus message
1151
* @wpa_s: wpa_supplicant structure for a network interface
1152
* Returns: A dbus message containing a UINT32 indicating success (1) or
1155
* Handler function for "setAPScan" method call.
1157
DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
1158
struct wpa_supplicant *wpa_s)
1160
DBusMessage *reply = NULL;
1161
dbus_uint32_t ap_scan = 1;
1163
if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
1164
DBUS_TYPE_INVALID)) {
1165
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1170
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
1173
wpa_s->conf->ap_scan = ap_scan;
1174
reply = wpas_dbus_new_success_reply(message);
1182
* wpas_dbus_iface_get_state - Get interface state
1183
* @message: Pointer to incoming dbus message
1184
* @wpa_s: wpa_supplicant structure for a network interface
1185
* Returns: A dbus message containing a STRING representing the current
1188
* Handler function for "state" method call.
1190
DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
1191
struct wpa_supplicant *wpa_s)
1193
DBusMessage *reply = NULL;
1194
const char *str_state;
1196
reply = dbus_message_new_method_return(message);
1197
if (reply != NULL) {
1198
str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
1199
dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
1208
* wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
1209
* @message: Pointer to incoming dbus message
1210
* @global: %wpa_supplicant global data structure
1211
* Returns: A dbus message containing a UINT32 indicating success (1) or
1214
* Asks wpa_supplicant to internally store a one or more binary blobs.
1216
DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
1217
struct wpa_supplicant *wpa_s)
1219
DBusMessage *reply = NULL;
1220
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1221
DBusMessageIter iter, iter_dict;
1223
dbus_message_iter_init(message, &iter);
1225
if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1226
return wpas_dbus_new_invalid_opts_error(message, NULL);
1228
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1229
struct wpa_config_blob *blob;
1231
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1232
reply = wpas_dbus_new_invalid_opts_error(message,
1237
if (entry.type != DBUS_TYPE_ARRAY ||
1238
entry.array_type != DBUS_TYPE_BYTE) {
1239
reply = wpas_dbus_new_invalid_opts_error(
1240
message, "Byte array expected.");
1244
if ((entry.array_len <= 0) || (entry.array_len > 65536) ||
1245
!strlen(entry.key)) {
1246
reply = wpas_dbus_new_invalid_opts_error(
1247
message, "Invalid array size.");
1251
blob = os_zalloc(sizeof(*blob));
1253
reply = dbus_message_new_error(
1254
message, WPAS_ERROR_ADD_ERROR,
1255
"Not enough memory to add blob.");
1258
blob->data = os_zalloc(entry.array_len);
1259
if (blob->data == NULL) {
1260
reply = dbus_message_new_error(
1261
message, WPAS_ERROR_ADD_ERROR,
1262
"Not enough memory to add blob data.");
1267
blob->name = os_strdup(entry.key);
1268
blob->len = entry.array_len;
1269
os_memcpy(blob->data, (u8 *) entry.bytearray_value,
1271
if (blob->name == NULL || blob->data == NULL) {
1272
wpa_config_free_blob(blob);
1273
reply = dbus_message_new_error(
1274
message, WPAS_ERROR_ADD_ERROR,
1275
"Error adding blob.");
1280
wpa_config_remove_blob(wpa_s->conf, blob->name);
1281
wpa_config_set_blob(wpa_s->conf, blob);
1282
wpa_dbus_dict_entry_clear(&entry);
1284
wpa_dbus_dict_entry_clear(&entry);
1286
return reply ? reply : wpas_dbus_new_success_reply(message);
1291
* wpas_dbus_iface_remove_blob - Remove named binary blobs
1292
* @message: Pointer to incoming dbus message
1293
* @global: %wpa_supplicant global data structure
1294
* Returns: A dbus message containing a UINT32 indicating success (1) or
1297
* Asks wpa_supplicant to remove one or more previously stored binary blobs.
1299
DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
1300
struct wpa_supplicant *wpa_s)
1302
DBusMessageIter iter, array;
1303
char *err_msg = NULL;
1305
dbus_message_iter_init(message, &iter);
1307
if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
1308
(dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
1309
return wpas_dbus_new_invalid_opts_error(message, NULL);
1311
dbus_message_iter_recurse(&iter, &array);
1312
while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
1315
dbus_message_iter_get_basic(&array, &name);
1317
err_msg = "Invalid blob name.";
1319
if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
1320
err_msg = "Error removing blob.";
1321
dbus_message_iter_next(&array);
1325
return dbus_message_new_error(message, WPAS_ERROR_REMOVE_ERROR,
1329
return wpas_dbus_new_success_reply(message);