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 },
77 static struct strvalmap keymgmt_capa_map[] = {
78 { "none", SUPPLICANT_CAPABILITY_KEYMGMT_NONE },
79 { "ieee8021x", SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X },
80 { "wpa-none", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE },
81 { "wpa-psk", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK },
82 { "wpa-eap", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP },
83 { "wps", SUPPLICANT_CAPABILITY_KEYMGMT_WPS },
87 static struct strvalmap authalg_capa_map[] = {
88 { "open", SUPPLICANT_CAPABILITY_AUTHALG_OPEN },
89 { "shared", SUPPLICANT_CAPABILITY_AUTHALG_SHARED },
90 { "leap", SUPPLICANT_CAPABILITY_AUTHALG_LEAP },
94 static struct strvalmap proto_capa_map[] = {
95 { "wpa", SUPPLICANT_CAPABILITY_PROTO_WPA },
96 { "rsn", SUPPLICANT_CAPABILITY_PROTO_RSN },
100 static struct strvalmap scan_capa_map[] = {
101 { "active", SUPPLICANT_CAPABILITY_SCAN_ACTIVE },
102 { "passive", SUPPLICANT_CAPABILITY_SCAN_PASSIVE },
103 { "ssid", SUPPLICANT_CAPABILITY_SCAN_SSID },
107 static struct strvalmap mode_capa_map[] = {
108 { "infrastructure", SUPPLICANT_CAPABILITY_MODE_INFRA },
109 { "ad-hoc", SUPPLICANT_CAPABILITY_MODE_IBSS },
110 { "ap", SUPPLICANT_CAPABILITY_MODE_AP },
114 static GHashTable *interface_table;
116 struct supplicant_interface {
118 unsigned int keymgmt_capa;
119 unsigned int authalg_capa;
120 unsigned int proto_capa;
121 unsigned int scan_capa;
122 unsigned int mode_capa;
123 enum supplicant_state state;
124 dbus_bool_t scanning;
129 GHashTable *network_table;
130 GHashTable *bss_mapping;
133 struct supplicant_network {
134 struct supplicant_interface *interface;
137 enum supplicant_mode mode;
138 GHashTable *bss_table;
141 struct supplicant_bss {
142 struct supplicant_interface *interface;
144 unsigned char bssid[6];
145 unsigned char ssid[32];
146 unsigned int ssid_len;
147 dbus_uint16_t frequency;
148 enum supplicant_mode mode;
149 enum supplicant_security security;
152 dbus_bool_t ieee8021x;
155 static enum supplicant_mode string2mode(const char *mode)
158 return SUPPLICANT_MODE_UNKNOWN;
160 if (g_str_equal(mode, "infrastructure") == TRUE)
161 return SUPPLICANT_MODE_INFRA;
162 else if (g_str_equal(mode, "ad-hoc") == TRUE)
163 return SUPPLICANT_MODE_IBSS;
165 return SUPPLICANT_MODE_UNKNOWN;
168 static const char *mode2string(enum supplicant_mode mode)
171 case SUPPLICANT_MODE_UNKNOWN:
173 case SUPPLICANT_MODE_INFRA:
175 case SUPPLICANT_MODE_IBSS:
182 static const char *security2string(enum supplicant_security security)
185 case SUPPLICANT_SECURITY_UNKNOWN:
187 case SUPPLICANT_SECURITY_NONE:
189 case SUPPLICANT_SECURITY_WEP:
191 case SUPPLICANT_SECURITY_PSK:
193 case SUPPLICANT_SECURITY_IEEE8021X:
200 static enum supplicant_state string2state(const char *state)
203 return SUPPLICANT_STATE_UNKNOWN;
205 if (g_str_equal(state, "unknown") == TRUE)
206 return SUPPLICANT_STATE_UNKNOWN;
207 else if (g_str_equal(state, "disconnected") == TRUE)
208 return SUPPLICANT_STATE_DISCONNECTED;
209 else if (g_str_equal(state, "inactive") == TRUE)
210 return SUPPLICANT_STATE_INACTIVE;
211 else if (g_str_equal(state, "scanning") == TRUE)
212 return SUPPLICANT_STATE_SCANNING;
213 else if (g_str_equal(state, "authenticating") == TRUE)
214 return SUPPLICANT_STATE_AUTHENTICATING;
215 else if (g_str_equal(state, "associating") == TRUE)
216 return SUPPLICANT_STATE_ASSOCIATING;
217 else if (g_str_equal(state, "associated") == TRUE)
218 return SUPPLICANT_STATE_ASSOCIATED;
219 else if (g_str_equal(state, "group_handshake") == TRUE)
220 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
221 else if (g_str_equal(state, "4way_handshake") == TRUE)
222 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
223 else if (g_str_equal(state, "completed") == TRUE)
224 return SUPPLICANT_STATE_COMPLETED;
226 return SUPPLICANT_STATE_UNKNOWN;
229 static void callback_system_ready(void)
231 if (system_ready == TRUE)
236 if (callbacks_pointer == NULL)
239 if (callbacks_pointer->system_ready == NULL)
242 callbacks_pointer->system_ready();
245 static void callback_system_killed(void)
247 system_ready = FALSE;
249 if (callbacks_pointer == NULL)
252 if (callbacks_pointer->system_killed == NULL)
255 callbacks_pointer->system_killed();
258 static void callback_interface_added(struct supplicant_interface *interface)
260 if (callbacks_pointer == NULL)
263 if (callbacks_pointer->interface_added == NULL)
266 callbacks_pointer->interface_added(interface);
269 static void callback_interface_removed(struct supplicant_interface *interface)
271 if (callbacks_pointer == NULL)
274 if (callbacks_pointer->interface_removed == NULL)
277 callbacks_pointer->interface_removed(interface);
280 static void callback_network_added(struct supplicant_network *network)
282 if (callbacks_pointer == NULL)
285 if (callbacks_pointer->network_added == NULL)
288 callbacks_pointer->network_added(network);
291 static void callback_network_removed(struct supplicant_network *network)
293 if (callbacks_pointer == NULL)
296 if (callbacks_pointer->network_removed == NULL)
299 callbacks_pointer->network_removed(network);
302 static void remove_interface(gpointer data)
304 struct supplicant_interface *interface = data;
306 g_hash_table_destroy(interface->bss_mapping);
307 g_hash_table_destroy(interface->network_table);
309 callback_interface_removed(interface);
311 g_free(interface->path);
312 g_free(interface->ifname);
313 g_free(interface->driver);
314 g_free(interface->bridge);
318 static void remove_network(gpointer data)
320 struct supplicant_network *network = data;
322 callback_network_removed(network);
324 g_free(network->group);
325 g_free(network->name);
329 static void remove_bss(gpointer data)
331 struct supplicant_bss *bss = data;
337 static void debug_strvalmap(const char *label, struct strvalmap *map,
342 for (i = 0; map[i].str != NULL; i++) {
343 if (val & map[i].val)
344 DBG("%s: %s", label, map[i].str);
348 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
350 struct supplicant_interface *interface = user_data;
351 const char *str = NULL;
354 dbus_message_iter_get_basic(iter, &str);
358 for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
359 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
360 interface->keymgmt_capa |= keymgmt_capa_map[i].val;
365 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
367 struct supplicant_interface *interface = user_data;
368 const char *str = NULL;
371 dbus_message_iter_get_basic(iter, &str);
375 for (i = 0; authalg_capa_map[i].str != NULL; i++)
376 if (strcmp(str, authalg_capa_map[i].str) == 0) {
377 interface->authalg_capa |= authalg_capa_map[i].val;
382 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
384 struct supplicant_interface *interface = user_data;
385 const char *str = NULL;
388 dbus_message_iter_get_basic(iter, &str);
392 for (i = 0; proto_capa_map[i].str != NULL; i++)
393 if (strcmp(str, proto_capa_map[i].str) == 0) {
394 interface->proto_capa |= proto_capa_map[i].val;
399 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
401 struct supplicant_interface *interface = user_data;
402 const char *str = NULL;
405 dbus_message_iter_get_basic(iter, &str);
409 for (i = 0; scan_capa_map[i].str != NULL; i++)
410 if (strcmp(str, scan_capa_map[i].str) == 0) {
411 interface->scan_capa |= scan_capa_map[i].val;
416 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
418 struct supplicant_interface *interface = user_data;
419 const char *str = NULL;
422 dbus_message_iter_get_basic(iter, &str);
426 for (i = 0; mode_capa_map[i].str != NULL; i++)
427 if (strcmp(str, mode_capa_map[i].str) == 0) {
428 interface->mode_capa |= mode_capa_map[i].val;
433 static void interface_capability(const char *key, DBusMessageIter *iter,
436 struct supplicant_interface *interface = user_data;
441 if (g_strcmp0(key, "KeyMgmt") == 0)
442 supplicant_dbus_array_foreach(iter,
443 interface_capability_keymgmt, interface);
444 else if (g_strcmp0(key, "AuthAlg") == 0)
445 supplicant_dbus_array_foreach(iter,
446 interface_capability_authalg, interface);
447 else if (g_strcmp0(key, "Protocol") == 0)
448 supplicant_dbus_array_foreach(iter, interface_capability_proto,
450 else if (g_strcmp0(key, "Scan") == 0)
451 supplicant_dbus_array_foreach(iter, interface_capability_scan,
453 else if (g_strcmp0(key, "Modes") == 0)
454 supplicant_dbus_array_foreach(iter, interface_capability_mode,
457 DBG("key %s type %c",
458 key, dbus_message_iter_get_arg_type(iter));
461 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
463 if (interface == NULL)
466 return interface->ifname;
469 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
474 return network->interface;
477 const char *supplicant_network_get_name(struct supplicant_network *network)
479 if (network == NULL || network->name == NULL)
482 return network->name;
485 const char *supplicant_network_get_identifier(struct supplicant_network *network)
487 if (network == NULL || network->group == NULL)
490 return network->group;
493 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
496 return SUPPLICANT_MODE_UNKNOWN;
498 return network->mode;
501 static void network_property(const char *key, DBusMessageIter *iter,
507 DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
510 static void interface_network_added(DBusMessageIter *iter, void *user_data)
512 const char *path = NULL;
514 dbus_message_iter_get_basic(iter, &path);
518 if (g_strcmp0(path, "/") == 0)
521 DBG("path %s", path);
523 supplicant_dbus_property_get_all(path,
524 SUPPLICANT_INTERFACE ".Interface.Network",
525 network_property, NULL);
528 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
530 const char *path = NULL;
532 dbus_message_iter_get_basic(iter, &path);
536 DBG("path %s", path);
539 static char *create_name(unsigned char *ssid, int ssid_len)
544 if (ssid_len < 1 || ssid[0] == '\0')
547 name = g_try_malloc0(ssid_len + 1);
552 for (i = 0; i < ssid_len; i++) {
553 if (g_ascii_isprint(ssid[i]))
562 static char *create_group(struct supplicant_bss *bss)
566 const char *mode, *security;
568 str = g_string_sized_new((bss->ssid_len * 2) + 24);
572 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
573 for (i = 0; i < bss->ssid_len; i++)
574 g_string_append_printf(str, "%02x", bss->ssid[i]);
576 g_string_append_printf(str, "hidden");
578 mode = mode2string(bss->mode);
580 g_string_append_printf(str, "_%s", mode);
582 security = security2string(bss->security);
583 if (security != NULL)
584 g_string_append_printf(str, "_%s", security);
586 return g_string_free(str, FALSE);
589 static void add_bss_to_network(struct supplicant_bss *bss)
591 struct supplicant_interface *interface = bss->interface;
592 struct supplicant_network *network;
595 group = create_group(bss);
599 network = g_hash_table_lookup(interface->network_table, group);
600 if (network != NULL) {
605 network = g_try_new0(struct supplicant_network, 1);
606 if (network == NULL) {
611 network->group = group;
612 network->name = create_name(bss->ssid, bss->ssid_len);
613 network->mode = bss->mode;
615 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
618 g_hash_table_replace(interface->network_table,
619 network->group, network);
621 callback_network_added(network);
624 g_hash_table_replace(interface->bss_mapping, bss->path, network);
625 g_hash_table_replace(network->bss_table, bss->path, bss);
628 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
629 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
631 static void extract_rsn(struct supplicant_bss *bss,
632 const unsigned char *buf, int len)
651 /* Pairwise cipher */
655 count = buf[0] | (buf[1] << 8);
656 if (2 + (count * 4) > len)
659 buf += 2 + (count * 4);
660 len -= 2 + (count * 4);
666 count = buf[0] | (buf[1] << 8);
667 if (2 + (count * 4) > len)
670 for (i = 0; i < count; i++) {
671 const unsigned char *ptr = buf + 2 + (i * 4);
673 if (memcmp(ptr, wifi_oui, 3) == 0) {
676 bss->ieee8021x = TRUE;
682 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
685 bss->ieee8021x = TRUE;
694 buf += 2 + (count * 4);
695 len -= 2 + (count * 4);
698 static void bss_property(const char *key, DBusMessageIter *iter,
701 struct supplicant_bss *bss = user_data;
703 if (bss->interface == NULL)
707 if (bss->ieee8021x == TRUE)
708 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
709 else if (bss->psk == TRUE)
710 bss->security = SUPPLICANT_SECURITY_PSK;
711 else if (bss->privacy == TRUE)
712 bss->security = SUPPLICANT_SECURITY_WEP;
714 bss->security = SUPPLICANT_SECURITY_NONE;
716 add_bss_to_network(bss);
720 if (g_strcmp0(key, "BSSID") == 0) {
721 DBusMessageIter array;
725 dbus_message_iter_recurse(iter, &array);
726 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
729 memcpy(bss->bssid, addr, addr_len);
730 } else if (g_strcmp0(key, "SSID") == 0) {
731 DBusMessageIter array;
735 dbus_message_iter_recurse(iter, &array);
736 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
738 if (ssid_len > 0 && ssid_len < 33) {
739 memcpy(bss->ssid, ssid, ssid_len);
740 bss->ssid_len = ssid_len;
742 memset(bss->ssid, 0, sizeof(bss->ssid));
745 } else if (g_strcmp0(key, "Capabilities") == 0) {
746 dbus_uint16_t capabilities = 0x0000;
748 dbus_message_iter_get_basic(iter, &capabilities);
750 if (capabilities & IEEE80211_CAP_ESS)
751 bss->mode = SUPPLICANT_MODE_INFRA;
752 else if (capabilities & IEEE80211_CAP_IBSS)
753 bss->mode = SUPPLICANT_MODE_IBSS;
755 if (capabilities & IEEE80211_CAP_PRIVACY)
757 } else if (g_strcmp0(key, "Mode") == 0) {
758 const char *mode = NULL;
760 dbus_message_iter_get_basic(iter, &mode);
761 bss->mode = string2mode(mode);
762 } else if (g_strcmp0(key, "Frequency") == 0) {
763 dbus_uint16_t frequency = 0;
765 dbus_message_iter_get_basic(iter, &frequency);
766 bss->frequency = frequency;
767 } else if (g_strcmp0(key, "Signal") == 0) {
768 dbus_int16_t signal = 0;
770 dbus_message_iter_get_basic(iter, &signal);
771 } else if (g_strcmp0(key, "Level") == 0) {
772 dbus_int32_t level = 0;
774 dbus_message_iter_get_basic(iter, &level);
775 } else if (g_strcmp0(key, "MaxRate") == 0) {
776 dbus_uint16_t maxrate = 0;
778 dbus_message_iter_get_basic(iter, &maxrate);
779 } else if (g_strcmp0(key, "Privacy") == 0) {
780 dbus_bool_t privacy = FALSE;
782 dbus_message_iter_get_basic(iter, &privacy);
783 bss->privacy = privacy;
784 } else if (g_strcmp0(key, "RSNIE") == 0) {
785 DBusMessageIter array;
789 dbus_message_iter_recurse(iter, &array);
790 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
793 extract_rsn(bss, ie + 2, ie_len - 2);
794 } else if (g_strcmp0(key, "WPAIE") == 0) {
795 DBusMessageIter array;
799 dbus_message_iter_recurse(iter, &array);
800 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
803 extract_rsn(bss, ie + 6, ie_len - 6);
804 } else if (g_strcmp0(key, "WPSIE") == 0) {
805 DBusMessageIter array;
809 dbus_message_iter_recurse(iter, &array);
810 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
812 DBG("key %s type %c",
813 key, dbus_message_iter_get_arg_type(iter));
816 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
818 struct supplicant_interface *interface = user_data;
819 struct supplicant_network *network;
820 struct supplicant_bss *bss;
821 const char *path = NULL;
823 dbus_message_iter_get_basic(iter, &path);
827 if (g_strcmp0(path, "/") == 0)
830 network = g_hash_table_lookup(interface->bss_mapping, path);
831 if (network != NULL) {
832 bss = g_hash_table_lookup(network->bss_table, path);
837 bss = g_try_new0(struct supplicant_bss, 1);
841 bss->interface = interface;
842 bss->path = g_strdup(path);
844 supplicant_dbus_property_get_all(path,
845 SUPPLICANT_INTERFACE ".Interface.BSS",
849 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
851 struct supplicant_interface *interface = user_data;
852 struct supplicant_network *network;
853 const char *path = NULL;
855 dbus_message_iter_get_basic(iter, &path);
859 network = g_hash_table_lookup(interface->bss_mapping, path);
863 g_hash_table_remove(interface->bss_mapping, path);
864 g_hash_table_remove(network->bss_table, path);
866 if (g_hash_table_size(network->bss_table) == 0)
867 g_hash_table_remove(interface->network_table, network->group);
870 static void interface_property(const char *key, DBusMessageIter *iter,
873 struct supplicant_interface *interface = user_data;
875 if (interface == NULL)
879 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
880 interface->keymgmt_capa);
881 debug_strvalmap("AuthAlg capability", authalg_capa_map,
882 interface->authalg_capa);
883 debug_strvalmap("Protocol capability", proto_capa_map,
884 interface->proto_capa);
885 debug_strvalmap("Scan capability", scan_capa_map,
886 interface->scan_capa);
887 debug_strvalmap("Mode capability", mode_capa_map,
888 interface->mode_capa);
890 callback_interface_added(interface);
894 if (g_strcmp0(key, "Capabilities") == 0) {
895 supplicant_dbus_property_foreach(iter, interface_capability,
897 } else if (g_strcmp0(key, "State") == 0) {
898 const char *str = NULL;
900 dbus_message_iter_get_basic(iter, &str);
902 interface->state = string2state(str);
903 } else if (g_strcmp0(key, "Scanning") == 0) {
904 dbus_bool_t scanning = FALSE;
906 dbus_message_iter_get_basic(iter, &scanning);
907 interface->scanning = scanning;
908 } else if (g_strcmp0(key, "ApScan") == 0) {
911 dbus_message_iter_get_basic(iter, &apscan);
912 interface->apscan = apscan;
913 } else if (g_strcmp0(key, "Ifname") == 0) {
914 const char *str = NULL;
916 dbus_message_iter_get_basic(iter, &str);
918 interface->ifname = g_strdup(str);
919 } else if (g_strcmp0(key, "Driver") == 0) {
920 const char *str = NULL;
922 dbus_message_iter_get_basic(iter, &str);
924 interface->driver = g_strdup(str);
925 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
926 const char *str = NULL;
928 dbus_message_iter_get_basic(iter, &str);
930 interface->bridge = g_strdup(str);
931 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
932 interface_bss_added(iter, interface);
933 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
934 interface_network_added(iter, interface);
935 } else if (g_strcmp0(key, "BSSs") == 0) {
936 supplicant_dbus_array_foreach(iter, interface_bss_added,
938 } else if (g_strcmp0(key, "Blobs") == 0) {
939 } else if (g_strcmp0(key, "Networks") == 0) {
940 supplicant_dbus_array_foreach(iter, interface_network_added,
943 DBG("key %s type %c",
944 key, dbus_message_iter_get_arg_type(iter));
947 static struct supplicant_interface *interface_alloc(const char *path)
949 struct supplicant_interface *interface;
951 interface = g_try_new0(struct supplicant_interface, 1);
952 if (interface == NULL)
955 interface->path = g_strdup(path);
957 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
958 NULL, remove_network);
960 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
963 g_hash_table_replace(interface_table, interface->path, interface);
968 static void interface_added(DBusMessageIter *iter, void *user_data)
970 struct supplicant_interface *interface;
971 const char *path = NULL;
973 dbus_message_iter_get_basic(iter, &path);
977 if (g_strcmp0(path, "/") == 0)
980 interface = g_hash_table_lookup(interface_table, path);
981 if (interface != NULL)
984 interface = interface_alloc(path);
985 if (interface == NULL)
988 supplicant_dbus_property_get_all(path,
989 SUPPLICANT_INTERFACE ".Interface",
990 interface_property, interface);
993 static void interface_removed(DBusMessageIter *iter, void *user_data)
995 const char *path = NULL;
997 dbus_message_iter_get_basic(iter, &path);
1001 g_hash_table_remove(interface_table, path);
1004 static void eap_method(DBusMessageIter *iter, void *user_data)
1006 const char *str = NULL;
1009 dbus_message_iter_get_basic(iter, &str);
1013 for (i = 0; eap_method_map[i].str != NULL; i++)
1014 if (strcmp(str, eap_method_map[i].str) == 0) {
1015 eap_methods |= eap_method_map[i].val;
1020 static void service_property(const char *key, DBusMessageIter *iter,
1024 callback_system_ready();
1028 if (g_strcmp0(key, "DebugParams") == 0) {
1029 DBusMessageIter list;
1031 dbus_message_iter_recurse(iter, &list);
1032 dbus_message_iter_get_basic(&list, &debug_level);
1034 dbus_message_iter_next(&list);
1035 dbus_message_iter_get_basic(&list, &debug_timestamp);
1037 dbus_message_iter_next(&list);
1038 dbus_message_iter_get_basic(&list, &debug_showkeys);
1040 DBG("Debug level %d (timestamp %u show keys %u)",
1041 debug_level, debug_timestamp, debug_showkeys);
1042 } else if (g_strcmp0(key, "DebugLevel") == 0) {
1043 dbus_message_iter_get_basic(iter, &debug_level);
1044 DBG("Debug level %d", debug_level);
1045 } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
1046 dbus_message_iter_get_basic(iter, &debug_timestamp);
1047 DBG("Debug timestamp %u", debug_timestamp);
1048 } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1049 dbus_message_iter_get_basic(iter, &debug_showkeys);
1050 DBG("Debug show keys %u", debug_showkeys);
1051 } else if (g_strcmp0(key, "Interfaces") == 0) {
1052 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1053 } else if (g_strcmp0(key, "EapMethods") == 0) {
1054 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1055 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1057 DBG("key %s type %c",
1058 key, dbus_message_iter_get_arg_type(iter));
1061 static void supplicant_bootstrap(void)
1063 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1064 SUPPLICANT_INTERFACE,
1065 service_property, NULL);
1068 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1070 const char *name = NULL, *old = NULL, *new = NULL;
1072 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1075 dbus_message_iter_get_basic(iter, &name);
1079 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1082 dbus_message_iter_next(iter);
1083 dbus_message_iter_get_basic(iter, &old);
1084 dbus_message_iter_next(iter);
1085 dbus_message_iter_get_basic(iter, &new);
1087 if (old == NULL || new == NULL)
1090 if (strlen(old) > 0 && strlen(new) == 0) {
1091 system_available = FALSE;
1092 g_hash_table_remove_all(interface_table);
1093 callback_system_killed();
1096 if (strlen(new) > 0 && strlen(old) == 0) {
1097 system_available = TRUE;
1098 supplicant_bootstrap();
1102 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1104 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1107 supplicant_dbus_property_foreach(iter, service_property, NULL);
1110 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1112 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1113 interface_added(iter, NULL);
1116 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1118 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1119 interface_removed(iter, NULL);
1122 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1124 struct supplicant_interface *interface;
1126 interface = g_hash_table_lookup(interface_table, path);
1127 if (interface == NULL)
1130 interface_bss_added(iter, interface);
1133 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1135 struct supplicant_interface *interface;
1137 interface = g_hash_table_lookup(interface_table, path);
1138 if (interface == NULL)
1141 interface_bss_removed(iter, interface);
1144 static void signal_network_added(const char *path, DBusMessageIter *iter)
1146 struct supplicant_interface *interface;
1148 interface = g_hash_table_lookup(interface_table, path);
1149 if (interface == NULL)
1152 interface_network_added(iter, interface);
1155 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1157 struct supplicant_interface *interface;
1159 interface = g_hash_table_lookup(interface_table, path);
1160 if (interface == NULL)
1163 interface_network_removed(iter, interface);
1167 const char *interface;
1169 void (*function) (const char *path, DBusMessageIter *iter);
1171 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1173 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1174 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1175 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1176 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1178 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1179 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1180 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1181 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1186 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1187 DBusMessage *message, void *data)
1189 DBusMessageIter iter;
1193 path = dbus_message_get_path(message);
1195 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1197 if (dbus_message_iter_init(message, &iter) == FALSE)
1198 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1200 for (i = 0; signal_map[i].interface != NULL; i++) {
1201 if (dbus_message_has_interface(message,
1202 signal_map[i].interface) == FALSE)
1205 if (dbus_message_has_member(message,
1206 signal_map[i].member) == FALSE)
1209 signal_map[i].function(path, &iter);
1213 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1216 static const char *supplicant_rule0 = "type=signal,"
1217 "path=" DBUS_PATH_DBUS ","
1218 "sender=" DBUS_SERVICE_DBUS ","
1219 "interface=" DBUS_INTERFACE_DBUS ","
1220 "member=NameOwnerChanged,"
1221 "arg0=" SUPPLICANT_SERVICE;
1222 static const char *supplicant_rule1 = "type=signal,"
1223 "interface=" SUPPLICANT_INTERFACE;
1224 static const char *supplicant_rule2 = "type=signal,"
1225 "interface=" SUPPLICANT_INTERFACE ".Interface";
1226 static const char *supplicant_rule3 = "type=signal,"
1227 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1228 static const char *supplicant_rule4 = "type=signal,"
1229 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1230 static const char *supplicant_rule5 = "type=signal,"
1231 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1232 static const char *supplicant_rule6 = "type=signal,"
1233 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1235 int supplicant_register(const struct supplicant_callbacks *callbacks)
1237 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1238 if (connection == NULL)
1241 if (dbus_connection_add_filter(connection,
1242 supplicant_filter, NULL, NULL) == FALSE) {
1243 dbus_connection_unref(connection);
1248 callbacks_pointer = callbacks;
1251 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1252 NULL, remove_interface);
1254 supplicant_dbus_setup(connection);
1256 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1257 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1258 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1259 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1260 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1261 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1262 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1263 dbus_connection_flush(connection);
1265 if (dbus_bus_name_has_owner(connection,
1266 SUPPLICANT_SERVICE, NULL) == TRUE) {
1267 system_available = TRUE;
1268 supplicant_bootstrap();
1274 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1276 if (connection != NULL) {
1277 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1278 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1279 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1280 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1281 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1282 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1283 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1284 dbus_connection_flush(connection);
1286 dbus_connection_remove_filter(connection,
1287 supplicant_filter, NULL);
1290 if (interface_table != NULL) {
1291 g_hash_table_destroy(interface_table);
1292 interface_table = NULL;
1295 if (system_available == TRUE)
1296 callback_system_killed();
1298 if (connection != NULL) {
1299 dbus_connection_unref(connection);
1303 callbacks_pointer = NULL;
1307 static void debug_level_result(const char *error,
1308 DBusMessageIter *iter, void *user_data)
1311 DBG("debug level failure: %s", error);
1314 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1316 dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1317 DBusMessageIter entry;
1319 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1322 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1323 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1325 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1328 dbus_message_iter_close_container(iter, &entry);
1331 void supplicant_set_debug_level(unsigned int level)
1333 if (system_available == FALSE)
1336 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1337 "DebugParams", "(ibb)", add_debug_level,
1338 debug_level_result, GUINT_TO_POINTER(level));
1341 struct interface_create_data {
1344 struct supplicant_interface *interface;
1345 supplicant_interface_create_callback callback;
1349 static void interface_create_property(const char *key, DBusMessageIter *iter,
1352 struct interface_create_data *data = user_data;
1353 struct supplicant_interface *interface = data->interface;
1356 if (data->callback != NULL)
1357 data->callback(0, data->interface, data->user_data);
1362 interface_property(key, iter, interface);
1365 static void interface_create_result(const char *error,
1366 DBusMessageIter *iter, void *user_data)
1368 struct interface_create_data *data = user_data;
1369 const char *path = NULL;
1372 if (error != NULL) {
1377 dbus_message_iter_get_basic(iter, &path);
1383 if (system_available == FALSE) {
1388 data->interface = g_hash_table_lookup(interface_table, path);
1389 if (data->interface == NULL) {
1390 data->interface = interface_alloc(path);
1391 if (data->interface == NULL) {
1397 err = supplicant_dbus_property_get_all(path,
1398 SUPPLICANT_INTERFACE ".Interface",
1399 interface_create_property, data);
1404 if (data->callback != NULL)
1405 data->callback(err, NULL, data->user_data);
1410 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1412 struct interface_create_data *data = user_data;
1413 DBusMessageIter dict;
1415 supplicant_dbus_dict_open(iter, &dict);
1417 supplicant_dbus_dict_append_basic(&dict, "Ifname",
1418 DBUS_TYPE_STRING, &data->ifname);
1419 supplicant_dbus_dict_append_basic(&dict, "Driver",
1420 DBUS_TYPE_STRING, &data->driver);
1422 supplicant_dbus_dict_close(iter, &dict);
1425 static void interface_get_result(const char *error,
1426 DBusMessageIter *iter, void *user_data)
1428 struct interface_create_data *data = user_data;
1429 struct supplicant_interface *interface;
1430 const char *path = NULL;
1433 if (error != NULL) {
1438 dbus_message_iter_get_basic(iter, &path);
1444 interface = g_hash_table_lookup(interface_table, path);
1445 if (interface == NULL) {
1450 if (data->callback != NULL)
1451 data->callback(0, interface, data->user_data);
1458 if (system_available == FALSE) {
1463 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1464 SUPPLICANT_INTERFACE,
1466 interface_create_params,
1467 interface_create_result, data);
1472 if (data->callback != NULL)
1473 data->callback(err, NULL, data->user_data);
1478 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1480 struct interface_create_data *data = user_data;
1482 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1485 int supplicant_interface_create(const char *ifname, const char *driver,
1486 supplicant_interface_create_callback callback,
1489 struct interface_create_data *data;
1491 if (system_available == FALSE)
1494 data = dbus_malloc0(sizeof(*data));
1498 data->ifname = ifname;
1499 data->driver = driver;
1500 data->callback = callback;
1501 data->user_data = user_data;
1503 return supplicant_dbus_method_call(SUPPLICANT_PATH,
1504 SUPPLICANT_INTERFACE,
1506 interface_get_params,
1507 interface_get_result, data);
1510 int supplicant_interface_remove(struct supplicant_interface *interface,
1511 supplicant_interface_remove_callback callback,
1514 if (system_available == FALSE)