5 * Copyright (C) 2007-2009 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 unsigned int eap_methods;
65 static struct strvalmap eap_method_map[] = {
66 { "MD5", SUPPLICANT_EAP_METHOD_MD5 },
67 { "TLS", SUPPLICANT_EAP_METHOD_TLS },
68 { "MSCHAPV2", SUPPLICANT_EAP_METHOD_MSCHAPV2 },
69 { "PEAP", SUPPLICANT_EAP_METHOD_PEAP },
70 { "TTLS", SUPPLICANT_EAP_METHOD_TTLS },
71 { "GTC", SUPPLICANT_EAP_METHOD_GTC },
72 { "OTP", SUPPLICANT_EAP_METHOD_OTP },
73 { "LEAP", SUPPLICANT_EAP_METHOD_LEAP },
74 { "WSC", SUPPLICANT_EAP_METHOD_WSC },
78 static struct strvalmap keymgmt_capa_map[] = {
79 { "none", SUPPLICANT_CAPABILITY_KEYMGMT_NONE },
80 { "ieee8021x", SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X },
81 { "wpa-none", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE },
82 { "wpa-psk", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK },
83 { "wpa-eap", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP },
84 { "wps", SUPPLICANT_CAPABILITY_KEYMGMT_WPS },
88 static struct strvalmap authalg_capa_map[] = {
89 { "open", SUPPLICANT_CAPABILITY_AUTHALG_OPEN },
90 { "shared", SUPPLICANT_CAPABILITY_AUTHALG_SHARED },
91 { "leap", SUPPLICANT_CAPABILITY_AUTHALG_LEAP },
95 static struct strvalmap proto_capa_map[] = {
96 { "wpa", SUPPLICANT_CAPABILITY_PROTO_WPA },
97 { "rsn", SUPPLICANT_CAPABILITY_PROTO_RSN },
101 static struct strvalmap group_capa_map[] = {
102 { "wep40", SUPPLICANT_CAPABILITY_GROUP_WEP40 },
103 { "wep104", SUPPLICANT_CAPABILITY_GROUP_WEP104 },
104 { "tkip", SUPPLICANT_CAPABILITY_GROUP_TKIP },
105 { "ccmp", SUPPLICANT_CAPABILITY_GROUP_CCMP },
109 static struct strvalmap pairwise_capa_map[] = {
110 { "none", SUPPLICANT_CAPABILITY_PAIRWISE_NONE },
111 { "tkip", SUPPLICANT_CAPABILITY_PAIRWISE_TKIP },
112 { "ccmp", SUPPLICANT_CAPABILITY_PAIRWISE_CCMP },
116 static struct strvalmap scan_capa_map[] = {
117 { "active", SUPPLICANT_CAPABILITY_SCAN_ACTIVE },
118 { "passive", SUPPLICANT_CAPABILITY_SCAN_PASSIVE },
119 { "ssid", SUPPLICANT_CAPABILITY_SCAN_SSID },
123 static struct strvalmap mode_capa_map[] = {
124 { "infrastructure", SUPPLICANT_CAPABILITY_MODE_INFRA },
125 { "ad-hoc", SUPPLICANT_CAPABILITY_MODE_IBSS },
126 { "ap", SUPPLICANT_CAPABILITY_MODE_AP },
130 static GHashTable *interface_table;
132 struct supplicant_interface {
134 unsigned int keymgmt_capa;
135 unsigned int authalg_capa;
136 unsigned int proto_capa;
137 unsigned int group_capa;
138 unsigned int pairwise_capa;
139 unsigned int scan_capa;
140 unsigned int mode_capa;
141 enum supplicant_state state;
142 dbus_bool_t scanning;
147 GHashTable *network_table;
148 GHashTable *bss_mapping;
151 struct supplicant_network {
152 struct supplicant_interface *interface;
155 enum supplicant_mode mode;
156 GHashTable *bss_table;
159 struct supplicant_bss {
160 struct supplicant_interface *interface;
162 unsigned char bssid[6];
163 unsigned char ssid[32];
164 unsigned int ssid_len;
165 dbus_uint16_t frequency;
166 enum supplicant_mode mode;
167 enum supplicant_security security;
170 dbus_bool_t ieee8021x;
173 static enum supplicant_mode string2mode(const char *mode)
176 return SUPPLICANT_MODE_UNKNOWN;
178 if (g_str_equal(mode, "infrastructure") == TRUE)
179 return SUPPLICANT_MODE_INFRA;
180 else if (g_str_equal(mode, "ad-hoc") == TRUE)
181 return SUPPLICANT_MODE_IBSS;
183 return SUPPLICANT_MODE_UNKNOWN;
186 static const char *mode2string(enum supplicant_mode mode)
189 case SUPPLICANT_MODE_UNKNOWN:
191 case SUPPLICANT_MODE_INFRA:
193 case SUPPLICANT_MODE_IBSS:
200 static const char *security2string(enum supplicant_security security)
203 case SUPPLICANT_SECURITY_UNKNOWN:
205 case SUPPLICANT_SECURITY_NONE:
207 case SUPPLICANT_SECURITY_WEP:
209 case SUPPLICANT_SECURITY_PSK:
211 case SUPPLICANT_SECURITY_IEEE8021X:
218 static enum supplicant_state string2state(const char *state)
221 return SUPPLICANT_STATE_UNKNOWN;
223 if (g_str_equal(state, "unknown") == TRUE)
224 return SUPPLICANT_STATE_UNKNOWN;
225 else if (g_str_equal(state, "disconnected") == TRUE)
226 return SUPPLICANT_STATE_DISCONNECTED;
227 else if (g_str_equal(state, "inactive") == TRUE)
228 return SUPPLICANT_STATE_INACTIVE;
229 else if (g_str_equal(state, "scanning") == TRUE)
230 return SUPPLICANT_STATE_SCANNING;
231 else if (g_str_equal(state, "authenticating") == TRUE)
232 return SUPPLICANT_STATE_AUTHENTICATING;
233 else if (g_str_equal(state, "associating") == TRUE)
234 return SUPPLICANT_STATE_ASSOCIATING;
235 else if (g_str_equal(state, "associated") == TRUE)
236 return SUPPLICANT_STATE_ASSOCIATED;
237 else if (g_str_equal(state, "group_handshake") == TRUE)
238 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
239 else if (g_str_equal(state, "4way_handshake") == TRUE)
240 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
241 else if (g_str_equal(state, "completed") == TRUE)
242 return SUPPLICANT_STATE_COMPLETED;
244 return SUPPLICANT_STATE_UNKNOWN;
247 static void callback_system_ready(void)
249 if (system_ready == TRUE)
254 if (callbacks_pointer == NULL)
257 if (callbacks_pointer->system_ready == NULL)
260 callbacks_pointer->system_ready();
263 static void callback_system_killed(void)
265 system_ready = FALSE;
267 if (callbacks_pointer == NULL)
270 if (callbacks_pointer->system_killed == NULL)
273 callbacks_pointer->system_killed();
276 static void callback_interface_added(struct supplicant_interface *interface)
278 if (callbacks_pointer == NULL)
281 if (callbacks_pointer->interface_added == NULL)
284 callbacks_pointer->interface_added(interface);
287 static void callback_interface_removed(struct supplicant_interface *interface)
289 if (callbacks_pointer == NULL)
292 if (callbacks_pointer->interface_removed == NULL)
295 callbacks_pointer->interface_removed(interface);
298 static void callback_scan_started(struct supplicant_interface *interface)
300 if (callbacks_pointer == NULL)
303 if (callbacks_pointer->scan_started == NULL)
306 callbacks_pointer->scan_started(interface);
309 static void callback_scan_finished(struct supplicant_interface *interface)
311 if (callbacks_pointer == NULL)
314 if (callbacks_pointer->scan_finished == NULL)
317 callbacks_pointer->scan_finished(interface);
320 static void callback_network_added(struct supplicant_network *network)
322 if (callbacks_pointer == NULL)
325 if (callbacks_pointer->network_added == NULL)
328 callbacks_pointer->network_added(network);
331 static void callback_network_removed(struct supplicant_network *network)
333 if (callbacks_pointer == NULL)
336 if (callbacks_pointer->network_removed == NULL)
339 callbacks_pointer->network_removed(network);
342 static void remove_interface(gpointer data)
344 struct supplicant_interface *interface = data;
346 g_hash_table_destroy(interface->bss_mapping);
347 g_hash_table_destroy(interface->network_table);
349 callback_interface_removed(interface);
351 g_free(interface->path);
352 g_free(interface->ifname);
353 g_free(interface->driver);
354 g_free(interface->bridge);
358 static void remove_network(gpointer data)
360 struct supplicant_network *network = data;
362 callback_network_removed(network);
364 g_free(network->group);
365 g_free(network->name);
369 static void remove_bss(gpointer data)
371 struct supplicant_bss *bss = data;
377 static void debug_strvalmap(const char *label, struct strvalmap *map,
382 for (i = 0; map[i].str != NULL; i++) {
383 if (val & map[i].val)
384 DBG("%s: %s", label, map[i].str);
388 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
390 struct supplicant_interface *interface = user_data;
391 const char *str = NULL;
394 dbus_message_iter_get_basic(iter, &str);
398 for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
399 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
400 interface->keymgmt_capa |= keymgmt_capa_map[i].val;
405 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
407 struct supplicant_interface *interface = user_data;
408 const char *str = NULL;
411 dbus_message_iter_get_basic(iter, &str);
415 for (i = 0; authalg_capa_map[i].str != NULL; i++)
416 if (strcmp(str, authalg_capa_map[i].str) == 0) {
417 interface->authalg_capa |= authalg_capa_map[i].val;
422 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
424 struct supplicant_interface *interface = user_data;
425 const char *str = NULL;
428 dbus_message_iter_get_basic(iter, &str);
432 for (i = 0; proto_capa_map[i].str != NULL; i++)
433 if (strcmp(str, proto_capa_map[i].str) == 0) {
434 interface->proto_capa |= proto_capa_map[i].val;
439 static void interface_capability_pairwise(DBusMessageIter *iter, void *user_data)
441 struct supplicant_interface *interface = user_data;
442 const char *str = NULL;
445 dbus_message_iter_get_basic(iter, &str);
449 for (i = 0; pairwise_capa_map[i].str != NULL; i++)
450 if (strcmp(str, pairwise_capa_map[i].str) == 0) {
451 interface->pairwise_capa |= pairwise_capa_map[i].val;
456 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
458 struct supplicant_interface *interface = user_data;
459 const char *str = NULL;
462 dbus_message_iter_get_basic(iter, &str);
466 for (i = 0; group_capa_map[i].str != NULL; i++)
467 if (strcmp(str, group_capa_map[i].str) == 0) {
468 interface->group_capa |= group_capa_map[i].val;
473 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
475 struct supplicant_interface *interface = user_data;
476 const char *str = NULL;
479 dbus_message_iter_get_basic(iter, &str);
483 for (i = 0; scan_capa_map[i].str != NULL; i++)
484 if (strcmp(str, scan_capa_map[i].str) == 0) {
485 interface->scan_capa |= scan_capa_map[i].val;
490 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
492 struct supplicant_interface *interface = user_data;
493 const char *str = NULL;
496 dbus_message_iter_get_basic(iter, &str);
500 for (i = 0; mode_capa_map[i].str != NULL; i++)
501 if (strcmp(str, mode_capa_map[i].str) == 0) {
502 interface->mode_capa |= mode_capa_map[i].val;
507 static void interface_capability(const char *key, DBusMessageIter *iter,
510 struct supplicant_interface *interface = user_data;
515 if (g_strcmp0(key, "KeyMgmt") == 0)
516 supplicant_dbus_array_foreach(iter,
517 interface_capability_keymgmt, interface);
518 else if (g_strcmp0(key, "AuthAlg") == 0)
519 supplicant_dbus_array_foreach(iter,
520 interface_capability_authalg, interface);
521 else if (g_strcmp0(key, "Protocol") == 0)
522 supplicant_dbus_array_foreach(iter,
523 interface_capability_proto, interface);
524 else if (g_strcmp0(key, "Pairwise") == 0)
525 supplicant_dbus_array_foreach(iter,
526 interface_capability_pairwise, interface);
527 else if (g_strcmp0(key, "Group") == 0)
528 supplicant_dbus_array_foreach(iter,
529 interface_capability_group, interface);
530 else if (g_strcmp0(key, "Scan") == 0)
531 supplicant_dbus_array_foreach(iter,
532 interface_capability_scan, interface);
533 else if (g_strcmp0(key, "Modes") == 0)
534 supplicant_dbus_array_foreach(iter,
535 interface_capability_mode, interface);
537 DBG("key %s type %c",
538 key, dbus_message_iter_get_arg_type(iter));
541 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
543 if (interface == NULL)
546 return interface->ifname;
549 const char *supplicant_interface_get_driver(struct supplicant_interface *interface)
551 if (interface == NULL)
554 return interface->driver;
557 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
562 return network->interface;
565 const char *supplicant_network_get_name(struct supplicant_network *network)
567 if (network == NULL || network->name == NULL)
570 return network->name;
573 const char *supplicant_network_get_identifier(struct supplicant_network *network)
575 if (network == NULL || network->group == NULL)
578 return network->group;
581 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
584 return SUPPLICANT_MODE_UNKNOWN;
586 return network->mode;
589 static void network_property(const char *key, DBusMessageIter *iter,
595 //DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
598 static void interface_network_added(DBusMessageIter *iter, void *user_data)
600 //struct supplicant_interface *interface = user_data;
601 const char *path = NULL;
603 dbus_message_iter_get_basic(iter, &path);
607 if (g_strcmp0(path, "/") == 0)
610 dbus_message_iter_next(iter);
611 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
612 supplicant_dbus_property_foreach(iter, network_property, NULL);
613 network_property(NULL, NULL, NULL);
617 DBG("path %s", path);
619 supplicant_dbus_property_get_all(path,
620 SUPPLICANT_INTERFACE ".Interface.Network",
621 network_property, NULL);
624 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
626 const char *path = NULL;
628 dbus_message_iter_get_basic(iter, &path);
632 DBG("path %s", path);
635 static char *create_name(unsigned char *ssid, int ssid_len)
640 if (ssid_len < 1 || ssid[0] == '\0')
643 name = g_try_malloc0(ssid_len + 1);
648 for (i = 0; i < ssid_len; i++) {
649 if (g_ascii_isprint(ssid[i]))
658 static char *create_group(struct supplicant_bss *bss)
662 const char *mode, *security;
664 str = g_string_sized_new((bss->ssid_len * 2) + 24);
668 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
669 for (i = 0; i < bss->ssid_len; i++)
670 g_string_append_printf(str, "%02x", bss->ssid[i]);
672 g_string_append_printf(str, "hidden");
674 mode = mode2string(bss->mode);
676 g_string_append_printf(str, "_%s", mode);
678 security = security2string(bss->security);
679 if (security != NULL)
680 g_string_append_printf(str, "_%s", security);
682 return g_string_free(str, FALSE);
685 static void add_bss_to_network(struct supplicant_bss *bss)
687 struct supplicant_interface *interface = bss->interface;
688 struct supplicant_network *network;
691 group = create_group(bss);
695 network = g_hash_table_lookup(interface->network_table, group);
696 if (network != NULL) {
701 network = g_try_new0(struct supplicant_network, 1);
702 if (network == NULL) {
707 network->group = group;
708 network->name = create_name(bss->ssid, bss->ssid_len);
709 network->mode = bss->mode;
711 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
714 g_hash_table_replace(interface->network_table,
715 network->group, network);
717 callback_network_added(network);
720 g_hash_table_replace(interface->bss_mapping, bss->path, network);
721 g_hash_table_replace(network->bss_table, bss->path, bss);
724 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
725 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
727 static void extract_rsn(struct supplicant_bss *bss,
728 const unsigned char *buf, int len)
747 /* Pairwise cipher */
751 count = buf[0] | (buf[1] << 8);
752 if (2 + (count * 4) > len)
755 buf += 2 + (count * 4);
756 len -= 2 + (count * 4);
762 count = buf[0] | (buf[1] << 8);
763 if (2 + (count * 4) > len)
766 for (i = 0; i < count; i++) {
767 const unsigned char *ptr = buf + 2 + (i * 4);
769 if (memcmp(ptr, wifi_oui, 3) == 0) {
772 bss->ieee8021x = TRUE;
778 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
781 bss->ieee8021x = TRUE;
790 buf += 2 + (count * 4);
791 len -= 2 + (count * 4);
794 static void bss_property(const char *key, DBusMessageIter *iter,
797 struct supplicant_bss *bss = user_data;
799 if (bss->interface == NULL)
803 if (bss->ieee8021x == TRUE)
804 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
805 else if (bss->psk == TRUE)
806 bss->security = SUPPLICANT_SECURITY_PSK;
807 else if (bss->privacy == TRUE)
808 bss->security = SUPPLICANT_SECURITY_WEP;
810 bss->security = SUPPLICANT_SECURITY_NONE;
812 add_bss_to_network(bss);
816 if (g_strcmp0(key, "BSSID") == 0) {
817 DBusMessageIter array;
821 dbus_message_iter_recurse(iter, &array);
822 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
825 memcpy(bss->bssid, addr, addr_len);
826 } else if (g_strcmp0(key, "SSID") == 0) {
827 DBusMessageIter array;
831 dbus_message_iter_recurse(iter, &array);
832 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
834 if (ssid_len > 0 && ssid_len < 33) {
835 memcpy(bss->ssid, ssid, ssid_len);
836 bss->ssid_len = ssid_len;
838 memset(bss->ssid, 0, sizeof(bss->ssid));
841 } else if (g_strcmp0(key, "Capabilities") == 0) {
842 dbus_uint16_t capabilities = 0x0000;
844 dbus_message_iter_get_basic(iter, &capabilities);
846 if (capabilities & IEEE80211_CAP_ESS)
847 bss->mode = SUPPLICANT_MODE_INFRA;
848 else if (capabilities & IEEE80211_CAP_IBSS)
849 bss->mode = SUPPLICANT_MODE_IBSS;
851 if (capabilities & IEEE80211_CAP_PRIVACY)
853 } else if (g_strcmp0(key, "Mode") == 0) {
854 const char *mode = NULL;
856 dbus_message_iter_get_basic(iter, &mode);
857 bss->mode = string2mode(mode);
858 } else if (g_strcmp0(key, "Frequency") == 0) {
859 dbus_uint16_t frequency = 0;
861 dbus_message_iter_get_basic(iter, &frequency);
862 bss->frequency = frequency;
863 } else if (g_strcmp0(key, "Signal") == 0) {
864 dbus_int16_t signal = 0;
866 dbus_message_iter_get_basic(iter, &signal);
867 } else if (g_strcmp0(key, "Level") == 0) {
868 dbus_int32_t level = 0;
870 dbus_message_iter_get_basic(iter, &level);
871 } else if (g_strcmp0(key, "MaxRate") == 0) {
872 dbus_uint16_t maxrate = 0;
874 dbus_message_iter_get_basic(iter, &maxrate);
875 } else if (g_strcmp0(key, "Privacy") == 0) {
876 dbus_bool_t privacy = FALSE;
878 dbus_message_iter_get_basic(iter, &privacy);
879 bss->privacy = privacy;
880 } else if (g_strcmp0(key, "RSNIE") == 0) {
881 DBusMessageIter array;
885 dbus_message_iter_recurse(iter, &array);
886 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
889 extract_rsn(bss, ie + 2, ie_len - 2);
890 } else if (g_strcmp0(key, "WPAIE") == 0) {
891 DBusMessageIter array;
895 dbus_message_iter_recurse(iter, &array);
896 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
899 extract_rsn(bss, ie + 6, ie_len - 6);
900 } else if (g_strcmp0(key, "WPSIE") == 0) {
901 DBusMessageIter array;
905 dbus_message_iter_recurse(iter, &array);
906 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
908 DBG("key %s type %c",
909 key, dbus_message_iter_get_arg_type(iter));
912 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
914 struct supplicant_interface *interface = user_data;
915 struct supplicant_network *network;
916 struct supplicant_bss *bss;
917 const char *path = NULL;
919 dbus_message_iter_get_basic(iter, &path);
923 if (g_strcmp0(path, "/") == 0)
926 network = g_hash_table_lookup(interface->bss_mapping, path);
927 if (network != NULL) {
928 bss = g_hash_table_lookup(network->bss_table, path);
933 bss = g_try_new0(struct supplicant_bss, 1);
937 bss->interface = interface;
938 bss->path = g_strdup(path);
940 dbus_message_iter_next(iter);
941 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
942 supplicant_dbus_property_foreach(iter, bss_property, bss);
943 bss_property(NULL, NULL, bss);
947 supplicant_dbus_property_get_all(path,
948 SUPPLICANT_INTERFACE ".Interface.BSS",
952 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
954 struct supplicant_interface *interface = user_data;
955 struct supplicant_network *network;
956 const char *path = NULL;
958 dbus_message_iter_get_basic(iter, &path);
962 network = g_hash_table_lookup(interface->bss_mapping, path);
966 g_hash_table_remove(interface->bss_mapping, path);
967 g_hash_table_remove(network->bss_table, path);
969 if (g_hash_table_size(network->bss_table) == 0)
970 g_hash_table_remove(interface->network_table, network->group);
973 static void interface_property(const char *key, DBusMessageIter *iter,
976 struct supplicant_interface *interface = user_data;
978 if (interface == NULL)
982 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
983 interface->keymgmt_capa);
984 debug_strvalmap("AuthAlg capability", authalg_capa_map,
985 interface->authalg_capa);
986 debug_strvalmap("Protocol capability", proto_capa_map,
987 interface->proto_capa);
988 debug_strvalmap("Pairwise capability", pairwise_capa_map,
989 interface->pairwise_capa);
990 debug_strvalmap("Group capability", group_capa_map,
991 interface->group_capa);
992 debug_strvalmap("Scan capability", scan_capa_map,
993 interface->scan_capa);
994 debug_strvalmap("Mode capability", mode_capa_map,
995 interface->mode_capa);
997 callback_interface_added(interface);
1001 if (g_strcmp0(key, "Capabilities") == 0) {
1002 supplicant_dbus_property_foreach(iter, interface_capability,
1004 } else if (g_strcmp0(key, "State") == 0) {
1005 const char *str = NULL;
1007 dbus_message_iter_get_basic(iter, &str);
1009 interface->state = string2state(str);
1010 } else if (g_strcmp0(key, "Scanning") == 0) {
1011 dbus_bool_t scanning = FALSE;
1013 dbus_message_iter_get_basic(iter, &scanning);
1014 interface->scanning = scanning;
1016 DBG("scanning %u", interface->scanning);
1018 if (interface->scanning == TRUE)
1019 callback_scan_started(interface);
1020 } else if (g_strcmp0(key, "ApScan") == 0) {
1023 dbus_message_iter_get_basic(iter, &apscan);
1024 interface->apscan = apscan;
1025 } else if (g_strcmp0(key, "Ifname") == 0) {
1026 const char *str = NULL;
1028 dbus_message_iter_get_basic(iter, &str);
1030 interface->ifname = g_strdup(str);
1031 } else if (g_strcmp0(key, "Driver") == 0) {
1032 const char *str = NULL;
1034 dbus_message_iter_get_basic(iter, &str);
1036 interface->driver = g_strdup(str);
1037 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1038 const char *str = NULL;
1040 dbus_message_iter_get_basic(iter, &str);
1042 interface->bridge = g_strdup(str);
1043 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1044 interface_bss_added(iter, interface);
1045 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1046 interface_network_added(iter, interface);
1047 } else if (g_strcmp0(key, "BSSs") == 0) {
1048 supplicant_dbus_array_foreach(iter, interface_bss_added,
1050 } else if (g_strcmp0(key, "Blobs") == 0) {
1051 } else if (g_strcmp0(key, "Networks") == 0) {
1052 supplicant_dbus_array_foreach(iter, interface_network_added,
1055 DBG("key %s type %c",
1056 key, dbus_message_iter_get_arg_type(iter));
1059 static struct supplicant_interface *interface_alloc(const char *path)
1061 struct supplicant_interface *interface;
1063 interface = g_try_new0(struct supplicant_interface, 1);
1064 if (interface == NULL)
1067 interface->path = g_strdup(path);
1069 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1070 NULL, remove_network);
1072 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1075 g_hash_table_replace(interface_table, interface->path, interface);
1080 static void interface_added(DBusMessageIter *iter, void *user_data)
1082 struct supplicant_interface *interface;
1083 const char *path = NULL;
1085 dbus_message_iter_get_basic(iter, &path);
1089 if (g_strcmp0(path, "/") == 0)
1092 interface = g_hash_table_lookup(interface_table, path);
1093 if (interface != NULL)
1096 interface = interface_alloc(path);
1097 if (interface == NULL)
1100 dbus_message_iter_next(iter);
1101 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1102 supplicant_dbus_property_foreach(iter, interface_property,
1104 interface_property(NULL, NULL, interface);
1108 supplicant_dbus_property_get_all(path,
1109 SUPPLICANT_INTERFACE ".Interface",
1110 interface_property, interface);
1113 static void interface_removed(DBusMessageIter *iter, void *user_data)
1115 const char *path = NULL;
1117 dbus_message_iter_get_basic(iter, &path);
1121 g_hash_table_remove(interface_table, path);
1124 static void eap_method(DBusMessageIter *iter, void *user_data)
1126 const char *str = NULL;
1129 dbus_message_iter_get_basic(iter, &str);
1133 for (i = 0; eap_method_map[i].str != NULL; i++)
1134 if (strcmp(str, eap_method_map[i].str) == 0) {
1135 eap_methods |= eap_method_map[i].val;
1140 static void service_property(const char *key, DBusMessageIter *iter,
1144 callback_system_ready();
1148 if (g_strcmp0(key, "DebugParams") == 0) {
1149 DBusMessageIter list;
1151 dbus_message_iter_recurse(iter, &list);
1152 dbus_message_iter_get_basic(&list, &debug_level);
1154 dbus_message_iter_next(&list);
1155 dbus_message_iter_get_basic(&list, &debug_timestamp);
1157 dbus_message_iter_next(&list);
1158 dbus_message_iter_get_basic(&list, &debug_showkeys);
1160 DBG("Debug level %d (timestamp %u show keys %u)",
1161 debug_level, debug_timestamp, debug_showkeys);
1162 } else if (g_strcmp0(key, "DebugLevel") == 0) {
1163 dbus_message_iter_get_basic(iter, &debug_level);
1164 DBG("Debug level %d", debug_level);
1165 } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
1166 dbus_message_iter_get_basic(iter, &debug_timestamp);
1167 DBG("Debug timestamp %u", debug_timestamp);
1168 } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1169 dbus_message_iter_get_basic(iter, &debug_showkeys);
1170 DBG("Debug show keys %u", debug_showkeys);
1171 } else if (g_strcmp0(key, "Interfaces") == 0) {
1172 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1173 } else if (g_strcmp0(key, "EapMethods") == 0) {
1174 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1175 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1177 DBG("key %s type %c",
1178 key, dbus_message_iter_get_arg_type(iter));
1181 static void supplicant_bootstrap(void)
1183 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1184 SUPPLICANT_INTERFACE,
1185 service_property, NULL);
1188 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1190 const char *name = NULL, *old = NULL, *new = NULL;
1192 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1195 dbus_message_iter_get_basic(iter, &name);
1199 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1202 dbus_message_iter_next(iter);
1203 dbus_message_iter_get_basic(iter, &old);
1204 dbus_message_iter_next(iter);
1205 dbus_message_iter_get_basic(iter, &new);
1207 if (old == NULL || new == NULL)
1210 if (strlen(old) > 0 && strlen(new) == 0) {
1211 system_available = FALSE;
1212 g_hash_table_remove_all(interface_table);
1213 callback_system_killed();
1216 if (strlen(new) > 0 && strlen(old) == 0) {
1217 system_available = TRUE;
1218 supplicant_bootstrap();
1222 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1224 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1227 supplicant_dbus_property_foreach(iter, service_property, NULL);
1230 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1232 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1233 interface_added(iter, NULL);
1236 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1238 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1239 interface_removed(iter, NULL);
1242 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1244 struct supplicant_interface *interface;
1245 dbus_bool_t success = FALSE;
1247 interface = g_hash_table_lookup(interface_table, path);
1248 if (interface == NULL)
1251 dbus_message_iter_get_basic(iter, &success);
1253 callback_scan_finished(interface);
1256 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1258 struct supplicant_interface *interface;
1260 interface = g_hash_table_lookup(interface_table, path);
1261 if (interface == NULL)
1264 interface_bss_added(iter, interface);
1267 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1269 struct supplicant_interface *interface;
1271 interface = g_hash_table_lookup(interface_table, path);
1272 if (interface == NULL)
1275 interface_bss_removed(iter, interface);
1278 static void signal_network_added(const char *path, DBusMessageIter *iter)
1280 struct supplicant_interface *interface;
1282 interface = g_hash_table_lookup(interface_table, path);
1283 if (interface == NULL)
1286 interface_network_added(iter, interface);
1289 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1291 struct supplicant_interface *interface;
1293 interface = g_hash_table_lookup(interface_table, path);
1294 if (interface == NULL)
1297 interface_network_removed(iter, interface);
1301 const char *interface;
1303 void (*function) (const char *path, DBusMessageIter *iter);
1305 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1307 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1308 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1309 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1310 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1312 { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done },
1313 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1314 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1315 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1316 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1321 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1322 DBusMessage *message, void *data)
1324 DBusMessageIter iter;
1328 path = dbus_message_get_path(message);
1330 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1332 if (dbus_message_iter_init(message, &iter) == FALSE)
1333 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1335 for (i = 0; signal_map[i].interface != NULL; i++) {
1336 if (dbus_message_has_interface(message,
1337 signal_map[i].interface) == FALSE)
1340 if (dbus_message_has_member(message,
1341 signal_map[i].member) == FALSE)
1344 signal_map[i].function(path, &iter);
1348 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1351 static const char *supplicant_rule0 = "type=signal,"
1352 "path=" DBUS_PATH_DBUS ","
1353 "sender=" DBUS_SERVICE_DBUS ","
1354 "interface=" DBUS_INTERFACE_DBUS ","
1355 "member=NameOwnerChanged,"
1356 "arg0=" SUPPLICANT_SERVICE;
1357 static const char *supplicant_rule1 = "type=signal,"
1358 "interface=" SUPPLICANT_INTERFACE;
1359 static const char *supplicant_rule2 = "type=signal,"
1360 "interface=" SUPPLICANT_INTERFACE ".Interface";
1361 static const char *supplicant_rule3 = "type=signal,"
1362 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1363 static const char *supplicant_rule4 = "type=signal,"
1364 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1365 static const char *supplicant_rule5 = "type=signal,"
1366 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1367 static const char *supplicant_rule6 = "type=signal,"
1368 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1370 int supplicant_register(const struct supplicant_callbacks *callbacks)
1372 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1373 if (connection == NULL)
1376 if (dbus_connection_add_filter(connection,
1377 supplicant_filter, NULL, NULL) == FALSE) {
1378 dbus_connection_unref(connection);
1383 callbacks_pointer = callbacks;
1386 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1387 NULL, remove_interface);
1389 supplicant_dbus_setup(connection);
1391 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1392 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1393 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1394 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1395 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1396 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1397 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1398 dbus_connection_flush(connection);
1400 if (dbus_bus_name_has_owner(connection,
1401 SUPPLICANT_SERVICE, NULL) == TRUE) {
1402 system_available = TRUE;
1403 supplicant_bootstrap();
1409 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1411 if (connection != NULL) {
1412 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1413 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1414 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1415 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1416 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1417 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1418 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1419 dbus_connection_flush(connection);
1421 dbus_connection_remove_filter(connection,
1422 supplicant_filter, NULL);
1425 if (interface_table != NULL) {
1426 g_hash_table_destroy(interface_table);
1427 interface_table = NULL;
1430 if (system_available == TRUE)
1431 callback_system_killed();
1433 if (connection != NULL) {
1434 dbus_connection_unref(connection);
1438 callbacks_pointer = NULL;
1442 static void debug_level_result(const char *error,
1443 DBusMessageIter *iter, void *user_data)
1446 DBG("debug level failure: %s", error);
1449 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1451 dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1452 DBusMessageIter entry;
1454 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1457 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1458 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1460 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1463 dbus_message_iter_close_container(iter, &entry);
1466 void supplicant_set_debug_level(unsigned int level)
1468 if (system_available == FALSE)
1471 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1472 "DebugParams", "(ibb)", add_debug_level,
1473 debug_level_result, GUINT_TO_POINTER(level));
1476 struct interface_create_data {
1479 struct supplicant_interface *interface;
1480 supplicant_interface_create_callback callback;
1484 static void interface_create_property(const char *key, DBusMessageIter *iter,
1487 struct interface_create_data *data = user_data;
1488 struct supplicant_interface *interface = data->interface;
1491 if (data->callback != NULL)
1492 data->callback(0, data->interface, data->user_data);
1497 interface_property(key, iter, interface);
1500 static void interface_create_result(const char *error,
1501 DBusMessageIter *iter, void *user_data)
1503 struct interface_create_data *data = user_data;
1504 const char *path = NULL;
1507 if (error != NULL) {
1512 dbus_message_iter_get_basic(iter, &path);
1518 if (system_available == FALSE) {
1523 data->interface = g_hash_table_lookup(interface_table, path);
1524 if (data->interface == NULL) {
1525 data->interface = interface_alloc(path);
1526 if (data->interface == NULL) {
1532 err = supplicant_dbus_property_get_all(path,
1533 SUPPLICANT_INTERFACE ".Interface",
1534 interface_create_property, data);
1539 if (data->callback != NULL)
1540 data->callback(err, NULL, data->user_data);
1545 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1547 struct interface_create_data *data = user_data;
1548 DBusMessageIter dict;
1550 supplicant_dbus_dict_open(iter, &dict);
1552 supplicant_dbus_dict_append_basic(&dict, "Ifname",
1553 DBUS_TYPE_STRING, &data->ifname);
1554 supplicant_dbus_dict_append_basic(&dict, "Driver",
1555 DBUS_TYPE_STRING, &data->driver);
1557 supplicant_dbus_dict_close(iter, &dict);
1560 static void interface_get_result(const char *error,
1561 DBusMessageIter *iter, void *user_data)
1563 struct interface_create_data *data = user_data;
1564 struct supplicant_interface *interface;
1565 const char *path = NULL;
1568 if (error != NULL) {
1573 dbus_message_iter_get_basic(iter, &path);
1579 interface = g_hash_table_lookup(interface_table, path);
1580 if (interface == NULL) {
1585 if (data->callback != NULL)
1586 data->callback(0, interface, data->user_data);
1593 if (system_available == FALSE) {
1598 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1599 SUPPLICANT_INTERFACE,
1601 interface_create_params,
1602 interface_create_result, data);
1607 if (data->callback != NULL)
1608 data->callback(err, NULL, data->user_data);
1613 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1615 struct interface_create_data *data = user_data;
1617 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1620 int supplicant_interface_create(const char *ifname, const char *driver,
1621 supplicant_interface_create_callback callback,
1624 struct interface_create_data *data;
1626 if (system_available == FALSE)
1629 data = dbus_malloc0(sizeof(*data));
1633 data->ifname = ifname;
1634 data->driver = driver;
1635 data->callback = callback;
1636 data->user_data = user_data;
1638 return supplicant_dbus_method_call(SUPPLICANT_PATH,
1639 SUPPLICANT_INTERFACE,
1641 interface_get_params,
1642 interface_get_result, data);
1645 int supplicant_interface_remove(struct supplicant_interface *interface,
1646 supplicant_interface_remove_callback callback,
1649 if (system_available == FALSE)
1655 static void interface_scan_result(const char *error,
1656 DBusMessageIter *iter, void *user_data)
1658 DBG("error %s", error);
1661 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
1663 DBusMessageIter dict;
1664 const char *type = "passive";
1668 supplicant_dbus_dict_open(iter, &dict);
1670 supplicant_dbus_dict_append_basic(&dict, "Type",
1671 DBUS_TYPE_STRING, &type);
1673 supplicant_dbus_dict_close(iter, &dict);
1676 int supplicant_interface_scan(struct supplicant_interface *interface)
1678 if (system_available == FALSE)
1681 return supplicant_dbus_method_call(interface->path,
1682 SUPPLICANT_INTERFACE ".Interface", "Scan",
1683 interface_scan_params, interface_scan_result, NULL);
1686 static void interface_disconnect_result(const char *error,
1687 DBusMessageIter *iter, void *user_data)
1689 DBG("error %s", error);
1692 int supplicant_interface_disconnect(struct supplicant_interface *interface)
1694 if (system_available == FALSE)
1697 return supplicant_dbus_method_call(interface->path,
1698 SUPPLICANT_INTERFACE ".Interface", "Disconnect",
1699 NULL, interface_disconnect_result, NULL);