5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "supplicant-dbus.h"
35 #include "supplicant.h"
37 #define DBG(fmt, arg...) do { \
38 syslog(LOG_DEBUG, "%s() " fmt, __FUNCTION__ , ## arg); \
43 #define IEEE80211_CAP_ESS 0x0001
44 #define IEEE80211_CAP_IBSS 0x0002
45 #define IEEE80211_CAP_PRIVACY 0x0010
47 static DBusConnection *connection;
49 static const struct supplicant_callbacks *callbacks_pointer;
51 static dbus_bool_t system_available = FALSE;
52 static dbus_bool_t system_ready = FALSE;
54 static dbus_int32_t debug_level = 0;
55 static dbus_bool_t debug_timestamp = FALSE;
56 static dbus_bool_t debug_showkeys = FALSE;
58 static const char *debug_strings[] = {
59 "msgdump", "debug", "info", "warning", "error", NULL
62 static unsigned int eap_methods;
69 static struct strvalmap eap_method_map[] = {
70 { "MD5", SUPPLICANT_EAP_METHOD_MD5 },
71 { "TLS", SUPPLICANT_EAP_METHOD_TLS },
72 { "MSCHAPV2", SUPPLICANT_EAP_METHOD_MSCHAPV2 },
73 { "PEAP", SUPPLICANT_EAP_METHOD_PEAP },
74 { "TTLS", SUPPLICANT_EAP_METHOD_TTLS },
75 { "GTC", SUPPLICANT_EAP_METHOD_GTC },
76 { "OTP", SUPPLICANT_EAP_METHOD_OTP },
77 { "LEAP", SUPPLICANT_EAP_METHOD_LEAP },
78 { "WSC", SUPPLICANT_EAP_METHOD_WSC },
82 static struct strvalmap keymgmt_capa_map[] = {
83 { "none", SUPPLICANT_CAPABILITY_KEYMGMT_NONE },
84 { "ieee8021x", SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X },
85 { "wpa-none", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE },
86 { "wpa-psk", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK },
87 { "wpa-eap", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP },
88 { "wps", SUPPLICANT_CAPABILITY_KEYMGMT_WPS },
92 static struct strvalmap authalg_capa_map[] = {
93 { "open", SUPPLICANT_CAPABILITY_AUTHALG_OPEN },
94 { "shared", SUPPLICANT_CAPABILITY_AUTHALG_SHARED },
95 { "leap", SUPPLICANT_CAPABILITY_AUTHALG_LEAP },
99 static struct strvalmap proto_capa_map[] = {
100 { "wpa", SUPPLICANT_CAPABILITY_PROTO_WPA },
101 { "rsn", SUPPLICANT_CAPABILITY_PROTO_RSN },
105 static struct strvalmap group_capa_map[] = {
106 { "wep40", SUPPLICANT_CAPABILITY_GROUP_WEP40 },
107 { "wep104", SUPPLICANT_CAPABILITY_GROUP_WEP104 },
108 { "tkip", SUPPLICANT_CAPABILITY_GROUP_TKIP },
109 { "ccmp", SUPPLICANT_CAPABILITY_GROUP_CCMP },
113 static struct strvalmap pairwise_capa_map[] = {
114 { "none", SUPPLICANT_CAPABILITY_PAIRWISE_NONE },
115 { "tkip", SUPPLICANT_CAPABILITY_PAIRWISE_TKIP },
116 { "ccmp", SUPPLICANT_CAPABILITY_PAIRWISE_CCMP },
120 static struct strvalmap scan_capa_map[] = {
121 { "active", SUPPLICANT_CAPABILITY_SCAN_ACTIVE },
122 { "passive", SUPPLICANT_CAPABILITY_SCAN_PASSIVE },
123 { "ssid", SUPPLICANT_CAPABILITY_SCAN_SSID },
127 static struct strvalmap mode_capa_map[] = {
128 { "infrastructure", SUPPLICANT_CAPABILITY_MODE_INFRA },
129 { "ad-hoc", SUPPLICANT_CAPABILITY_MODE_IBSS },
130 { "ap", SUPPLICANT_CAPABILITY_MODE_AP },
134 static GHashTable *interface_table;
136 struct supplicant_interface {
138 unsigned int keymgmt_capa;
139 unsigned int authalg_capa;
140 unsigned int proto_capa;
141 unsigned int group_capa;
142 unsigned int pairwise_capa;
143 unsigned int scan_capa;
144 unsigned int mode_capa;
146 enum supplicant_state state;
147 dbus_bool_t scanning;
148 supplicant_interface_scan_callback scan_callback;
154 GHashTable *network_table;
155 GHashTable *net_mapping;
156 GHashTable *bss_mapping;
159 struct supplicant_network {
160 struct supplicant_interface *interface;
164 enum supplicant_mode mode;
165 GHashTable *bss_table;
166 GHashTable *config_table;
169 struct supplicant_bss {
170 struct supplicant_interface *interface;
172 unsigned char bssid[6];
173 unsigned char ssid[32];
174 unsigned int ssid_len;
175 dbus_uint16_t frequency;
176 dbus_uint32_t maxrate;
177 enum supplicant_mode mode;
178 enum supplicant_security security;
181 dbus_bool_t ieee8021x;
184 static enum supplicant_mode string2mode(const char *mode)
187 return SUPPLICANT_MODE_UNKNOWN;
189 if (g_str_equal(mode, "infrastructure") == TRUE)
190 return SUPPLICANT_MODE_INFRA;
191 else if (g_str_equal(mode, "ad-hoc") == TRUE)
192 return SUPPLICANT_MODE_IBSS;
194 return SUPPLICANT_MODE_UNKNOWN;
197 static const char *mode2string(enum supplicant_mode mode)
200 case SUPPLICANT_MODE_UNKNOWN:
202 case SUPPLICANT_MODE_INFRA:
204 case SUPPLICANT_MODE_IBSS:
211 static const char *security2string(enum supplicant_security security)
214 case SUPPLICANT_SECURITY_UNKNOWN:
216 case SUPPLICANT_SECURITY_NONE:
218 case SUPPLICANT_SECURITY_WEP:
220 case SUPPLICANT_SECURITY_PSK:
222 case SUPPLICANT_SECURITY_IEEE8021X:
229 static enum supplicant_state string2state(const char *state)
232 return SUPPLICANT_STATE_UNKNOWN;
234 if (g_str_equal(state, "unknown") == TRUE)
235 return SUPPLICANT_STATE_UNKNOWN;
236 else if (g_str_equal(state, "disconnected") == TRUE)
237 return SUPPLICANT_STATE_DISCONNECTED;
238 else if (g_str_equal(state, "inactive") == TRUE)
239 return SUPPLICANT_STATE_INACTIVE;
240 else if (g_str_equal(state, "scanning") == TRUE)
241 return SUPPLICANT_STATE_SCANNING;
242 else if (g_str_equal(state, "authenticating") == TRUE)
243 return SUPPLICANT_STATE_AUTHENTICATING;
244 else if (g_str_equal(state, "associating") == TRUE)
245 return SUPPLICANT_STATE_ASSOCIATING;
246 else if (g_str_equal(state, "associated") == TRUE)
247 return SUPPLICANT_STATE_ASSOCIATED;
248 else if (g_str_equal(state, "group_handshake") == TRUE)
249 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
250 else if (g_str_equal(state, "4way_handshake") == TRUE)
251 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
252 else if (g_str_equal(state, "completed") == TRUE)
253 return SUPPLICANT_STATE_COMPLETED;
255 return SUPPLICANT_STATE_UNKNOWN;
258 static void callback_system_ready(void)
260 if (system_ready == TRUE)
265 if (callbacks_pointer == NULL)
268 if (callbacks_pointer->system_ready == NULL)
271 callbacks_pointer->system_ready();
274 static void callback_system_killed(void)
276 system_ready = FALSE;
278 if (callbacks_pointer == NULL)
281 if (callbacks_pointer->system_killed == NULL)
284 callbacks_pointer->system_killed();
287 static void callback_interface_added(struct supplicant_interface *interface)
289 if (callbacks_pointer == NULL)
292 if (callbacks_pointer->interface_added == NULL)
295 callbacks_pointer->interface_added(interface);
298 static void callback_interface_removed(struct supplicant_interface *interface)
300 if (callbacks_pointer == NULL)
303 if (callbacks_pointer->interface_removed == NULL)
306 callbacks_pointer->interface_removed(interface);
309 static void callback_scan_started(struct supplicant_interface *interface)
311 if (callbacks_pointer == NULL)
314 if (callbacks_pointer->scan_started == NULL)
317 callbacks_pointer->scan_started(interface);
320 static void callback_scan_finished(struct supplicant_interface *interface)
322 if (callbacks_pointer == NULL)
325 if (callbacks_pointer->scan_finished == NULL)
328 callbacks_pointer->scan_finished(interface);
331 static void callback_network_added(struct supplicant_network *network)
333 if (callbacks_pointer == NULL)
336 if (callbacks_pointer->network_added == NULL)
339 callbacks_pointer->network_added(network);
342 static void callback_network_removed(struct supplicant_network *network)
344 if (callbacks_pointer == NULL)
347 if (callbacks_pointer->network_removed == NULL)
350 callbacks_pointer->network_removed(network);
353 static void remove_interface(gpointer data)
355 struct supplicant_interface *interface = data;
357 g_hash_table_destroy(interface->bss_mapping);
358 g_hash_table_destroy(interface->net_mapping);
359 g_hash_table_destroy(interface->network_table);
361 callback_interface_removed(interface);
363 g_free(interface->path);
364 g_free(interface->ifname);
365 g_free(interface->driver);
366 g_free(interface->bridge);
370 static void remove_network(gpointer data)
372 struct supplicant_network *network = data;
374 g_hash_table_destroy(network->bss_table);
376 callback_network_removed(network);
378 g_hash_table_destroy(network->config_table);
380 g_free(network->group);
381 g_free(network->name);
385 static void remove_bss(gpointer data)
387 struct supplicant_bss *bss = data;
393 static void debug_strvalmap(const char *label, struct strvalmap *map,
398 for (i = 0; map[i].str != NULL; i++) {
399 if (val & map[i].val)
400 DBG("%s: %s", label, map[i].str);
404 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
406 struct supplicant_interface *interface = user_data;
407 const char *str = NULL;
410 dbus_message_iter_get_basic(iter, &str);
414 for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
415 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
416 interface->keymgmt_capa |= keymgmt_capa_map[i].val;
421 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
423 struct supplicant_interface *interface = user_data;
424 const char *str = NULL;
427 dbus_message_iter_get_basic(iter, &str);
431 for (i = 0; authalg_capa_map[i].str != NULL; i++)
432 if (strcmp(str, authalg_capa_map[i].str) == 0) {
433 interface->authalg_capa |= authalg_capa_map[i].val;
438 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
440 struct supplicant_interface *interface = user_data;
441 const char *str = NULL;
444 dbus_message_iter_get_basic(iter, &str);
448 for (i = 0; proto_capa_map[i].str != NULL; i++)
449 if (strcmp(str, proto_capa_map[i].str) == 0) {
450 interface->proto_capa |= proto_capa_map[i].val;
455 static void interface_capability_pairwise(DBusMessageIter *iter, void *user_data)
457 struct supplicant_interface *interface = user_data;
458 const char *str = NULL;
461 dbus_message_iter_get_basic(iter, &str);
465 for (i = 0; pairwise_capa_map[i].str != NULL; i++)
466 if (strcmp(str, pairwise_capa_map[i].str) == 0) {
467 interface->pairwise_capa |= pairwise_capa_map[i].val;
472 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
474 struct supplicant_interface *interface = user_data;
475 const char *str = NULL;
478 dbus_message_iter_get_basic(iter, &str);
482 for (i = 0; group_capa_map[i].str != NULL; i++)
483 if (strcmp(str, group_capa_map[i].str) == 0) {
484 interface->group_capa |= group_capa_map[i].val;
489 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
491 struct supplicant_interface *interface = user_data;
492 const char *str = NULL;
495 dbus_message_iter_get_basic(iter, &str);
499 for (i = 0; scan_capa_map[i].str != NULL; i++)
500 if (strcmp(str, scan_capa_map[i].str) == 0) {
501 interface->scan_capa |= scan_capa_map[i].val;
506 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
508 struct supplicant_interface *interface = user_data;
509 const char *str = NULL;
512 dbus_message_iter_get_basic(iter, &str);
516 for (i = 0; mode_capa_map[i].str != NULL; i++)
517 if (strcmp(str, mode_capa_map[i].str) == 0) {
518 interface->mode_capa |= mode_capa_map[i].val;
523 static void interface_capability(const char *key, DBusMessageIter *iter,
526 struct supplicant_interface *interface = user_data;
531 if (g_strcmp0(key, "KeyMgmt") == 0)
532 supplicant_dbus_array_foreach(iter,
533 interface_capability_keymgmt, interface);
534 else if (g_strcmp0(key, "AuthAlg") == 0)
535 supplicant_dbus_array_foreach(iter,
536 interface_capability_authalg, interface);
537 else if (g_strcmp0(key, "Protocol") == 0)
538 supplicant_dbus_array_foreach(iter,
539 interface_capability_proto, interface);
540 else if (g_strcmp0(key, "Pairwise") == 0)
541 supplicant_dbus_array_foreach(iter,
542 interface_capability_pairwise, interface);
543 else if (g_strcmp0(key, "Group") == 0)
544 supplicant_dbus_array_foreach(iter,
545 interface_capability_group, interface);
546 else if (g_strcmp0(key, "Scan") == 0)
547 supplicant_dbus_array_foreach(iter,
548 interface_capability_scan, interface);
549 else if (g_strcmp0(key, "Modes") == 0)
550 supplicant_dbus_array_foreach(iter,
551 interface_capability_mode, interface);
553 DBG("key %s type %c",
554 key, dbus_message_iter_get_arg_type(iter));
557 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
559 if (interface == NULL)
562 return interface->ifname;
565 const char *supplicant_interface_get_driver(struct supplicant_interface *interface)
567 if (interface == NULL)
570 return interface->driver;
573 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
578 return network->interface;
581 const char *supplicant_network_get_name(struct supplicant_network *network)
583 if (network == NULL || network->name == NULL)
586 return network->name;
589 const char *supplicant_network_get_identifier(struct supplicant_network *network)
591 if (network == NULL || network->group == NULL)
594 return network->group;
597 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
600 return SUPPLICANT_MODE_UNKNOWN;
602 return network->mode;
605 static void merge_network(struct supplicant_network *network)
608 const char *ssid, *mode, *key_mgmt;
609 unsigned int i, ssid_len;
612 ssid = g_hash_table_lookup(network->config_table, "ssid");
613 mode = g_hash_table_lookup(network->config_table, "mode");
614 key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
616 DBG("ssid %s mode %s", ssid, mode);
619 ssid_len = strlen(ssid);
623 str = g_string_sized_new((ssid_len * 2) + 24);
627 for (i = 0; i < ssid_len; i++)
628 g_string_append_printf(str, "%02x", ssid[i]);
630 if (g_strcmp0(mode, "0") == 0)
631 g_string_append_printf(str, "_infra");
632 else if (g_strcmp0(mode, "1") == 0)
633 g_string_append_printf(str, "_adhoc");
635 if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
636 g_string_append_printf(str, "_psk");
638 group = g_string_free(str, FALSE);
644 g_hash_table_destroy(network->config_table);
646 g_free(network->path);
650 static void network_property(const char *key, DBusMessageIter *iter,
653 struct supplicant_network *network = user_data;
655 if (network->interface == NULL)
659 merge_network(network);
663 if (g_strcmp0(key, "Enabled") == 0) {
664 dbus_bool_t enabled = FALSE;
666 dbus_message_iter_get_basic(iter, &enabled);
667 } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
668 const char *str = NULL;
670 dbus_message_iter_get_basic(iter, &str);
672 g_hash_table_replace(network->config_table,
673 g_strdup(key), g_strdup(str));
675 DBG("key %s type %c",
676 key, dbus_message_iter_get_arg_type(iter));
679 static void interface_network_added(DBusMessageIter *iter, void *user_data)
681 struct supplicant_interface *interface = user_data;
682 struct supplicant_network *network;
683 const char *path = NULL;
685 dbus_message_iter_get_basic(iter, &path);
689 if (g_strcmp0(path, "/") == 0)
692 network = g_hash_table_lookup(interface->net_mapping, path);
696 network = g_try_new0(struct supplicant_network, 1);
700 network->interface = interface;
701 network->path = g_strdup(path);
703 network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
706 dbus_message_iter_next(iter);
707 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
708 supplicant_dbus_property_foreach(iter, network_property,
710 network_property(NULL, NULL, network);
714 supplicant_dbus_property_get_all(path,
715 SUPPLICANT_INTERFACE ".Interface.Network",
716 network_property, network);
719 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
721 struct supplicant_interface *interface = user_data;
722 struct supplicant_network *network;
723 const char *path = NULL;
725 dbus_message_iter_get_basic(iter, &path);
729 network = g_hash_table_lookup(interface->net_mapping, path);
733 g_hash_table_remove(interface->net_mapping, path);
736 static char *create_name(unsigned char *ssid, int ssid_len)
741 if (ssid_len < 1 || ssid[0] == '\0')
744 name = g_try_malloc0(ssid_len + 1);
749 for (i = 0; i < ssid_len; i++) {
750 if (g_ascii_isprint(ssid[i]))
759 static char *create_group(struct supplicant_bss *bss)
763 const char *mode, *security;
765 str = g_string_sized_new((bss->ssid_len * 2) + 24);
769 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
770 for (i = 0; i < bss->ssid_len; i++)
771 g_string_append_printf(str, "%02x", bss->ssid[i]);
773 g_string_append_printf(str, "hidden");
775 mode = mode2string(bss->mode);
777 g_string_append_printf(str, "_%s", mode);
779 security = security2string(bss->security);
780 if (security != NULL)
781 g_string_append_printf(str, "_%s", security);
783 return g_string_free(str, FALSE);
786 static void add_bss_to_network(struct supplicant_bss *bss)
788 struct supplicant_interface *interface = bss->interface;
789 struct supplicant_network *network;
792 group = create_group(bss);
796 network = g_hash_table_lookup(interface->network_table, group);
797 if (network != NULL) {
802 network = g_try_new0(struct supplicant_network, 1);
803 if (network == NULL) {
808 network->group = group;
809 network->name = create_name(bss->ssid, bss->ssid_len);
810 network->mode = bss->mode;
812 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
815 network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
818 g_hash_table_replace(interface->network_table,
819 network->group, network);
821 callback_network_added(network);
824 g_hash_table_replace(interface->bss_mapping, bss->path, network);
825 g_hash_table_replace(network->bss_table, bss->path, bss);
828 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
829 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
831 static void extract_rsn(struct supplicant_bss *bss,
832 const unsigned char *buf, int len)
851 /* Pairwise cipher */
855 count = buf[0] | (buf[1] << 8);
856 if (2 + (count * 4) > len)
859 buf += 2 + (count * 4);
860 len -= 2 + (count * 4);
866 count = buf[0] | (buf[1] << 8);
867 if (2 + (count * 4) > len)
870 for (i = 0; i < count; i++) {
871 const unsigned char *ptr = buf + 2 + (i * 4);
873 if (memcmp(ptr, wifi_oui, 3) == 0) {
876 bss->ieee8021x = TRUE;
882 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
885 bss->ieee8021x = TRUE;
894 buf += 2 + (count * 4);
895 len -= 2 + (count * 4);
898 static void bss_rates(DBusMessageIter *iter, void *user_data)
900 struct supplicant_bss *bss = user_data;
901 dbus_uint32_t rate = 0;
903 dbus_message_iter_get_basic(iter, &rate);
907 if (rate > bss->maxrate)
911 static void bss_property(const char *key, DBusMessageIter *iter,
914 struct supplicant_bss *bss = user_data;
916 if (bss->interface == NULL)
920 if (bss->ieee8021x == TRUE)
921 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
922 else if (bss->psk == TRUE)
923 bss->security = SUPPLICANT_SECURITY_PSK;
924 else if (bss->privacy == TRUE)
925 bss->security = SUPPLICANT_SECURITY_WEP;
927 bss->security = SUPPLICANT_SECURITY_NONE;
929 add_bss_to_network(bss);
933 if (g_strcmp0(key, "BSSID") == 0) {
934 DBusMessageIter array;
938 dbus_message_iter_recurse(iter, &array);
939 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
942 memcpy(bss->bssid, addr, addr_len);
943 } else if (g_strcmp0(key, "SSID") == 0) {
944 DBusMessageIter array;
948 dbus_message_iter_recurse(iter, &array);
949 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
951 if (ssid_len > 0 && ssid_len < 33) {
952 memcpy(bss->ssid, ssid, ssid_len);
953 bss->ssid_len = ssid_len;
955 memset(bss->ssid, 0, sizeof(bss->ssid));
958 } else if (g_strcmp0(key, "Capabilities") == 0) {
959 dbus_uint16_t capabilities = 0x0000;
961 dbus_message_iter_get_basic(iter, &capabilities);
963 if (capabilities & IEEE80211_CAP_ESS)
964 bss->mode = SUPPLICANT_MODE_INFRA;
965 else if (capabilities & IEEE80211_CAP_IBSS)
966 bss->mode = SUPPLICANT_MODE_IBSS;
968 if (capabilities & IEEE80211_CAP_PRIVACY)
970 } else if (g_strcmp0(key, "Mode") == 0) {
971 const char *mode = NULL;
973 dbus_message_iter_get_basic(iter, &mode);
974 bss->mode = string2mode(mode);
975 } else if (g_strcmp0(key, "Frequency") == 0) {
976 dbus_uint16_t frequency = 0;
978 dbus_message_iter_get_basic(iter, &frequency);
979 bss->frequency = frequency;
980 } else if (g_strcmp0(key, "Signal") == 0) {
981 dbus_int16_t signal = 0;
983 dbus_message_iter_get_basic(iter, &signal);
984 } else if (g_strcmp0(key, "Level") == 0) {
985 dbus_int32_t level = 0;
987 dbus_message_iter_get_basic(iter, &level);
988 } else if (g_strcmp0(key, "Rates") == 0) {
989 supplicant_dbus_array_foreach(iter, bss_rates, bss);
990 } else if (g_strcmp0(key, "MaxRate") == 0) {
991 dbus_uint32_t maxrate = 0;
993 dbus_message_iter_get_basic(iter, &maxrate);
995 bss->maxrate =maxrate;
996 } else if (g_strcmp0(key, "Privacy") == 0) {
997 dbus_bool_t privacy = FALSE;
999 dbus_message_iter_get_basic(iter, &privacy);
1000 bss->privacy = privacy;
1001 } else if (g_strcmp0(key, "RSNIE") == 0) {
1002 DBusMessageIter array;
1006 dbus_message_iter_recurse(iter, &array);
1007 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1010 extract_rsn(bss, ie + 2, ie_len - 2);
1011 } else if (g_strcmp0(key, "WPAIE") == 0) {
1012 DBusMessageIter array;
1016 dbus_message_iter_recurse(iter, &array);
1017 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1020 extract_rsn(bss, ie + 6, ie_len - 6);
1021 } else if (g_strcmp0(key, "WPSIE") == 0) {
1022 DBusMessageIter array;
1026 dbus_message_iter_recurse(iter, &array);
1027 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1029 DBG("key %s type %c",
1030 key, dbus_message_iter_get_arg_type(iter));
1033 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
1035 struct supplicant_interface *interface = user_data;
1036 struct supplicant_network *network;
1037 struct supplicant_bss *bss;
1038 const char *path = NULL;
1040 dbus_message_iter_get_basic(iter, &path);
1044 if (g_strcmp0(path, "/") == 0)
1047 network = g_hash_table_lookup(interface->bss_mapping, path);
1048 if (network != NULL) {
1049 bss = g_hash_table_lookup(network->bss_table, path);
1054 bss = g_try_new0(struct supplicant_bss, 1);
1058 bss->interface = interface;
1059 bss->path = g_strdup(path);
1061 dbus_message_iter_next(iter);
1062 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1063 supplicant_dbus_property_foreach(iter, bss_property, bss);
1064 bss_property(NULL, NULL, bss);
1068 supplicant_dbus_property_get_all(path,
1069 SUPPLICANT_INTERFACE ".Interface.BSS",
1073 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
1075 struct supplicant_interface *interface = user_data;
1076 struct supplicant_network *network;
1077 const char *path = NULL;
1079 dbus_message_iter_get_basic(iter, &path);
1083 network = g_hash_table_lookup(interface->bss_mapping, path);
1084 if (network == NULL)
1087 g_hash_table_remove(interface->bss_mapping, path);
1088 g_hash_table_remove(network->bss_table, path);
1090 if (g_hash_table_size(network->bss_table) == 0)
1091 g_hash_table_remove(interface->network_table, network->group);
1094 static void interface_property(const char *key, DBusMessageIter *iter,
1097 struct supplicant_interface *interface = user_data;
1099 if (interface == NULL)
1103 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
1104 interface->keymgmt_capa);
1105 debug_strvalmap("AuthAlg capability", authalg_capa_map,
1106 interface->authalg_capa);
1107 debug_strvalmap("Protocol capability", proto_capa_map,
1108 interface->proto_capa);
1109 debug_strvalmap("Pairwise capability", pairwise_capa_map,
1110 interface->pairwise_capa);
1111 debug_strvalmap("Group capability", group_capa_map,
1112 interface->group_capa);
1113 debug_strvalmap("Scan capability", scan_capa_map,
1114 interface->scan_capa);
1115 debug_strvalmap("Mode capability", mode_capa_map,
1116 interface->mode_capa);
1118 interface->ready = TRUE;
1119 callback_interface_added(interface);
1123 if (g_strcmp0(key, "Capabilities") == 0) {
1124 supplicant_dbus_property_foreach(iter, interface_capability,
1126 } else if (g_strcmp0(key, "State") == 0) {
1127 const char *str = NULL;
1129 dbus_message_iter_get_basic(iter, &str);
1131 interface->state = string2state(str);
1133 DBG("state %s (%d)", str, interface->state);
1134 } else if (g_strcmp0(key, "Scanning") == 0) {
1135 dbus_bool_t scanning = FALSE;
1137 dbus_message_iter_get_basic(iter, &scanning);
1138 interface->scanning = scanning;
1140 if (interface->ready == TRUE) {
1141 if (interface->scanning == TRUE)
1142 callback_scan_started(interface);
1144 callback_scan_finished(interface);
1146 } else if (g_strcmp0(key, "ApScan") == 0) {
1149 dbus_message_iter_get_basic(iter, &apscan);
1150 interface->apscan = apscan;
1151 } else if (g_strcmp0(key, "Ifname") == 0) {
1152 const char *str = NULL;
1154 dbus_message_iter_get_basic(iter, &str);
1156 interface->ifname = g_strdup(str);
1157 } else if (g_strcmp0(key, "Driver") == 0) {
1158 const char *str = NULL;
1160 dbus_message_iter_get_basic(iter, &str);
1162 interface->driver = g_strdup(str);
1163 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1164 const char *str = NULL;
1166 dbus_message_iter_get_basic(iter, &str);
1168 interface->bridge = g_strdup(str);
1169 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1170 interface_bss_added(iter, interface);
1171 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1172 interface_network_added(iter, interface);
1173 } else if (g_strcmp0(key, "BSSs") == 0) {
1174 supplicant_dbus_array_foreach(iter, interface_bss_added,
1176 } else if (g_strcmp0(key, "Blobs") == 0) {
1177 } else if (g_strcmp0(key, "Networks") == 0) {
1178 supplicant_dbus_array_foreach(iter, interface_network_added,
1181 DBG("key %s type %c",
1182 key, dbus_message_iter_get_arg_type(iter));
1185 static struct supplicant_interface *interface_alloc(const char *path)
1187 struct supplicant_interface *interface;
1189 interface = g_try_new0(struct supplicant_interface, 1);
1190 if (interface == NULL)
1193 interface->path = g_strdup(path);
1195 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1196 NULL, remove_network);
1198 interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1200 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1203 g_hash_table_replace(interface_table, interface->path, interface);
1208 static void interface_added(DBusMessageIter *iter, void *user_data)
1210 struct supplicant_interface *interface;
1211 const char *path = NULL;
1213 dbus_message_iter_get_basic(iter, &path);
1217 if (g_strcmp0(path, "/") == 0)
1220 interface = g_hash_table_lookup(interface_table, path);
1221 if (interface != NULL)
1224 interface = interface_alloc(path);
1225 if (interface == NULL)
1228 dbus_message_iter_next(iter);
1229 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1230 supplicant_dbus_property_foreach(iter, interface_property,
1232 interface_property(NULL, NULL, interface);
1236 supplicant_dbus_property_get_all(path,
1237 SUPPLICANT_INTERFACE ".Interface",
1238 interface_property, interface);
1241 static void interface_removed(DBusMessageIter *iter, void *user_data)
1243 const char *path = NULL;
1245 dbus_message_iter_get_basic(iter, &path);
1249 g_hash_table_remove(interface_table, path);
1252 static void eap_method(DBusMessageIter *iter, void *user_data)
1254 const char *str = NULL;
1257 dbus_message_iter_get_basic(iter, &str);
1261 for (i = 0; eap_method_map[i].str != NULL; i++)
1262 if (strcmp(str, eap_method_map[i].str) == 0) {
1263 eap_methods |= eap_method_map[i].val;
1268 static void service_property(const char *key, DBusMessageIter *iter,
1272 callback_system_ready();
1276 if (g_strcmp0(key, "DebugLevel") == 0) {
1277 const char *str = NULL;
1280 dbus_message_iter_get_basic(iter, &str);
1281 for (i = 0; debug_strings[i] != NULL; i++)
1282 if (g_strcmp0(debug_strings[i], str) == 0) {
1286 DBG("Debug level %d", debug_level);
1287 } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
1288 dbus_message_iter_get_basic(iter, &debug_timestamp);
1289 DBG("Debug timestamp %u", debug_timestamp);
1290 } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1291 dbus_message_iter_get_basic(iter, &debug_showkeys);
1292 DBG("Debug show keys %u", debug_showkeys);
1293 } else if (g_strcmp0(key, "Interfaces") == 0) {
1294 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1295 } else if (g_strcmp0(key, "EapMethods") == 0) {
1296 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1297 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1299 DBG("key %s type %c",
1300 key, dbus_message_iter_get_arg_type(iter));
1303 static void supplicant_bootstrap(void)
1305 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1306 SUPPLICANT_INTERFACE,
1307 service_property, NULL);
1310 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1312 const char *name = NULL, *old = NULL, *new = NULL;
1314 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1317 dbus_message_iter_get_basic(iter, &name);
1321 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1324 dbus_message_iter_next(iter);
1325 dbus_message_iter_get_basic(iter, &old);
1326 dbus_message_iter_next(iter);
1327 dbus_message_iter_get_basic(iter, &new);
1329 if (old == NULL || new == NULL)
1332 if (strlen(old) > 0 && strlen(new) == 0) {
1333 system_available = FALSE;
1334 g_hash_table_remove_all(interface_table);
1335 callback_system_killed();
1338 if (strlen(new) > 0 && strlen(old) == 0) {
1339 system_available = TRUE;
1340 supplicant_bootstrap();
1344 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1346 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1349 supplicant_dbus_property_foreach(iter, service_property, NULL);
1352 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1354 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1355 interface_added(iter, NULL);
1358 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1360 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1361 interface_removed(iter, NULL);
1364 static void signal_properties(const char *path, DBusMessageIter *iter)
1366 struct supplicant_interface *interface;
1368 interface = g_hash_table_lookup(interface_table, path);
1369 if (interface == NULL)
1372 supplicant_dbus_property_foreach(iter, interface_property, interface);
1375 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1377 struct supplicant_interface *interface;
1378 dbus_bool_t success = FALSE;
1380 interface = g_hash_table_lookup(interface_table, path);
1381 if (interface == NULL)
1384 dbus_message_iter_get_basic(iter, &success);
1386 if (interface->scan_callback != NULL) {
1389 if (success == FALSE)
1392 interface->scan_callback(result, interface->scan_data);
1395 interface->scan_callback = NULL;
1396 interface->scan_data = NULL;
1399 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1401 struct supplicant_interface *interface;
1403 interface = g_hash_table_lookup(interface_table, path);
1404 if (interface == NULL)
1407 interface_bss_added(iter, interface);
1410 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1412 struct supplicant_interface *interface;
1414 interface = g_hash_table_lookup(interface_table, path);
1415 if (interface == NULL)
1418 interface_bss_removed(iter, interface);
1421 static void signal_network_added(const char *path, DBusMessageIter *iter)
1423 struct supplicant_interface *interface;
1425 interface = g_hash_table_lookup(interface_table, path);
1426 if (interface == NULL)
1429 interface_network_added(iter, interface);
1432 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1434 struct supplicant_interface *interface;
1436 interface = g_hash_table_lookup(interface_table, path);
1437 if (interface == NULL)
1440 interface_network_removed(iter, interface);
1444 const char *interface;
1446 void (*function) (const char *path, DBusMessageIter *iter);
1448 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1450 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1451 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1452 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1453 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1455 { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_properties },
1456 { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done },
1457 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1458 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1459 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1460 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1465 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1466 DBusMessage *message, void *data)
1468 DBusMessageIter iter;
1472 path = dbus_message_get_path(message);
1474 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1476 if (dbus_message_iter_init(message, &iter) == FALSE)
1477 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1479 for (i = 0; signal_map[i].interface != NULL; i++) {
1480 if (dbus_message_has_interface(message,
1481 signal_map[i].interface) == FALSE)
1484 if (dbus_message_has_member(message,
1485 signal_map[i].member) == FALSE)
1488 signal_map[i].function(path, &iter);
1492 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1495 static const char *supplicant_rule0 = "type=signal,"
1496 "path=" DBUS_PATH_DBUS ","
1497 "sender=" DBUS_SERVICE_DBUS ","
1498 "interface=" DBUS_INTERFACE_DBUS ","
1499 "member=NameOwnerChanged,"
1500 "arg0=" SUPPLICANT_SERVICE;
1501 static const char *supplicant_rule1 = "type=signal,"
1502 "interface=" SUPPLICANT_INTERFACE;
1503 static const char *supplicant_rule2 = "type=signal,"
1504 "interface=" SUPPLICANT_INTERFACE ".Interface";
1505 static const char *supplicant_rule3 = "type=signal,"
1506 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1507 static const char *supplicant_rule4 = "type=signal,"
1508 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1509 static const char *supplicant_rule5 = "type=signal,"
1510 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1511 static const char *supplicant_rule6 = "type=signal,"
1512 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1514 int supplicant_register(const struct supplicant_callbacks *callbacks)
1516 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1517 if (connection == NULL)
1520 if (dbus_connection_add_filter(connection,
1521 supplicant_filter, NULL, NULL) == FALSE) {
1522 dbus_connection_unref(connection);
1527 callbacks_pointer = callbacks;
1530 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1531 NULL, remove_interface);
1533 supplicant_dbus_setup(connection);
1535 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1536 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1537 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1538 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1539 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1540 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1541 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1542 dbus_connection_flush(connection);
1544 if (dbus_bus_name_has_owner(connection,
1545 SUPPLICANT_SERVICE, NULL) == TRUE) {
1546 system_available = TRUE;
1547 supplicant_bootstrap();
1553 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1555 if (connection != NULL) {
1556 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1557 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1558 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1559 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1560 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1561 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1562 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1563 dbus_connection_flush(connection);
1565 dbus_connection_remove_filter(connection,
1566 supplicant_filter, NULL);
1569 if (interface_table != NULL) {
1570 g_hash_table_destroy(interface_table);
1571 interface_table = NULL;
1574 if (system_available == TRUE)
1575 callback_system_killed();
1577 if (connection != NULL) {
1578 dbus_connection_unref(connection);
1582 callbacks_pointer = NULL;
1586 static void debug_level_result(const char *error,
1587 DBusMessageIter *iter, void *user_data)
1590 DBG("debug level failure: %s", error);
1593 static void debug_level_params(DBusMessageIter *iter, void *user_data)
1595 guint level = GPOINTER_TO_UINT(user_data);
1601 str = debug_strings[level];
1603 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
1606 void supplicant_set_debug_level(unsigned int level)
1608 if (system_available == FALSE)
1611 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1612 "DebugLevel", DBUS_TYPE_STRING_AS_STRING,
1613 debug_level_params, debug_level_result,
1614 GUINT_TO_POINTER(level));
1617 struct interface_create_data {
1620 struct supplicant_interface *interface;
1621 supplicant_interface_create_callback callback;
1625 static void interface_create_property(const char *key, DBusMessageIter *iter,
1628 struct interface_create_data *data = user_data;
1629 struct supplicant_interface *interface = data->interface;
1632 if (data->callback != NULL)
1633 data->callback(0, data->interface, data->user_data);
1638 interface_property(key, iter, interface);
1641 static void interface_create_result(const char *error,
1642 DBusMessageIter *iter, void *user_data)
1644 struct interface_create_data *data = user_data;
1645 const char *path = NULL;
1648 if (error != NULL) {
1653 dbus_message_iter_get_basic(iter, &path);
1659 if (system_available == FALSE) {
1664 data->interface = g_hash_table_lookup(interface_table, path);
1665 if (data->interface == NULL) {
1666 data->interface = interface_alloc(path);
1667 if (data->interface == NULL) {
1673 err = supplicant_dbus_property_get_all(path,
1674 SUPPLICANT_INTERFACE ".Interface",
1675 interface_create_property, data);
1680 if (data->callback != NULL)
1681 data->callback(err, NULL, data->user_data);
1686 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1688 struct interface_create_data *data = user_data;
1689 DBusMessageIter dict;
1691 supplicant_dbus_dict_open(iter, &dict);
1693 supplicant_dbus_dict_append_basic(&dict, "Ifname",
1694 DBUS_TYPE_STRING, &data->ifname);
1696 if (data->driver != NULL)
1697 supplicant_dbus_dict_append_basic(&dict, "Driver",
1698 DBUS_TYPE_STRING, &data->driver);
1700 supplicant_dbus_dict_close(iter, &dict);
1703 static void interface_get_result(const char *error,
1704 DBusMessageIter *iter, void *user_data)
1706 struct interface_create_data *data = user_data;
1707 struct supplicant_interface *interface;
1708 const char *path = NULL;
1711 if (error != NULL) {
1716 dbus_message_iter_get_basic(iter, &path);
1722 interface = g_hash_table_lookup(interface_table, path);
1723 if (interface == NULL) {
1728 if (data->callback != NULL)
1729 data->callback(0, interface, data->user_data);
1736 if (system_available == FALSE) {
1741 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1742 SUPPLICANT_INTERFACE,
1744 interface_create_params,
1745 interface_create_result, data);
1750 if (data->callback != NULL)
1751 data->callback(err, NULL, data->user_data);
1756 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1758 struct interface_create_data *data = user_data;
1760 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1763 int supplicant_interface_create(const char *ifname, const char *driver,
1764 supplicant_interface_create_callback callback,
1767 struct interface_create_data *data;
1772 if (system_available == FALSE)
1775 data = dbus_malloc0(sizeof(*data));
1779 data->ifname = ifname;
1780 data->driver = driver;
1781 data->callback = callback;
1782 data->user_data = user_data;
1784 return supplicant_dbus_method_call(SUPPLICANT_PATH,
1785 SUPPLICANT_INTERFACE,
1787 interface_get_params,
1788 interface_get_result, data);
1791 int supplicant_interface_remove(struct supplicant_interface *interface,
1792 supplicant_interface_remove_callback callback,
1795 if (interface == NULL)
1798 if (system_available == FALSE)
1804 struct interface_scan_data {
1805 struct supplicant_interface *interface;
1806 supplicant_interface_scan_callback callback;
1810 static void interface_scan_result(const char *error,
1811 DBusMessageIter *iter, void *user_data)
1813 struct interface_scan_data *data = user_data;
1815 if (error != NULL) {
1816 if (data->callback != NULL)
1817 data->callback(-EIO, data->user_data);
1819 data->interface->scan_callback = data->callback;
1820 data->interface->scan_data = data->user_data;
1826 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
1828 DBusMessageIter dict;
1829 const char *type = "passive";
1831 supplicant_dbus_dict_open(iter, &dict);
1833 supplicant_dbus_dict_append_basic(&dict, "Type",
1834 DBUS_TYPE_STRING, &type);
1836 supplicant_dbus_dict_close(iter, &dict);
1839 int supplicant_interface_scan(struct supplicant_interface *interface,
1840 supplicant_interface_scan_callback callback,
1843 struct interface_scan_data *data;
1845 if (interface == NULL)
1848 if (system_available == FALSE)
1851 if (interface->scanning == TRUE)
1854 data = dbus_malloc0(sizeof(*data));
1858 data->interface = interface;
1859 data->callback = callback;
1860 data->user_data = user_data;
1862 return supplicant_dbus_method_call(interface->path,
1863 SUPPLICANT_INTERFACE ".Interface", "Scan",
1864 interface_scan_params, interface_scan_result, data);
1867 struct interface_disconnect_data {
1868 supplicant_interface_disconnect_callback callback;
1872 static void interface_disconnect_result(const char *error,
1873 DBusMessageIter *iter, void *user_data)
1875 struct interface_disconnect_data *data = user_data;
1881 if (data->callback != NULL)
1882 data->callback(result, data->user_data);
1887 int supplicant_interface_disconnect(struct supplicant_interface *interface,
1888 supplicant_interface_disconnect_callback callback,
1891 struct interface_disconnect_data *data;
1893 if (interface == NULL)
1896 if (system_available == FALSE)
1899 data = dbus_malloc0(sizeof(*data));
1903 data->callback = callback;
1904 data->user_data = user_data;
1906 return supplicant_dbus_method_call(interface->path,
1907 SUPPLICANT_INTERFACE ".Interface", "Disconnect",
1908 NULL, interface_disconnect_result, data);