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 *bss_mapping;
158 struct supplicant_network {
159 struct supplicant_interface *interface;
162 enum supplicant_mode mode;
163 GHashTable *bss_table;
166 struct supplicant_bss {
167 struct supplicant_interface *interface;
169 unsigned char bssid[6];
170 unsigned char ssid[32];
171 unsigned int ssid_len;
172 dbus_uint16_t frequency;
173 enum supplicant_mode mode;
174 enum supplicant_security security;
177 dbus_bool_t ieee8021x;
180 static enum supplicant_mode string2mode(const char *mode)
183 return SUPPLICANT_MODE_UNKNOWN;
185 if (g_str_equal(mode, "infrastructure") == TRUE)
186 return SUPPLICANT_MODE_INFRA;
187 else if (g_str_equal(mode, "ad-hoc") == TRUE)
188 return SUPPLICANT_MODE_IBSS;
190 return SUPPLICANT_MODE_UNKNOWN;
193 static const char *mode2string(enum supplicant_mode mode)
196 case SUPPLICANT_MODE_UNKNOWN:
198 case SUPPLICANT_MODE_INFRA:
200 case SUPPLICANT_MODE_IBSS:
207 static const char *security2string(enum supplicant_security security)
210 case SUPPLICANT_SECURITY_UNKNOWN:
212 case SUPPLICANT_SECURITY_NONE:
214 case SUPPLICANT_SECURITY_WEP:
216 case SUPPLICANT_SECURITY_PSK:
218 case SUPPLICANT_SECURITY_IEEE8021X:
225 static enum supplicant_state string2state(const char *state)
228 return SUPPLICANT_STATE_UNKNOWN;
230 if (g_str_equal(state, "unknown") == TRUE)
231 return SUPPLICANT_STATE_UNKNOWN;
232 else if (g_str_equal(state, "disconnected") == TRUE)
233 return SUPPLICANT_STATE_DISCONNECTED;
234 else if (g_str_equal(state, "inactive") == TRUE)
235 return SUPPLICANT_STATE_INACTIVE;
236 else if (g_str_equal(state, "scanning") == TRUE)
237 return SUPPLICANT_STATE_SCANNING;
238 else if (g_str_equal(state, "authenticating") == TRUE)
239 return SUPPLICANT_STATE_AUTHENTICATING;
240 else if (g_str_equal(state, "associating") == TRUE)
241 return SUPPLICANT_STATE_ASSOCIATING;
242 else if (g_str_equal(state, "associated") == TRUE)
243 return SUPPLICANT_STATE_ASSOCIATED;
244 else if (g_str_equal(state, "group_handshake") == TRUE)
245 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
246 else if (g_str_equal(state, "4way_handshake") == TRUE)
247 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
248 else if (g_str_equal(state, "completed") == TRUE)
249 return SUPPLICANT_STATE_COMPLETED;
251 return SUPPLICANT_STATE_UNKNOWN;
254 static void callback_system_ready(void)
256 if (system_ready == TRUE)
261 if (callbacks_pointer == NULL)
264 if (callbacks_pointer->system_ready == NULL)
267 callbacks_pointer->system_ready();
270 static void callback_system_killed(void)
272 system_ready = FALSE;
274 if (callbacks_pointer == NULL)
277 if (callbacks_pointer->system_killed == NULL)
280 callbacks_pointer->system_killed();
283 static void callback_interface_added(struct supplicant_interface *interface)
285 if (callbacks_pointer == NULL)
288 if (callbacks_pointer->interface_added == NULL)
291 callbacks_pointer->interface_added(interface);
294 static void callback_interface_removed(struct supplicant_interface *interface)
296 if (callbacks_pointer == NULL)
299 if (callbacks_pointer->interface_removed == NULL)
302 callbacks_pointer->interface_removed(interface);
305 static void callback_scan_started(struct supplicant_interface *interface)
307 if (callbacks_pointer == NULL)
310 if (callbacks_pointer->scan_started == NULL)
313 callbacks_pointer->scan_started(interface);
316 static void callback_scan_finished(struct supplicant_interface *interface)
318 if (callbacks_pointer == NULL)
321 if (callbacks_pointer->scan_finished == NULL)
324 callbacks_pointer->scan_finished(interface);
327 static void callback_network_added(struct supplicant_network *network)
329 if (callbacks_pointer == NULL)
332 if (callbacks_pointer->network_added == NULL)
335 callbacks_pointer->network_added(network);
338 static void callback_network_removed(struct supplicant_network *network)
340 if (callbacks_pointer == NULL)
343 if (callbacks_pointer->network_removed == NULL)
346 callbacks_pointer->network_removed(network);
349 static void remove_interface(gpointer data)
351 struct supplicant_interface *interface = data;
353 g_hash_table_destroy(interface->bss_mapping);
354 g_hash_table_destroy(interface->network_table);
356 callback_interface_removed(interface);
358 g_free(interface->path);
359 g_free(interface->ifname);
360 g_free(interface->driver);
361 g_free(interface->bridge);
365 static void remove_network(gpointer data)
367 struct supplicant_network *network = data;
369 callback_network_removed(network);
371 g_free(network->group);
372 g_free(network->name);
376 static void remove_bss(gpointer data)
378 struct supplicant_bss *bss = data;
384 static void debug_strvalmap(const char *label, struct strvalmap *map,
389 for (i = 0; map[i].str != NULL; i++) {
390 if (val & map[i].val)
391 DBG("%s: %s", label, map[i].str);
395 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
397 struct supplicant_interface *interface = user_data;
398 const char *str = NULL;
401 dbus_message_iter_get_basic(iter, &str);
405 for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
406 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
407 interface->keymgmt_capa |= keymgmt_capa_map[i].val;
412 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
414 struct supplicant_interface *interface = user_data;
415 const char *str = NULL;
418 dbus_message_iter_get_basic(iter, &str);
422 for (i = 0; authalg_capa_map[i].str != NULL; i++)
423 if (strcmp(str, authalg_capa_map[i].str) == 0) {
424 interface->authalg_capa |= authalg_capa_map[i].val;
429 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
431 struct supplicant_interface *interface = user_data;
432 const char *str = NULL;
435 dbus_message_iter_get_basic(iter, &str);
439 for (i = 0; proto_capa_map[i].str != NULL; i++)
440 if (strcmp(str, proto_capa_map[i].str) == 0) {
441 interface->proto_capa |= proto_capa_map[i].val;
446 static void interface_capability_pairwise(DBusMessageIter *iter, void *user_data)
448 struct supplicant_interface *interface = user_data;
449 const char *str = NULL;
452 dbus_message_iter_get_basic(iter, &str);
456 for (i = 0; pairwise_capa_map[i].str != NULL; i++)
457 if (strcmp(str, pairwise_capa_map[i].str) == 0) {
458 interface->pairwise_capa |= pairwise_capa_map[i].val;
463 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
465 struct supplicant_interface *interface = user_data;
466 const char *str = NULL;
469 dbus_message_iter_get_basic(iter, &str);
473 for (i = 0; group_capa_map[i].str != NULL; i++)
474 if (strcmp(str, group_capa_map[i].str) == 0) {
475 interface->group_capa |= group_capa_map[i].val;
480 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
482 struct supplicant_interface *interface = user_data;
483 const char *str = NULL;
486 dbus_message_iter_get_basic(iter, &str);
490 for (i = 0; scan_capa_map[i].str != NULL; i++)
491 if (strcmp(str, scan_capa_map[i].str) == 0) {
492 interface->scan_capa |= scan_capa_map[i].val;
497 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
499 struct supplicant_interface *interface = user_data;
500 const char *str = NULL;
503 dbus_message_iter_get_basic(iter, &str);
507 for (i = 0; mode_capa_map[i].str != NULL; i++)
508 if (strcmp(str, mode_capa_map[i].str) == 0) {
509 interface->mode_capa |= mode_capa_map[i].val;
514 static void interface_capability(const char *key, DBusMessageIter *iter,
517 struct supplicant_interface *interface = user_data;
522 if (g_strcmp0(key, "KeyMgmt") == 0)
523 supplicant_dbus_array_foreach(iter,
524 interface_capability_keymgmt, interface);
525 else if (g_strcmp0(key, "AuthAlg") == 0)
526 supplicant_dbus_array_foreach(iter,
527 interface_capability_authalg, interface);
528 else if (g_strcmp0(key, "Protocol") == 0)
529 supplicant_dbus_array_foreach(iter,
530 interface_capability_proto, interface);
531 else if (g_strcmp0(key, "Pairwise") == 0)
532 supplicant_dbus_array_foreach(iter,
533 interface_capability_pairwise, interface);
534 else if (g_strcmp0(key, "Group") == 0)
535 supplicant_dbus_array_foreach(iter,
536 interface_capability_group, interface);
537 else if (g_strcmp0(key, "Scan") == 0)
538 supplicant_dbus_array_foreach(iter,
539 interface_capability_scan, interface);
540 else if (g_strcmp0(key, "Modes") == 0)
541 supplicant_dbus_array_foreach(iter,
542 interface_capability_mode, interface);
544 DBG("key %s type %c",
545 key, dbus_message_iter_get_arg_type(iter));
548 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
550 if (interface == NULL)
553 return interface->ifname;
556 const char *supplicant_interface_get_driver(struct supplicant_interface *interface)
558 if (interface == NULL)
561 return interface->driver;
564 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
569 return network->interface;
572 const char *supplicant_network_get_name(struct supplicant_network *network)
574 if (network == NULL || network->name == NULL)
577 return network->name;
580 const char *supplicant_network_get_identifier(struct supplicant_network *network)
582 if (network == NULL || network->group == NULL)
585 return network->group;
588 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
591 return SUPPLICANT_MODE_UNKNOWN;
593 return network->mode;
596 static void network_property(const char *key, DBusMessageIter *iter,
602 //DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
605 static void interface_network_added(DBusMessageIter *iter, void *user_data)
607 //struct supplicant_interface *interface = user_data;
608 const char *path = NULL;
610 dbus_message_iter_get_basic(iter, &path);
614 if (g_strcmp0(path, "/") == 0)
617 dbus_message_iter_next(iter);
618 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
619 supplicant_dbus_property_foreach(iter, network_property, NULL);
620 network_property(NULL, NULL, NULL);
624 DBG("path %s", path);
626 supplicant_dbus_property_get_all(path,
627 SUPPLICANT_INTERFACE ".Interface.Network",
628 network_property, NULL);
631 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
633 const char *path = NULL;
635 dbus_message_iter_get_basic(iter, &path);
639 DBG("path %s", path);
642 static char *create_name(unsigned char *ssid, int ssid_len)
647 if (ssid_len < 1 || ssid[0] == '\0')
650 name = g_try_malloc0(ssid_len + 1);
655 for (i = 0; i < ssid_len; i++) {
656 if (g_ascii_isprint(ssid[i]))
665 static char *create_group(struct supplicant_bss *bss)
669 const char *mode, *security;
671 str = g_string_sized_new((bss->ssid_len * 2) + 24);
675 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
676 for (i = 0; i < bss->ssid_len; i++)
677 g_string_append_printf(str, "%02x", bss->ssid[i]);
679 g_string_append_printf(str, "hidden");
681 mode = mode2string(bss->mode);
683 g_string_append_printf(str, "_%s", mode);
685 security = security2string(bss->security);
686 if (security != NULL)
687 g_string_append_printf(str, "_%s", security);
689 return g_string_free(str, FALSE);
692 static void add_bss_to_network(struct supplicant_bss *bss)
694 struct supplicant_interface *interface = bss->interface;
695 struct supplicant_network *network;
698 group = create_group(bss);
702 network = g_hash_table_lookup(interface->network_table, group);
703 if (network != NULL) {
708 network = g_try_new0(struct supplicant_network, 1);
709 if (network == NULL) {
714 network->group = group;
715 network->name = create_name(bss->ssid, bss->ssid_len);
716 network->mode = bss->mode;
718 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
721 g_hash_table_replace(interface->network_table,
722 network->group, network);
724 callback_network_added(network);
727 g_hash_table_replace(interface->bss_mapping, bss->path, network);
728 g_hash_table_replace(network->bss_table, bss->path, bss);
731 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
732 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
734 static void extract_rsn(struct supplicant_bss *bss,
735 const unsigned char *buf, int len)
754 /* Pairwise cipher */
758 count = buf[0] | (buf[1] << 8);
759 if (2 + (count * 4) > len)
762 buf += 2 + (count * 4);
763 len -= 2 + (count * 4);
769 count = buf[0] | (buf[1] << 8);
770 if (2 + (count * 4) > len)
773 for (i = 0; i < count; i++) {
774 const unsigned char *ptr = buf + 2 + (i * 4);
776 if (memcmp(ptr, wifi_oui, 3) == 0) {
779 bss->ieee8021x = TRUE;
785 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
788 bss->ieee8021x = TRUE;
797 buf += 2 + (count * 4);
798 len -= 2 + (count * 4);
801 static void bss_property(const char *key, DBusMessageIter *iter,
804 struct supplicant_bss *bss = user_data;
806 if (bss->interface == NULL)
810 if (bss->ieee8021x == TRUE)
811 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
812 else if (bss->psk == TRUE)
813 bss->security = SUPPLICANT_SECURITY_PSK;
814 else if (bss->privacy == TRUE)
815 bss->security = SUPPLICANT_SECURITY_WEP;
817 bss->security = SUPPLICANT_SECURITY_NONE;
819 add_bss_to_network(bss);
823 if (g_strcmp0(key, "BSSID") == 0) {
824 DBusMessageIter array;
828 dbus_message_iter_recurse(iter, &array);
829 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
832 memcpy(bss->bssid, addr, addr_len);
833 } else if (g_strcmp0(key, "SSID") == 0) {
834 DBusMessageIter array;
838 dbus_message_iter_recurse(iter, &array);
839 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
841 if (ssid_len > 0 && ssid_len < 33) {
842 memcpy(bss->ssid, ssid, ssid_len);
843 bss->ssid_len = ssid_len;
845 memset(bss->ssid, 0, sizeof(bss->ssid));
848 } else if (g_strcmp0(key, "Capabilities") == 0) {
849 dbus_uint16_t capabilities = 0x0000;
851 dbus_message_iter_get_basic(iter, &capabilities);
853 if (capabilities & IEEE80211_CAP_ESS)
854 bss->mode = SUPPLICANT_MODE_INFRA;
855 else if (capabilities & IEEE80211_CAP_IBSS)
856 bss->mode = SUPPLICANT_MODE_IBSS;
858 if (capabilities & IEEE80211_CAP_PRIVACY)
860 } else if (g_strcmp0(key, "Mode") == 0) {
861 const char *mode = NULL;
863 dbus_message_iter_get_basic(iter, &mode);
864 bss->mode = string2mode(mode);
865 } else if (g_strcmp0(key, "Frequency") == 0) {
866 dbus_uint16_t frequency = 0;
868 dbus_message_iter_get_basic(iter, &frequency);
869 bss->frequency = frequency;
870 } else if (g_strcmp0(key, "Signal") == 0) {
871 dbus_int16_t signal = 0;
873 dbus_message_iter_get_basic(iter, &signal);
874 } else if (g_strcmp0(key, "Level") == 0) {
875 dbus_int32_t level = 0;
877 dbus_message_iter_get_basic(iter, &level);
878 } else if (g_strcmp0(key, "MaxRate") == 0) {
879 dbus_uint16_t maxrate = 0;
881 dbus_message_iter_get_basic(iter, &maxrate);
882 } else if (g_strcmp0(key, "Privacy") == 0) {
883 dbus_bool_t privacy = FALSE;
885 dbus_message_iter_get_basic(iter, &privacy);
886 bss->privacy = privacy;
887 } else if (g_strcmp0(key, "RSNIE") == 0) {
888 DBusMessageIter array;
892 dbus_message_iter_recurse(iter, &array);
893 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
896 extract_rsn(bss, ie + 2, ie_len - 2);
897 } else if (g_strcmp0(key, "WPAIE") == 0) {
898 DBusMessageIter array;
902 dbus_message_iter_recurse(iter, &array);
903 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
906 extract_rsn(bss, ie + 6, ie_len - 6);
907 } else if (g_strcmp0(key, "WPSIE") == 0) {
908 DBusMessageIter array;
912 dbus_message_iter_recurse(iter, &array);
913 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
915 DBG("key %s type %c",
916 key, dbus_message_iter_get_arg_type(iter));
919 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
921 struct supplicant_interface *interface = user_data;
922 struct supplicant_network *network;
923 struct supplicant_bss *bss;
924 const char *path = NULL;
926 dbus_message_iter_get_basic(iter, &path);
930 if (g_strcmp0(path, "/") == 0)
933 network = g_hash_table_lookup(interface->bss_mapping, path);
934 if (network != NULL) {
935 bss = g_hash_table_lookup(network->bss_table, path);
940 bss = g_try_new0(struct supplicant_bss, 1);
944 bss->interface = interface;
945 bss->path = g_strdup(path);
947 dbus_message_iter_next(iter);
948 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
949 supplicant_dbus_property_foreach(iter, bss_property, bss);
950 bss_property(NULL, NULL, bss);
954 supplicant_dbus_property_get_all(path,
955 SUPPLICANT_INTERFACE ".Interface.BSS",
959 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
961 struct supplicant_interface *interface = user_data;
962 struct supplicant_network *network;
963 const char *path = NULL;
965 dbus_message_iter_get_basic(iter, &path);
969 network = g_hash_table_lookup(interface->bss_mapping, path);
973 g_hash_table_remove(interface->bss_mapping, path);
974 g_hash_table_remove(network->bss_table, path);
976 if (g_hash_table_size(network->bss_table) == 0)
977 g_hash_table_remove(interface->network_table, network->group);
980 static void interface_property(const char *key, DBusMessageIter *iter,
983 struct supplicant_interface *interface = user_data;
985 if (interface == NULL)
989 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
990 interface->keymgmt_capa);
991 debug_strvalmap("AuthAlg capability", authalg_capa_map,
992 interface->authalg_capa);
993 debug_strvalmap("Protocol capability", proto_capa_map,
994 interface->proto_capa);
995 debug_strvalmap("Pairwise capability", pairwise_capa_map,
996 interface->pairwise_capa);
997 debug_strvalmap("Group capability", group_capa_map,
998 interface->group_capa);
999 debug_strvalmap("Scan capability", scan_capa_map,
1000 interface->scan_capa);
1001 debug_strvalmap("Mode capability", mode_capa_map,
1002 interface->mode_capa);
1004 interface->ready = TRUE;
1005 callback_interface_added(interface);
1009 if (g_strcmp0(key, "Capabilities") == 0) {
1010 supplicant_dbus_property_foreach(iter, interface_capability,
1012 } else if (g_strcmp0(key, "State") == 0) {
1013 const char *str = NULL;
1015 dbus_message_iter_get_basic(iter, &str);
1017 interface->state = string2state(str);
1019 DBG("state %s (%d)", str, interface->state);
1020 } else if (g_strcmp0(key, "Scanning") == 0) {
1021 dbus_bool_t scanning = FALSE;
1023 dbus_message_iter_get_basic(iter, &scanning);
1024 interface->scanning = scanning;
1026 if (interface->ready == TRUE) {
1027 if (interface->scanning == TRUE)
1028 callback_scan_started(interface);
1030 callback_scan_finished(interface);
1032 } else if (g_strcmp0(key, "ApScan") == 0) {
1035 dbus_message_iter_get_basic(iter, &apscan);
1036 interface->apscan = apscan;
1037 } else if (g_strcmp0(key, "Ifname") == 0) {
1038 const char *str = NULL;
1040 dbus_message_iter_get_basic(iter, &str);
1042 interface->ifname = g_strdup(str);
1043 } else if (g_strcmp0(key, "Driver") == 0) {
1044 const char *str = NULL;
1046 dbus_message_iter_get_basic(iter, &str);
1048 interface->driver = g_strdup(str);
1049 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1050 const char *str = NULL;
1052 dbus_message_iter_get_basic(iter, &str);
1054 interface->bridge = g_strdup(str);
1055 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1056 interface_bss_added(iter, interface);
1057 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1058 interface_network_added(iter, interface);
1059 } else if (g_strcmp0(key, "BSSs") == 0) {
1060 supplicant_dbus_array_foreach(iter, interface_bss_added,
1062 } else if (g_strcmp0(key, "Blobs") == 0) {
1063 } else if (g_strcmp0(key, "Networks") == 0) {
1064 supplicant_dbus_array_foreach(iter, interface_network_added,
1067 DBG("key %s type %c",
1068 key, dbus_message_iter_get_arg_type(iter));
1071 static struct supplicant_interface *interface_alloc(const char *path)
1073 struct supplicant_interface *interface;
1075 interface = g_try_new0(struct supplicant_interface, 1);
1076 if (interface == NULL)
1079 interface->path = g_strdup(path);
1081 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1082 NULL, remove_network);
1084 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1087 g_hash_table_replace(interface_table, interface->path, interface);
1092 static void interface_added(DBusMessageIter *iter, void *user_data)
1094 struct supplicant_interface *interface;
1095 const char *path = NULL;
1097 dbus_message_iter_get_basic(iter, &path);
1101 if (g_strcmp0(path, "/") == 0)
1104 interface = g_hash_table_lookup(interface_table, path);
1105 if (interface != NULL)
1108 interface = interface_alloc(path);
1109 if (interface == NULL)
1112 dbus_message_iter_next(iter);
1113 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1114 supplicant_dbus_property_foreach(iter, interface_property,
1116 interface_property(NULL, NULL, interface);
1120 supplicant_dbus_property_get_all(path,
1121 SUPPLICANT_INTERFACE ".Interface",
1122 interface_property, interface);
1125 static void interface_removed(DBusMessageIter *iter, void *user_data)
1127 const char *path = NULL;
1129 dbus_message_iter_get_basic(iter, &path);
1133 g_hash_table_remove(interface_table, path);
1136 static void eap_method(DBusMessageIter *iter, void *user_data)
1138 const char *str = NULL;
1141 dbus_message_iter_get_basic(iter, &str);
1145 for (i = 0; eap_method_map[i].str != NULL; i++)
1146 if (strcmp(str, eap_method_map[i].str) == 0) {
1147 eap_methods |= eap_method_map[i].val;
1152 static void service_property(const char *key, DBusMessageIter *iter,
1156 callback_system_ready();
1160 if (g_strcmp0(key, "DebugLevel") == 0) {
1161 const char *str = NULL;
1164 dbus_message_iter_get_basic(iter, &str);
1165 for (i = 0; debug_strings[i] != NULL; i++)
1166 if (g_strcmp0(debug_strings[i], str) == 0) {
1170 DBG("Debug level %d", debug_level);
1171 } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
1172 dbus_message_iter_get_basic(iter, &debug_timestamp);
1173 DBG("Debug timestamp %u", debug_timestamp);
1174 } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1175 dbus_message_iter_get_basic(iter, &debug_showkeys);
1176 DBG("Debug show keys %u", debug_showkeys);
1177 } else if (g_strcmp0(key, "Interfaces") == 0) {
1178 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1179 } else if (g_strcmp0(key, "EapMethods") == 0) {
1180 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1181 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1183 DBG("key %s type %c",
1184 key, dbus_message_iter_get_arg_type(iter));
1187 static void supplicant_bootstrap(void)
1189 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1190 SUPPLICANT_INTERFACE,
1191 service_property, NULL);
1194 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1196 const char *name = NULL, *old = NULL, *new = NULL;
1198 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1201 dbus_message_iter_get_basic(iter, &name);
1205 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1208 dbus_message_iter_next(iter);
1209 dbus_message_iter_get_basic(iter, &old);
1210 dbus_message_iter_next(iter);
1211 dbus_message_iter_get_basic(iter, &new);
1213 if (old == NULL || new == NULL)
1216 if (strlen(old) > 0 && strlen(new) == 0) {
1217 system_available = FALSE;
1218 g_hash_table_remove_all(interface_table);
1219 callback_system_killed();
1222 if (strlen(new) > 0 && strlen(old) == 0) {
1223 system_available = TRUE;
1224 supplicant_bootstrap();
1228 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1230 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1233 supplicant_dbus_property_foreach(iter, service_property, NULL);
1236 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1238 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1239 interface_added(iter, NULL);
1242 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1244 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1245 interface_removed(iter, NULL);
1248 static void signal_properties(const char *path, DBusMessageIter *iter)
1250 struct supplicant_interface *interface;
1252 interface = g_hash_table_lookup(interface_table, path);
1253 if (interface == NULL)
1256 supplicant_dbus_property_foreach(iter, interface_property, interface);
1259 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1261 struct supplicant_interface *interface;
1262 dbus_bool_t success = FALSE;
1264 interface = g_hash_table_lookup(interface_table, path);
1265 if (interface == NULL)
1268 dbus_message_iter_get_basic(iter, &success);
1270 if (interface->scan_callback != NULL) {
1273 if (success == FALSE)
1276 interface->scan_callback(result, interface->scan_data);
1279 interface->scan_callback = NULL;
1280 interface->scan_data = NULL;
1283 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1285 struct supplicant_interface *interface;
1287 interface = g_hash_table_lookup(interface_table, path);
1288 if (interface == NULL)
1291 interface_bss_added(iter, interface);
1294 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1296 struct supplicant_interface *interface;
1298 interface = g_hash_table_lookup(interface_table, path);
1299 if (interface == NULL)
1302 interface_bss_removed(iter, interface);
1305 static void signal_network_added(const char *path, DBusMessageIter *iter)
1307 struct supplicant_interface *interface;
1309 interface = g_hash_table_lookup(interface_table, path);
1310 if (interface == NULL)
1313 interface_network_added(iter, interface);
1316 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1318 struct supplicant_interface *interface;
1320 interface = g_hash_table_lookup(interface_table, path);
1321 if (interface == NULL)
1324 interface_network_removed(iter, interface);
1328 const char *interface;
1330 void (*function) (const char *path, DBusMessageIter *iter);
1332 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1334 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1335 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1336 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1337 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1339 { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_properties },
1340 { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done },
1341 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1342 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1343 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1344 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1349 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1350 DBusMessage *message, void *data)
1352 DBusMessageIter iter;
1356 path = dbus_message_get_path(message);
1358 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1360 if (dbus_message_iter_init(message, &iter) == FALSE)
1361 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1363 for (i = 0; signal_map[i].interface != NULL; i++) {
1364 if (dbus_message_has_interface(message,
1365 signal_map[i].interface) == FALSE)
1368 if (dbus_message_has_member(message,
1369 signal_map[i].member) == FALSE)
1372 signal_map[i].function(path, &iter);
1376 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1379 static const char *supplicant_rule0 = "type=signal,"
1380 "path=" DBUS_PATH_DBUS ","
1381 "sender=" DBUS_SERVICE_DBUS ","
1382 "interface=" DBUS_INTERFACE_DBUS ","
1383 "member=NameOwnerChanged,"
1384 "arg0=" SUPPLICANT_SERVICE;
1385 static const char *supplicant_rule1 = "type=signal,"
1386 "interface=" SUPPLICANT_INTERFACE;
1387 static const char *supplicant_rule2 = "type=signal,"
1388 "interface=" SUPPLICANT_INTERFACE ".Interface";
1389 static const char *supplicant_rule3 = "type=signal,"
1390 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1391 static const char *supplicant_rule4 = "type=signal,"
1392 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1393 static const char *supplicant_rule5 = "type=signal,"
1394 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1395 static const char *supplicant_rule6 = "type=signal,"
1396 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1398 int supplicant_register(const struct supplicant_callbacks *callbacks)
1400 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1401 if (connection == NULL)
1404 if (dbus_connection_add_filter(connection,
1405 supplicant_filter, NULL, NULL) == FALSE) {
1406 dbus_connection_unref(connection);
1411 callbacks_pointer = callbacks;
1414 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1415 NULL, remove_interface);
1417 supplicant_dbus_setup(connection);
1419 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1420 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1421 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1422 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1423 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1424 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1425 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1426 dbus_connection_flush(connection);
1428 if (dbus_bus_name_has_owner(connection,
1429 SUPPLICANT_SERVICE, NULL) == TRUE) {
1430 system_available = TRUE;
1431 supplicant_bootstrap();
1437 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1439 if (connection != NULL) {
1440 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1441 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1442 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1443 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1444 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1445 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1446 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1447 dbus_connection_flush(connection);
1449 dbus_connection_remove_filter(connection,
1450 supplicant_filter, NULL);
1453 if (interface_table != NULL) {
1454 g_hash_table_destroy(interface_table);
1455 interface_table = NULL;
1458 if (system_available == TRUE)
1459 callback_system_killed();
1461 if (connection != NULL) {
1462 dbus_connection_unref(connection);
1466 callbacks_pointer = NULL;
1470 static void debug_level_result(const char *error,
1471 DBusMessageIter *iter, void *user_data)
1474 DBG("debug level failure: %s", error);
1477 static void debug_level_params(DBusMessageIter *iter, void *user_data)
1479 guint level = GPOINTER_TO_UINT(user_data);
1485 str = debug_strings[level];
1487 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
1490 void supplicant_set_debug_level(unsigned int level)
1492 if (system_available == FALSE)
1495 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1496 "DebugLevel", DBUS_TYPE_STRING_AS_STRING,
1497 debug_level_params, debug_level_result,
1498 GUINT_TO_POINTER(level));
1501 struct interface_create_data {
1504 struct supplicant_interface *interface;
1505 supplicant_interface_create_callback callback;
1509 static void interface_create_property(const char *key, DBusMessageIter *iter,
1512 struct interface_create_data *data = user_data;
1513 struct supplicant_interface *interface = data->interface;
1516 if (data->callback != NULL)
1517 data->callback(0, data->interface, data->user_data);
1522 interface_property(key, iter, interface);
1525 static void interface_create_result(const char *error,
1526 DBusMessageIter *iter, void *user_data)
1528 struct interface_create_data *data = user_data;
1529 const char *path = NULL;
1532 if (error != NULL) {
1537 dbus_message_iter_get_basic(iter, &path);
1543 if (system_available == FALSE) {
1548 data->interface = g_hash_table_lookup(interface_table, path);
1549 if (data->interface == NULL) {
1550 data->interface = interface_alloc(path);
1551 if (data->interface == NULL) {
1557 err = supplicant_dbus_property_get_all(path,
1558 SUPPLICANT_INTERFACE ".Interface",
1559 interface_create_property, data);
1564 if (data->callback != NULL)
1565 data->callback(err, NULL, data->user_data);
1570 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1572 struct interface_create_data *data = user_data;
1573 DBusMessageIter dict;
1575 supplicant_dbus_dict_open(iter, &dict);
1577 supplicant_dbus_dict_append_basic(&dict, "Ifname",
1578 DBUS_TYPE_STRING, &data->ifname);
1580 if (data->driver != NULL)
1581 supplicant_dbus_dict_append_basic(&dict, "Driver",
1582 DBUS_TYPE_STRING, &data->driver);
1584 supplicant_dbus_dict_close(iter, &dict);
1587 static void interface_get_result(const char *error,
1588 DBusMessageIter *iter, void *user_data)
1590 struct interface_create_data *data = user_data;
1591 struct supplicant_interface *interface;
1592 const char *path = NULL;
1595 if (error != NULL) {
1600 dbus_message_iter_get_basic(iter, &path);
1606 interface = g_hash_table_lookup(interface_table, path);
1607 if (interface == NULL) {
1612 if (data->callback != NULL)
1613 data->callback(0, interface, data->user_data);
1620 if (system_available == FALSE) {
1625 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1626 SUPPLICANT_INTERFACE,
1628 interface_create_params,
1629 interface_create_result, data);
1634 if (data->callback != NULL)
1635 data->callback(err, NULL, data->user_data);
1640 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1642 struct interface_create_data *data = user_data;
1644 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1647 int supplicant_interface_create(const char *ifname, const char *driver,
1648 supplicant_interface_create_callback callback,
1651 struct interface_create_data *data;
1656 if (system_available == FALSE)
1659 data = dbus_malloc0(sizeof(*data));
1663 data->ifname = ifname;
1664 data->driver = driver;
1665 data->callback = callback;
1666 data->user_data = user_data;
1668 return supplicant_dbus_method_call(SUPPLICANT_PATH,
1669 SUPPLICANT_INTERFACE,
1671 interface_get_params,
1672 interface_get_result, data);
1675 int supplicant_interface_remove(struct supplicant_interface *interface,
1676 supplicant_interface_remove_callback callback,
1679 if (interface == NULL)
1682 if (system_available == FALSE)
1688 struct interface_scan_data {
1689 struct supplicant_interface *interface;
1690 supplicant_interface_scan_callback callback;
1694 static void interface_scan_result(const char *error,
1695 DBusMessageIter *iter, void *user_data)
1697 struct interface_scan_data *data = user_data;
1699 if (error != NULL) {
1700 if (data->callback != NULL)
1701 data->callback(-EIO, data->user_data);
1703 data->interface->scan_callback = data->callback;
1704 data->interface->scan_data = data->user_data;
1710 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
1712 DBusMessageIter dict;
1713 const char *type = "passive";
1715 supplicant_dbus_dict_open(iter, &dict);
1717 supplicant_dbus_dict_append_basic(&dict, "Type",
1718 DBUS_TYPE_STRING, &type);
1720 supplicant_dbus_dict_close(iter, &dict);
1723 int supplicant_interface_scan(struct supplicant_interface *interface,
1724 supplicant_interface_scan_callback callback,
1727 struct interface_scan_data *data;
1729 if (interface == NULL)
1732 if (system_available == FALSE)
1735 if (interface->scanning == TRUE)
1738 data = dbus_malloc0(sizeof(*data));
1742 data->interface = interface;
1743 data->callback = callback;
1744 data->user_data = user_data;
1746 return supplicant_dbus_method_call(interface->path,
1747 SUPPLICANT_INTERFACE ".Interface", "Scan",
1748 interface_scan_params, interface_scan_result, data);
1751 struct interface_disconnect_data {
1752 supplicant_interface_disconnect_callback callback;
1756 static void interface_disconnect_result(const char *error,
1757 DBusMessageIter *iter, void *user_data)
1759 struct interface_disconnect_data *data = user_data;
1765 if (data->callback != NULL)
1766 data->callback(result, data->user_data);
1771 int supplicant_interface_disconnect(struct supplicant_interface *interface,
1772 supplicant_interface_disconnect_callback callback,
1775 struct interface_disconnect_data *data;
1777 if (interface == NULL)
1780 if (system_available == FALSE)
1783 data = dbus_malloc0(sizeof(*data));
1787 data->callback = callback;
1788 data->user_data = user_data;
1790 return supplicant_dbus_method_call(interface->path,
1791 SUPPLICANT_INTERFACE ".Interface", "Disconnect",
1792 NULL, interface_disconnect_result, data);