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_show_timestamps = FALSE;
56 static dbus_bool_t debug_show_keys = 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 unsigned int frequency;
148 enum supplicant_mode mode;
149 enum supplicant_security security;
152 dbus_bool_t ieee8021x;
155 static const char *mode2string(enum supplicant_mode mode)
158 case SUPPLICANT_MODE_UNKNOWN:
160 case SUPPLICANT_MODE_INFRA:
162 case SUPPLICANT_MODE_IBSS:
169 static const char *security2string(enum supplicant_security security)
172 case SUPPLICANT_SECURITY_UNKNOWN:
174 case SUPPLICANT_SECURITY_NONE:
176 case SUPPLICANT_SECURITY_WEP:
178 case SUPPLICANT_SECURITY_PSK:
180 case SUPPLICANT_SECURITY_IEEE8021X:
187 static enum supplicant_state string2state(const char *state)
190 return SUPPLICANT_STATE_UNKNOWN;
192 if (g_str_equal(state, "unknown") == TRUE)
193 return SUPPLICANT_STATE_UNKNOWN;
194 else if (g_str_equal(state, "disconnected") == TRUE)
195 return SUPPLICANT_STATE_DISCONNECTED;
196 else if (g_str_equal(state, "inactive") == TRUE)
197 return SUPPLICANT_STATE_INACTIVE;
198 else if (g_str_equal(state, "scanning") == TRUE)
199 return SUPPLICANT_STATE_SCANNING;
200 else if (g_str_equal(state, "authenticating") == TRUE)
201 return SUPPLICANT_STATE_AUTHENTICATING;
202 else if (g_str_equal(state, "associating") == TRUE)
203 return SUPPLICANT_STATE_ASSOCIATING;
204 else if (g_str_equal(state, "associated") == TRUE)
205 return SUPPLICANT_STATE_ASSOCIATED;
206 else if (g_str_equal(state, "group_handshake") == TRUE)
207 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
208 else if (g_str_equal(state, "4way_handshake") == TRUE)
209 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
210 else if (g_str_equal(state, "completed") == TRUE)
211 return SUPPLICANT_STATE_COMPLETED;
213 return SUPPLICANT_STATE_UNKNOWN;
216 static void callback_system_ready(void)
218 if (system_ready == TRUE)
223 if (callbacks_pointer == NULL)
226 if (callbacks_pointer->system_ready == NULL)
229 callbacks_pointer->system_ready();
232 static void callback_system_killed(void)
234 system_ready = FALSE;
236 if (callbacks_pointer == NULL)
239 if (callbacks_pointer->system_killed == NULL)
242 callbacks_pointer->system_killed();
245 static void callback_interface_added(struct supplicant_interface *interface)
247 if (callbacks_pointer == NULL)
250 if (callbacks_pointer->interface_added == NULL)
253 callbacks_pointer->interface_added(interface);
256 static void callback_interface_removed(struct supplicant_interface *interface)
258 if (callbacks_pointer == NULL)
261 if (callbacks_pointer->interface_removed == NULL)
264 callbacks_pointer->interface_removed(interface);
267 static void callback_network_added(struct supplicant_network *network)
269 if (callbacks_pointer == NULL)
272 if (callbacks_pointer->network_added == NULL)
275 callbacks_pointer->network_added(network);
278 static void callback_network_removed(struct supplicant_network *network)
280 if (callbacks_pointer == NULL)
283 if (callbacks_pointer->network_removed == NULL)
286 callbacks_pointer->network_removed(network);
289 static void remove_interface(gpointer data)
291 struct supplicant_interface *interface = data;
293 g_hash_table_destroy(interface->bss_mapping);
294 g_hash_table_destroy(interface->network_table);
296 callback_interface_removed(interface);
298 g_free(interface->path);
299 g_free(interface->ifname);
300 g_free(interface->driver);
301 g_free(interface->bridge);
305 static void remove_network(gpointer data)
307 struct supplicant_network *network = data;
309 callback_network_removed(network);
311 g_free(network->group);
312 g_free(network->name);
316 static void remove_bss(gpointer data)
318 struct supplicant_bss *bss = data;
324 static void debug_strvalmap(const char *label, struct strvalmap *map,
329 for (i = 0; map[i].str != NULL; i++) {
330 if (val & map[i].val)
331 DBG("%s: %s", label, map[i].str);
335 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
337 struct supplicant_interface *interface = user_data;
338 const char *str = NULL;
341 dbus_message_iter_get_basic(iter, &str);
345 for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
346 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
347 interface->keymgmt_capa |= keymgmt_capa_map[i].val;
352 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
354 struct supplicant_interface *interface = user_data;
355 const char *str = NULL;
358 dbus_message_iter_get_basic(iter, &str);
362 for (i = 0; authalg_capa_map[i].str != NULL; i++)
363 if (strcmp(str, authalg_capa_map[i].str) == 0) {
364 interface->authalg_capa |= authalg_capa_map[i].val;
369 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
371 struct supplicant_interface *interface = user_data;
372 const char *str = NULL;
375 dbus_message_iter_get_basic(iter, &str);
379 for (i = 0; proto_capa_map[i].str != NULL; i++)
380 if (strcmp(str, proto_capa_map[i].str) == 0) {
381 interface->proto_capa |= proto_capa_map[i].val;
386 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
388 struct supplicant_interface *interface = user_data;
389 const char *str = NULL;
392 dbus_message_iter_get_basic(iter, &str);
396 for (i = 0; scan_capa_map[i].str != NULL; i++)
397 if (strcmp(str, scan_capa_map[i].str) == 0) {
398 interface->scan_capa |= scan_capa_map[i].val;
403 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
405 struct supplicant_interface *interface = user_data;
406 const char *str = NULL;
409 dbus_message_iter_get_basic(iter, &str);
413 for (i = 0; mode_capa_map[i].str != NULL; i++)
414 if (strcmp(str, mode_capa_map[i].str) == 0) {
415 interface->mode_capa |= mode_capa_map[i].val;
420 static void interface_capability(const char *key, DBusMessageIter *iter,
423 struct supplicant_interface *interface = user_data;
428 if (g_strcmp0(key, "KeyMgmt") == 0)
429 supplicant_dbus_array_foreach(iter,
430 interface_capability_keymgmt, interface);
431 else if (g_strcmp0(key, "AuthAlg") == 0)
432 supplicant_dbus_array_foreach(iter,
433 interface_capability_authalg, interface);
434 else if (g_strcmp0(key, "Protocol") == 0)
435 supplicant_dbus_array_foreach(iter, interface_capability_proto,
437 else if (g_strcmp0(key, "Scan") == 0)
438 supplicant_dbus_array_foreach(iter, interface_capability_scan,
440 else if (g_strcmp0(key, "Modes") == 0)
441 supplicant_dbus_array_foreach(iter, interface_capability_mode,
444 DBG("key %s type %c",
445 key, dbus_message_iter_get_arg_type(iter));
448 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
450 if (interface == NULL)
453 return interface->ifname;
456 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
461 return network->interface;
464 const char *supplicant_network_get_name(struct supplicant_network *network)
466 if (network == NULL || network->name == NULL)
469 return network->name;
472 const char *supplicant_network_get_identifier(struct supplicant_network *network)
474 if (network == NULL || network->group == NULL)
477 return network->group;
480 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
483 return SUPPLICANT_MODE_UNKNOWN;
485 return network->mode;
488 static void network_property(const char *key, DBusMessageIter *iter,
494 DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
497 static void interface_network_added(DBusMessageIter *iter, void *user_data)
499 const char *path = NULL;
501 dbus_message_iter_get_basic(iter, &path);
505 if (g_strcmp0(path, "/") == 0)
508 DBG("path %s", path);
510 supplicant_dbus_property_get_all(path,
511 SUPPLICANT_INTERFACE ".Interface.Network",
512 network_property, NULL);
515 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
517 const char *path = NULL;
519 dbus_message_iter_get_basic(iter, &path);
523 DBG("path %s", path);
526 static char *create_name(unsigned char *ssid, int ssid_len)
531 if (ssid_len < 1 || ssid[0] == '\0')
534 name = g_try_malloc0(ssid_len + 1);
539 for (i = 0; i < ssid_len; i++) {
540 if (g_ascii_isprint(ssid[i]))
549 static char *create_group(struct supplicant_bss *bss)
553 const char *mode, *security;
555 str = g_string_sized_new((bss->ssid_len * 2) + 24);
559 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
560 for (i = 0; i < bss->ssid_len; i++)
561 g_string_append_printf(str, "%02x", bss->ssid[i]);
563 g_string_append_printf(str, "hidden");
565 mode = mode2string(bss->mode);
567 g_string_append_printf(str, "_%s", mode);
569 security = security2string(bss->security);
570 if (security != NULL)
571 g_string_append_printf(str, "_%s", security);
573 return g_string_free(str, FALSE);
576 static void add_bss_to_network(struct supplicant_bss *bss)
578 struct supplicant_interface *interface = bss->interface;
579 struct supplicant_network *network;
582 group = create_group(bss);
586 network = g_hash_table_lookup(interface->network_table, group);
587 if (network != NULL) {
592 network = g_try_new0(struct supplicant_network, 1);
593 if (network == NULL) {
598 network->group = group;
599 network->name = create_name(bss->ssid, bss->ssid_len);
600 network->mode = bss->mode;
602 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
605 g_hash_table_replace(interface->network_table,
606 network->group, network);
608 callback_network_added(network);
611 g_hash_table_replace(interface->bss_mapping, bss->path, network);
612 g_hash_table_replace(network->bss_table, bss->path, bss);
615 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
616 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
618 static void extract_rsn(struct supplicant_bss *bss,
619 const unsigned char *buf, int len)
638 /* Pairwise cipher */
642 count = buf[0] | (buf[1] << 8);
643 if (2 + (count * 4) > len)
646 buf += 2 + (count * 4);
647 len -= 2 + (count * 4);
653 count = buf[0] | (buf[1] << 8);
654 if (2 + (count * 4) > len)
657 for (i = 0; i < count; i++) {
658 const unsigned char *ptr = buf + 2 + (i * 4);
660 if (memcmp(ptr, wifi_oui, 3) == 0) {
663 bss->ieee8021x = TRUE;
669 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
672 bss->ieee8021x = TRUE;
681 buf += 2 + (count * 4);
682 len -= 2 + (count * 4);
685 static void bss_property(const char *key, DBusMessageIter *iter,
688 struct supplicant_bss *bss = user_data;
690 if (bss->interface == NULL)
694 if (bss->ieee8021x == TRUE)
695 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
696 else if (bss->psk == TRUE)
697 bss->security = SUPPLICANT_SECURITY_PSK;
698 else if (bss->privacy == TRUE)
699 bss->security = SUPPLICANT_SECURITY_WEP;
701 bss->security = SUPPLICANT_SECURITY_NONE;
703 add_bss_to_network(bss);
707 if (g_strcmp0(key, "BSSID") == 0) {
708 DBusMessageIter array;
712 dbus_message_iter_recurse(iter, &array);
713 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
716 memcpy(bss->bssid, addr, addr_len);
717 } else if (g_strcmp0(key, "SSID") == 0) {
718 DBusMessageIter array;
722 dbus_message_iter_recurse(iter, &array);
723 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
725 if (ssid_len > 0 && ssid_len < 33) {
726 memcpy(bss->ssid, ssid, ssid_len);
727 bss->ssid_len = ssid_len;
729 memset(bss->ssid, 0, sizeof(bss->ssid));
732 } else if (g_strcmp0(key, "Capabilities") == 0) {
733 dbus_uint16_t capabilities = 0x0000;
735 dbus_message_iter_get_basic(iter, &capabilities);
737 if (capabilities & IEEE80211_CAP_ESS)
738 bss->mode = SUPPLICANT_MODE_INFRA;
739 else if (capabilities & IEEE80211_CAP_IBSS)
740 bss->mode = SUPPLICANT_MODE_IBSS;
742 if (capabilities & IEEE80211_CAP_PRIVACY)
744 } else if (g_strcmp0(key, "Frequency") == 0) {
745 dbus_int32_t frequency = 0;
747 dbus_message_iter_get_basic(iter, &frequency);
748 bss->frequency = frequency;
749 } else if (g_strcmp0(key, "Level") == 0) {
750 dbus_int32_t level = 0;
752 dbus_message_iter_get_basic(iter, &level);
753 } else if (g_strcmp0(key, "MaxRate") == 0) {
754 dbus_int32_t maxrate = 0;
756 dbus_message_iter_get_basic(iter, &maxrate);
757 } else if (g_strcmp0(key, "RSNIE") == 0) {
758 DBusMessageIter array;
762 dbus_message_iter_recurse(iter, &array);
763 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
766 extract_rsn(bss, ie + 2, ie_len - 2);
767 } else if (g_strcmp0(key, "WPAIE") == 0) {
768 DBusMessageIter array;
772 dbus_message_iter_recurse(iter, &array);
773 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
776 extract_rsn(bss, ie + 6, ie_len - 6);
777 } else if (g_strcmp0(key, "WPSIE") == 0) {
778 DBusMessageIter array;
782 dbus_message_iter_recurse(iter, &array);
783 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
785 DBG("key %s type %c",
786 key, dbus_message_iter_get_arg_type(iter));
789 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
791 struct supplicant_interface *interface = user_data;
792 struct supplicant_network *network;
793 struct supplicant_bss *bss;
794 const char *path = NULL;
796 dbus_message_iter_get_basic(iter, &path);
800 if (g_strcmp0(path, "/") == 0)
803 network = g_hash_table_lookup(interface->bss_mapping, path);
804 if (network != NULL) {
805 bss = g_hash_table_lookup(network->bss_table, path);
810 bss = g_try_new0(struct supplicant_bss, 1);
814 bss->interface = interface;
815 bss->path = g_strdup(path);
817 supplicant_dbus_property_get_all(path,
818 SUPPLICANT_INTERFACE ".Interface.BSS",
822 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
824 struct supplicant_interface *interface = user_data;
825 struct supplicant_network *network;
826 const char *path = NULL;
828 dbus_message_iter_get_basic(iter, &path);
832 network = g_hash_table_lookup(interface->bss_mapping, path);
836 g_hash_table_remove(interface->bss_mapping, path);
837 g_hash_table_remove(network->bss_table, path);
839 if (g_hash_table_size(network->bss_table) == 0)
840 g_hash_table_remove(interface->network_table, network->group);
843 static void interface_property(const char *key, DBusMessageIter *iter,
846 struct supplicant_interface *interface = user_data;
848 if (interface == NULL)
852 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
853 interface->keymgmt_capa);
854 debug_strvalmap("AuthAlg capability", authalg_capa_map,
855 interface->authalg_capa);
856 debug_strvalmap("Protocol capability", proto_capa_map,
857 interface->proto_capa);
858 debug_strvalmap("Scan capability", scan_capa_map,
859 interface->scan_capa);
860 debug_strvalmap("Mode capability", mode_capa_map,
861 interface->mode_capa);
863 callback_interface_added(interface);
867 if (g_strcmp0(key, "Capabilities") == 0) {
868 supplicant_dbus_property_foreach(iter, interface_capability,
870 } else if (g_strcmp0(key, "State") == 0) {
871 const char *str = NULL;
873 dbus_message_iter_get_basic(iter, &str);
875 interface->state = string2state(str);
876 } else if (g_strcmp0(key, "Scanning") == 0) {
877 dbus_bool_t scanning = FALSE;
879 dbus_message_iter_get_basic(iter, &scanning);
880 interface->scanning = scanning;
881 } else if (g_strcmp0(key, "ApScan") == 0) {
884 dbus_message_iter_get_basic(iter, &apscan);
885 interface->apscan = apscan;
886 } else if (g_strcmp0(key, "Ifname") == 0) {
887 const char *str = NULL;
889 dbus_message_iter_get_basic(iter, &str);
891 interface->ifname = g_strdup(str);
892 } else if (g_strcmp0(key, "Driver") == 0) {
893 const char *str = NULL;
895 dbus_message_iter_get_basic(iter, &str);
897 interface->driver = g_strdup(str);
898 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
899 const char *str = NULL;
901 dbus_message_iter_get_basic(iter, &str);
903 interface->bridge = g_strdup(str);
904 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
905 interface_bss_added(iter, interface);
906 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
907 interface_network_added(iter, interface);
908 } else if (g_strcmp0(key, "BSSs") == 0) {
909 supplicant_dbus_array_foreach(iter, interface_bss_added,
911 } else if (g_strcmp0(key, "Blobs") == 0) {
912 } else if (g_strcmp0(key, "Networks") == 0) {
913 supplicant_dbus_array_foreach(iter, interface_network_added,
916 DBG("key %s type %c",
917 key, dbus_message_iter_get_arg_type(iter));
920 static struct supplicant_interface *interface_alloc(const char *path)
922 struct supplicant_interface *interface;
924 interface = g_try_new0(struct supplicant_interface, 1);
925 if (interface == NULL)
928 interface->path = g_strdup(path);
930 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
931 NULL, remove_network);
933 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
936 g_hash_table_replace(interface_table, interface->path, interface);
941 static void interface_added(DBusMessageIter *iter, void *user_data)
943 struct supplicant_interface *interface;
944 const char *path = NULL;
946 dbus_message_iter_get_basic(iter, &path);
950 if (g_strcmp0(path, "/") == 0)
953 interface = g_hash_table_lookup(interface_table, path);
954 if (interface != NULL)
957 interface = interface_alloc(path);
958 if (interface == NULL)
961 supplicant_dbus_property_get_all(path,
962 SUPPLICANT_INTERFACE ".Interface",
963 interface_property, interface);
966 static void interface_removed(DBusMessageIter *iter, void *user_data)
968 const char *path = NULL;
970 dbus_message_iter_get_basic(iter, &path);
974 g_hash_table_remove(interface_table, path);
977 static void eap_method(DBusMessageIter *iter, void *user_data)
979 const char *str = NULL;
982 dbus_message_iter_get_basic(iter, &str);
986 for (i = 0; eap_method_map[i].str != NULL; i++)
987 if (strcmp(str, eap_method_map[i].str) == 0) {
988 eap_methods |= eap_method_map[i].val;
993 static void service_property(const char *key, DBusMessageIter *iter,
997 callback_system_ready();
1001 if (g_strcmp0(key, "DebugParams") == 0) {
1002 DBusMessageIter list;
1004 dbus_message_iter_recurse(iter, &list);
1005 dbus_message_iter_get_basic(&list, &debug_level);
1007 dbus_message_iter_next(&list);
1008 dbus_message_iter_get_basic(&list, &debug_show_timestamps);
1010 dbus_message_iter_next(&list);
1011 dbus_message_iter_get_basic(&list, &debug_show_keys);
1013 DBG("Debug level %d (timestamps %u keys %u)", debug_level,
1014 debug_show_timestamps, debug_show_keys);
1015 } else if (g_strcmp0(key, "Interfaces") == 0) {
1016 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1017 } else if (g_strcmp0(key, "EapMethods") == 0) {
1018 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1019 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1023 static void supplicant_bootstrap(void)
1025 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1026 SUPPLICANT_INTERFACE,
1027 service_property, NULL);
1030 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1032 const char *name = NULL, *old = NULL, *new = NULL;
1034 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1037 dbus_message_iter_get_basic(iter, &name);
1041 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1044 dbus_message_iter_next(iter);
1045 dbus_message_iter_get_basic(iter, &old);
1046 dbus_message_iter_next(iter);
1047 dbus_message_iter_get_basic(iter, &new);
1049 if (old == NULL || new == NULL)
1052 if (strlen(old) > 0 && strlen(new) == 0) {
1053 system_available = FALSE;
1054 g_hash_table_remove_all(interface_table);
1055 callback_system_killed();
1058 if (strlen(new) > 0 && strlen(old) == 0) {
1059 system_available = TRUE;
1060 supplicant_bootstrap();
1064 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1066 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1069 supplicant_dbus_property_foreach(iter, service_property, NULL);
1072 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1074 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1075 interface_added(iter, NULL);
1078 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1080 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1081 interface_removed(iter, NULL);
1084 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1086 struct supplicant_interface *interface;
1088 interface = g_hash_table_lookup(interface_table, path);
1089 if (interface == NULL)
1092 interface_bss_added(iter, interface);
1095 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1097 struct supplicant_interface *interface;
1099 interface = g_hash_table_lookup(interface_table, path);
1100 if (interface == NULL)
1103 interface_bss_removed(iter, interface);
1106 static void signal_network_added(const char *path, DBusMessageIter *iter)
1108 struct supplicant_interface *interface;
1110 interface = g_hash_table_lookup(interface_table, path);
1111 if (interface == NULL)
1114 interface_network_added(iter, interface);
1117 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1119 struct supplicant_interface *interface;
1121 interface = g_hash_table_lookup(interface_table, path);
1122 if (interface == NULL)
1125 interface_network_removed(iter, interface);
1129 const char *interface;
1131 void (*function) (const char *path, DBusMessageIter *iter);
1133 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1135 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1136 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1137 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1138 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1140 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1141 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1142 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1143 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1148 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1149 DBusMessage *message, void *data)
1151 DBusMessageIter iter;
1155 path = dbus_message_get_path(message);
1157 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1159 if (dbus_message_iter_init(message, &iter) == FALSE)
1160 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1162 for (i = 0; signal_map[i].interface != NULL; i++) {
1163 if (dbus_message_has_interface(message,
1164 signal_map[i].interface) == FALSE)
1167 if (dbus_message_has_member(message,
1168 signal_map[i].member) == FALSE)
1171 signal_map[i].function(path, &iter);
1175 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1178 static const char *supplicant_rule0 = "type=signal,"
1179 "path=" DBUS_PATH_DBUS ","
1180 "sender=" DBUS_SERVICE_DBUS ","
1181 "interface=" DBUS_INTERFACE_DBUS ","
1182 "member=NameOwnerChanged,"
1183 "arg0=" SUPPLICANT_SERVICE;
1184 static const char *supplicant_rule1 = "type=signal,"
1185 "interface=" SUPPLICANT_INTERFACE;
1186 static const char *supplicant_rule2 = "type=signal,"
1187 "interface=" SUPPLICANT_INTERFACE ".Interface";
1188 static const char *supplicant_rule3 = "type=signal,"
1189 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1190 static const char *supplicant_rule4 = "type=signal,"
1191 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1192 static const char *supplicant_rule5 = "type=signal,"
1193 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1194 static const char *supplicant_rule6 = "type=signal,"
1195 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1197 int supplicant_register(const struct supplicant_callbacks *callbacks)
1199 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1200 if (connection == NULL)
1203 if (dbus_connection_add_filter(connection,
1204 supplicant_filter, NULL, NULL) == FALSE) {
1205 dbus_connection_unref(connection);
1210 callbacks_pointer = callbacks;
1213 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1214 NULL, remove_interface);
1216 supplicant_dbus_setup(connection);
1218 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1219 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1220 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1221 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1222 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1223 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1224 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1225 dbus_connection_flush(connection);
1227 if (dbus_bus_name_has_owner(connection,
1228 SUPPLICANT_SERVICE, NULL) == TRUE) {
1229 system_available = TRUE;
1230 supplicant_bootstrap();
1236 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1238 if (connection != NULL) {
1239 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1240 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1241 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1242 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1243 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1244 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1245 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1246 dbus_connection_flush(connection);
1248 dbus_connection_remove_filter(connection,
1249 supplicant_filter, NULL);
1252 if (interface_table != NULL) {
1253 g_hash_table_destroy(interface_table);
1254 interface_table = NULL;
1257 if (system_available == TRUE)
1258 callback_system_killed();
1260 if (connection != NULL) {
1261 dbus_connection_unref(connection);
1265 callbacks_pointer = NULL;
1269 static void debug_level_result(const char *error,
1270 DBusMessageIter *iter, void *user_data)
1273 DBG("debug level failure: %s", error);
1276 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1278 dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1279 DBusMessageIter entry;
1281 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1284 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1285 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1286 &debug_show_timestamps);
1287 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1290 dbus_message_iter_close_container(iter, &entry);
1293 void supplicant_set_debug_level(unsigned int level)
1295 if (system_available == FALSE)
1298 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1299 "DebugParams", "(ibb)", add_debug_level,
1300 debug_level_result, GUINT_TO_POINTER(level));
1303 static void add_show_timestamps(DBusMessageIter *iter, void *user_data)
1305 dbus_bool_t show_timestamps = GPOINTER_TO_UINT(user_data);
1306 DBusMessageIter entry;
1308 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1311 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &debug_level);
1312 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1314 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1317 dbus_message_iter_close_container(iter, &entry);
1320 void supplicant_set_debug_show_timestamps(dbus_bool_t enabled)
1322 if (system_available == FALSE)
1325 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1326 "DebugParams", "(ibb)", add_show_timestamps,
1327 NULL, GUINT_TO_POINTER(enabled));
1330 struct interface_create_data {
1333 struct supplicant_interface *interface;
1334 supplicant_interface_create_callback callback;
1338 static void interface_create_property(const char *key, DBusMessageIter *iter,
1341 struct interface_create_data *data = user_data;
1342 struct supplicant_interface *interface = data->interface;
1345 if (data->callback != NULL)
1346 data->callback(0, data->interface, data->user_data);
1351 interface_property(key, iter, interface);
1354 static void interface_create_result(const char *error,
1355 DBusMessageIter *iter, void *user_data)
1357 struct interface_create_data *data = user_data;
1358 const char *path = NULL;
1361 if (error != NULL) {
1366 dbus_message_iter_get_basic(iter, &path);
1372 if (system_available == FALSE) {
1377 data->interface = g_hash_table_lookup(interface_table, path);
1378 if (data->interface == NULL) {
1379 data->interface = interface_alloc(path);
1380 if (data->interface == NULL) {
1386 err = supplicant_dbus_property_get_all(path,
1387 SUPPLICANT_INTERFACE ".Interface",
1388 interface_create_property, data);
1393 if (data->callback != NULL)
1394 data->callback(err, NULL, data->user_data);
1399 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1401 struct interface_create_data *data = user_data;
1402 DBusMessageIter dict;
1404 supplicant_dbus_dict_open(iter, &dict);
1406 supplicant_dbus_dict_append_basic(&dict, "Ifname",
1407 DBUS_TYPE_STRING, &data->ifname);
1408 supplicant_dbus_dict_append_basic(&dict, "Driver",
1409 DBUS_TYPE_STRING, &data->driver);
1411 supplicant_dbus_dict_close(iter, &dict);
1414 static void interface_get_result(const char *error,
1415 DBusMessageIter *iter, void *user_data)
1417 struct interface_create_data *data = user_data;
1418 struct supplicant_interface *interface;
1419 const char *path = NULL;
1422 if (error != NULL) {
1427 dbus_message_iter_get_basic(iter, &path);
1433 interface = g_hash_table_lookup(interface_table, path);
1434 if (interface == NULL) {
1439 if (data->callback != NULL)
1440 data->callback(0, interface, data->user_data);
1447 if (system_available == FALSE) {
1452 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1453 SUPPLICANT_INTERFACE,
1455 interface_create_params,
1456 interface_create_result, data);
1461 if (data->callback != NULL)
1462 data->callback(err, NULL, data->user_data);
1467 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1469 struct interface_create_data *data = user_data;
1471 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1474 int supplicant_interface_create(const char *ifname, const char *driver,
1475 supplicant_interface_create_callback callback,
1478 struct interface_create_data *data;
1480 if (system_available == FALSE)
1483 data = dbus_malloc0(sizeof(*data));
1487 data->ifname = ifname;
1488 data->driver = driver;
1489 data->callback = callback;
1490 data->user_data = user_data;
1492 return supplicant_dbus_method_call(SUPPLICANT_PATH,
1493 SUPPLICANT_INTERFACE,
1495 interface_get_params,
1496 interface_get_result, data);
1499 int supplicant_interface_remove(struct supplicant_interface *interface,
1500 supplicant_interface_remove_callback callback,
1503 if (system_available == FALSE)