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 group_capa_map[] = {
101 { "wep40", SUPPLICANT_CAPABILITY_GROUP_WEP40 },
102 { "wep104", SUPPLICANT_CAPABILITY_GROUP_WEP104 },
103 { "tkip", SUPPLICANT_CAPABILITY_GROUP_TKIP },
104 { "ccmp", SUPPLICANT_CAPABILITY_GROUP_CCMP },
108 static struct strvalmap pairwise_capa_map[] = {
109 { "none", SUPPLICANT_CAPABILITY_PAIRWISE_NONE },
110 { "tkip", SUPPLICANT_CAPABILITY_PAIRWISE_TKIP },
111 { "ccmp", SUPPLICANT_CAPABILITY_PAIRWISE_CCMP },
115 static struct strvalmap scan_capa_map[] = {
116 { "active", SUPPLICANT_CAPABILITY_SCAN_ACTIVE },
117 { "passive", SUPPLICANT_CAPABILITY_SCAN_PASSIVE },
118 { "ssid", SUPPLICANT_CAPABILITY_SCAN_SSID },
122 static struct strvalmap mode_capa_map[] = {
123 { "infrastructure", SUPPLICANT_CAPABILITY_MODE_INFRA },
124 { "ad-hoc", SUPPLICANT_CAPABILITY_MODE_IBSS },
125 { "ap", SUPPLICANT_CAPABILITY_MODE_AP },
129 static GHashTable *interface_table;
131 struct supplicant_interface {
133 unsigned int keymgmt_capa;
134 unsigned int authalg_capa;
135 unsigned int proto_capa;
136 unsigned int group_capa;
137 unsigned int pairwise_capa;
138 unsigned int scan_capa;
139 unsigned int mode_capa;
140 enum supplicant_state state;
141 dbus_bool_t scanning;
146 GHashTable *network_table;
147 GHashTable *bss_mapping;
150 struct supplicant_network {
151 struct supplicant_interface *interface;
154 enum supplicant_mode mode;
155 GHashTable *bss_table;
158 struct supplicant_bss {
159 struct supplicant_interface *interface;
161 unsigned char bssid[6];
162 unsigned char ssid[32];
163 unsigned int ssid_len;
164 dbus_uint16_t frequency;
165 enum supplicant_mode mode;
166 enum supplicant_security security;
169 dbus_bool_t ieee8021x;
172 static enum supplicant_mode string2mode(const char *mode)
175 return SUPPLICANT_MODE_UNKNOWN;
177 if (g_str_equal(mode, "infrastructure") == TRUE)
178 return SUPPLICANT_MODE_INFRA;
179 else if (g_str_equal(mode, "ad-hoc") == TRUE)
180 return SUPPLICANT_MODE_IBSS;
182 return SUPPLICANT_MODE_UNKNOWN;
185 static const char *mode2string(enum supplicant_mode mode)
188 case SUPPLICANT_MODE_UNKNOWN:
190 case SUPPLICANT_MODE_INFRA:
192 case SUPPLICANT_MODE_IBSS:
199 static const char *security2string(enum supplicant_security security)
202 case SUPPLICANT_SECURITY_UNKNOWN:
204 case SUPPLICANT_SECURITY_NONE:
206 case SUPPLICANT_SECURITY_WEP:
208 case SUPPLICANT_SECURITY_PSK:
210 case SUPPLICANT_SECURITY_IEEE8021X:
217 static enum supplicant_state string2state(const char *state)
220 return SUPPLICANT_STATE_UNKNOWN;
222 if (g_str_equal(state, "unknown") == TRUE)
223 return SUPPLICANT_STATE_UNKNOWN;
224 else if (g_str_equal(state, "disconnected") == TRUE)
225 return SUPPLICANT_STATE_DISCONNECTED;
226 else if (g_str_equal(state, "inactive") == TRUE)
227 return SUPPLICANT_STATE_INACTIVE;
228 else if (g_str_equal(state, "scanning") == TRUE)
229 return SUPPLICANT_STATE_SCANNING;
230 else if (g_str_equal(state, "authenticating") == TRUE)
231 return SUPPLICANT_STATE_AUTHENTICATING;
232 else if (g_str_equal(state, "associating") == TRUE)
233 return SUPPLICANT_STATE_ASSOCIATING;
234 else if (g_str_equal(state, "associated") == TRUE)
235 return SUPPLICANT_STATE_ASSOCIATED;
236 else if (g_str_equal(state, "group_handshake") == TRUE)
237 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
238 else if (g_str_equal(state, "4way_handshake") == TRUE)
239 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
240 else if (g_str_equal(state, "completed") == TRUE)
241 return SUPPLICANT_STATE_COMPLETED;
243 return SUPPLICANT_STATE_UNKNOWN;
246 static void callback_system_ready(void)
248 if (system_ready == TRUE)
253 if (callbacks_pointer == NULL)
256 if (callbacks_pointer->system_ready == NULL)
259 callbacks_pointer->system_ready();
262 static void callback_system_killed(void)
264 system_ready = FALSE;
266 if (callbacks_pointer == NULL)
269 if (callbacks_pointer->system_killed == NULL)
272 callbacks_pointer->system_killed();
275 static void callback_interface_added(struct supplicant_interface *interface)
277 if (callbacks_pointer == NULL)
280 if (callbacks_pointer->interface_added == NULL)
283 callbacks_pointer->interface_added(interface);
286 static void callback_interface_removed(struct supplicant_interface *interface)
288 if (callbacks_pointer == NULL)
291 if (callbacks_pointer->interface_removed == NULL)
294 callbacks_pointer->interface_removed(interface);
297 static void callback_network_added(struct supplicant_network *network)
299 if (callbacks_pointer == NULL)
302 if (callbacks_pointer->network_added == NULL)
305 callbacks_pointer->network_added(network);
308 static void callback_network_removed(struct supplicant_network *network)
310 if (callbacks_pointer == NULL)
313 if (callbacks_pointer->network_removed == NULL)
316 callbacks_pointer->network_removed(network);
319 static void remove_interface(gpointer data)
321 struct supplicant_interface *interface = data;
323 g_hash_table_destroy(interface->bss_mapping);
324 g_hash_table_destroy(interface->network_table);
326 callback_interface_removed(interface);
328 g_free(interface->path);
329 g_free(interface->ifname);
330 g_free(interface->driver);
331 g_free(interface->bridge);
335 static void remove_network(gpointer data)
337 struct supplicant_network *network = data;
339 callback_network_removed(network);
341 g_free(network->group);
342 g_free(network->name);
346 static void remove_bss(gpointer data)
348 struct supplicant_bss *bss = data;
354 static void debug_strvalmap(const char *label, struct strvalmap *map,
359 for (i = 0; map[i].str != NULL; i++) {
360 if (val & map[i].val)
361 DBG("%s: %s", label, map[i].str);
365 static void interface_capability_keymgmt(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; keymgmt_capa_map[i].str != NULL; i++)
376 if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
377 interface->keymgmt_capa |= keymgmt_capa_map[i].val;
382 static void interface_capability_authalg(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; authalg_capa_map[i].str != NULL; i++)
393 if (strcmp(str, authalg_capa_map[i].str) == 0) {
394 interface->authalg_capa |= authalg_capa_map[i].val;
399 static void interface_capability_proto(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; proto_capa_map[i].str != NULL; i++)
410 if (strcmp(str, proto_capa_map[i].str) == 0) {
411 interface->proto_capa |= proto_capa_map[i].val;
416 static void interface_capability_pairwise(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; pairwise_capa_map[i].str != NULL; i++)
427 if (strcmp(str, pairwise_capa_map[i].str) == 0) {
428 interface->pairwise_capa |= pairwise_capa_map[i].val;
433 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
435 struct supplicant_interface *interface = user_data;
436 const char *str = NULL;
439 dbus_message_iter_get_basic(iter, &str);
443 for (i = 0; group_capa_map[i].str != NULL; i++)
444 if (strcmp(str, group_capa_map[i].str) == 0) {
445 interface->group_capa |= group_capa_map[i].val;
450 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
452 struct supplicant_interface *interface = user_data;
453 const char *str = NULL;
456 dbus_message_iter_get_basic(iter, &str);
460 for (i = 0; scan_capa_map[i].str != NULL; i++)
461 if (strcmp(str, scan_capa_map[i].str) == 0) {
462 interface->scan_capa |= scan_capa_map[i].val;
467 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
469 struct supplicant_interface *interface = user_data;
470 const char *str = NULL;
473 dbus_message_iter_get_basic(iter, &str);
477 for (i = 0; mode_capa_map[i].str != NULL; i++)
478 if (strcmp(str, mode_capa_map[i].str) == 0) {
479 interface->mode_capa |= mode_capa_map[i].val;
484 static void interface_capability(const char *key, DBusMessageIter *iter,
487 struct supplicant_interface *interface = user_data;
492 if (g_strcmp0(key, "KeyMgmt") == 0)
493 supplicant_dbus_array_foreach(iter,
494 interface_capability_keymgmt, interface);
495 else if (g_strcmp0(key, "AuthAlg") == 0)
496 supplicant_dbus_array_foreach(iter,
497 interface_capability_authalg, interface);
498 else if (g_strcmp0(key, "Protocol") == 0)
499 supplicant_dbus_array_foreach(iter,
500 interface_capability_proto, interface);
501 else if (g_strcmp0(key, "Pairwise") == 0)
502 supplicant_dbus_array_foreach(iter,
503 interface_capability_pairwise, interface);
504 else if (g_strcmp0(key, "Group") == 0)
505 supplicant_dbus_array_foreach(iter,
506 interface_capability_group, interface);
507 else if (g_strcmp0(key, "Scan") == 0)
508 supplicant_dbus_array_foreach(iter,
509 interface_capability_scan, interface);
510 else if (g_strcmp0(key, "Modes") == 0)
511 supplicant_dbus_array_foreach(iter,
512 interface_capability_mode, interface);
514 DBG("key %s type %c",
515 key, dbus_message_iter_get_arg_type(iter));
518 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
520 if (interface == NULL)
523 return interface->ifname;
526 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
531 return network->interface;
534 const char *supplicant_network_get_name(struct supplicant_network *network)
536 if (network == NULL || network->name == NULL)
539 return network->name;
542 const char *supplicant_network_get_identifier(struct supplicant_network *network)
544 if (network == NULL || network->group == NULL)
547 return network->group;
550 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
553 return SUPPLICANT_MODE_UNKNOWN;
555 return network->mode;
558 static void network_property(const char *key, DBusMessageIter *iter,
564 //DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
567 static void interface_network_added(DBusMessageIter *iter, void *user_data)
569 //struct supplicant_interface *interface = user_data;
570 const char *path = NULL;
572 dbus_message_iter_get_basic(iter, &path);
576 if (g_strcmp0(path, "/") == 0)
579 dbus_message_iter_next(iter);
580 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
581 supplicant_dbus_property_foreach(iter, network_property, NULL);
582 network_property(NULL, NULL, NULL);
586 supplicant_dbus_property_get_all(path,
587 SUPPLICANT_INTERFACE ".Interface.Network",
588 network_property, NULL);
591 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
593 const char *path = NULL;
595 dbus_message_iter_get_basic(iter, &path);
599 DBG("path %s", path);
602 static char *create_name(unsigned char *ssid, int ssid_len)
607 if (ssid_len < 1 || ssid[0] == '\0')
610 name = g_try_malloc0(ssid_len + 1);
615 for (i = 0; i < ssid_len; i++) {
616 if (g_ascii_isprint(ssid[i]))
625 static char *create_group(struct supplicant_bss *bss)
629 const char *mode, *security;
631 str = g_string_sized_new((bss->ssid_len * 2) + 24);
635 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
636 for (i = 0; i < bss->ssid_len; i++)
637 g_string_append_printf(str, "%02x", bss->ssid[i]);
639 g_string_append_printf(str, "hidden");
641 mode = mode2string(bss->mode);
643 g_string_append_printf(str, "_%s", mode);
645 security = security2string(bss->security);
646 if (security != NULL)
647 g_string_append_printf(str, "_%s", security);
649 return g_string_free(str, FALSE);
652 static void add_bss_to_network(struct supplicant_bss *bss)
654 struct supplicant_interface *interface = bss->interface;
655 struct supplicant_network *network;
658 group = create_group(bss);
662 network = g_hash_table_lookup(interface->network_table, group);
663 if (network != NULL) {
668 network = g_try_new0(struct supplicant_network, 1);
669 if (network == NULL) {
674 network->group = group;
675 network->name = create_name(bss->ssid, bss->ssid_len);
676 network->mode = bss->mode;
678 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
681 g_hash_table_replace(interface->network_table,
682 network->group, network);
684 callback_network_added(network);
687 g_hash_table_replace(interface->bss_mapping, bss->path, network);
688 g_hash_table_replace(network->bss_table, bss->path, bss);
691 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
692 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
694 static void extract_rsn(struct supplicant_bss *bss,
695 const unsigned char *buf, int len)
714 /* Pairwise cipher */
718 count = buf[0] | (buf[1] << 8);
719 if (2 + (count * 4) > len)
722 buf += 2 + (count * 4);
723 len -= 2 + (count * 4);
729 count = buf[0] | (buf[1] << 8);
730 if (2 + (count * 4) > len)
733 for (i = 0; i < count; i++) {
734 const unsigned char *ptr = buf + 2 + (i * 4);
736 if (memcmp(ptr, wifi_oui, 3) == 0) {
739 bss->ieee8021x = TRUE;
745 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
748 bss->ieee8021x = TRUE;
757 buf += 2 + (count * 4);
758 len -= 2 + (count * 4);
761 static void bss_property(const char *key, DBusMessageIter *iter,
764 struct supplicant_bss *bss = user_data;
766 if (bss->interface == NULL)
770 if (bss->ieee8021x == TRUE)
771 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
772 else if (bss->psk == TRUE)
773 bss->security = SUPPLICANT_SECURITY_PSK;
774 else if (bss->privacy == TRUE)
775 bss->security = SUPPLICANT_SECURITY_WEP;
777 bss->security = SUPPLICANT_SECURITY_NONE;
779 add_bss_to_network(bss);
783 if (g_strcmp0(key, "BSSID") == 0) {
784 DBusMessageIter array;
788 dbus_message_iter_recurse(iter, &array);
789 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
792 memcpy(bss->bssid, addr, addr_len);
793 } else if (g_strcmp0(key, "SSID") == 0) {
794 DBusMessageIter array;
798 dbus_message_iter_recurse(iter, &array);
799 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
801 if (ssid_len > 0 && ssid_len < 33) {
802 memcpy(bss->ssid, ssid, ssid_len);
803 bss->ssid_len = ssid_len;
805 memset(bss->ssid, 0, sizeof(bss->ssid));
808 } else if (g_strcmp0(key, "Capabilities") == 0) {
809 dbus_uint16_t capabilities = 0x0000;
811 dbus_message_iter_get_basic(iter, &capabilities);
813 if (capabilities & IEEE80211_CAP_ESS)
814 bss->mode = SUPPLICANT_MODE_INFRA;
815 else if (capabilities & IEEE80211_CAP_IBSS)
816 bss->mode = SUPPLICANT_MODE_IBSS;
818 if (capabilities & IEEE80211_CAP_PRIVACY)
820 } else if (g_strcmp0(key, "Mode") == 0) {
821 const char *mode = NULL;
823 dbus_message_iter_get_basic(iter, &mode);
824 bss->mode = string2mode(mode);
825 } else if (g_strcmp0(key, "Frequency") == 0) {
826 dbus_uint16_t frequency = 0;
828 dbus_message_iter_get_basic(iter, &frequency);
829 bss->frequency = frequency;
830 } else if (g_strcmp0(key, "Signal") == 0) {
831 dbus_int16_t signal = 0;
833 dbus_message_iter_get_basic(iter, &signal);
834 } else if (g_strcmp0(key, "Level") == 0) {
835 dbus_int32_t level = 0;
837 dbus_message_iter_get_basic(iter, &level);
838 } else if (g_strcmp0(key, "MaxRate") == 0) {
839 dbus_uint16_t maxrate = 0;
841 dbus_message_iter_get_basic(iter, &maxrate);
842 } else if (g_strcmp0(key, "Privacy") == 0) {
843 dbus_bool_t privacy = FALSE;
845 dbus_message_iter_get_basic(iter, &privacy);
846 bss->privacy = privacy;
847 } else if (g_strcmp0(key, "RSNIE") == 0) {
848 DBusMessageIter array;
852 dbus_message_iter_recurse(iter, &array);
853 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
856 extract_rsn(bss, ie + 2, ie_len - 2);
857 } else if (g_strcmp0(key, "WPAIE") == 0) {
858 DBusMessageIter array;
862 dbus_message_iter_recurse(iter, &array);
863 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
866 extract_rsn(bss, ie + 6, ie_len - 6);
867 } else if (g_strcmp0(key, "WPSIE") == 0) {
868 DBusMessageIter array;
872 dbus_message_iter_recurse(iter, &array);
873 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
875 DBG("key %s type %c",
876 key, dbus_message_iter_get_arg_type(iter));
879 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
881 struct supplicant_interface *interface = user_data;
882 struct supplicant_network *network;
883 struct supplicant_bss *bss;
884 const char *path = NULL;
886 dbus_message_iter_get_basic(iter, &path);
890 if (g_strcmp0(path, "/") == 0)
893 network = g_hash_table_lookup(interface->bss_mapping, path);
894 if (network != NULL) {
895 bss = g_hash_table_lookup(network->bss_table, path);
900 bss = g_try_new0(struct supplicant_bss, 1);
904 bss->interface = interface;
905 bss->path = g_strdup(path);
907 dbus_message_iter_next(iter);
908 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
909 supplicant_dbus_property_foreach(iter, bss_property, bss);
910 bss_property(NULL, NULL, bss);
914 supplicant_dbus_property_get_all(path,
915 SUPPLICANT_INTERFACE ".Interface.BSS",
919 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
921 struct supplicant_interface *interface = user_data;
922 struct supplicant_network *network;
923 const char *path = NULL;
925 dbus_message_iter_get_basic(iter, &path);
929 network = g_hash_table_lookup(interface->bss_mapping, path);
933 g_hash_table_remove(interface->bss_mapping, path);
934 g_hash_table_remove(network->bss_table, path);
936 if (g_hash_table_size(network->bss_table) == 0)
937 g_hash_table_remove(interface->network_table, network->group);
940 static void interface_property(const char *key, DBusMessageIter *iter,
943 struct supplicant_interface *interface = user_data;
945 if (interface == NULL)
949 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
950 interface->keymgmt_capa);
951 debug_strvalmap("AuthAlg capability", authalg_capa_map,
952 interface->authalg_capa);
953 debug_strvalmap("Protocol capability", proto_capa_map,
954 interface->proto_capa);
955 debug_strvalmap("Pairwise capability", pairwise_capa_map,
956 interface->pairwise_capa);
957 debug_strvalmap("Group capability", group_capa_map,
958 interface->group_capa);
959 debug_strvalmap("Scan capability", scan_capa_map,
960 interface->scan_capa);
961 debug_strvalmap("Mode capability", mode_capa_map,
962 interface->mode_capa);
964 callback_interface_added(interface);
968 if (g_strcmp0(key, "Capabilities") == 0) {
969 supplicant_dbus_property_foreach(iter, interface_capability,
971 } else if (g_strcmp0(key, "State") == 0) {
972 const char *str = NULL;
974 dbus_message_iter_get_basic(iter, &str);
976 interface->state = string2state(str);
977 } else if (g_strcmp0(key, "Scanning") == 0) {
978 dbus_bool_t scanning = FALSE;
980 dbus_message_iter_get_basic(iter, &scanning);
981 interface->scanning = scanning;
982 } else if (g_strcmp0(key, "ApScan") == 0) {
985 dbus_message_iter_get_basic(iter, &apscan);
986 interface->apscan = apscan;
987 } else if (g_strcmp0(key, "Ifname") == 0) {
988 const char *str = NULL;
990 dbus_message_iter_get_basic(iter, &str);
992 interface->ifname = g_strdup(str);
993 } else if (g_strcmp0(key, "Driver") == 0) {
994 const char *str = NULL;
996 dbus_message_iter_get_basic(iter, &str);
998 interface->driver = g_strdup(str);
999 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1000 const char *str = NULL;
1002 dbus_message_iter_get_basic(iter, &str);
1004 interface->bridge = g_strdup(str);
1005 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1006 interface_bss_added(iter, interface);
1007 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1008 interface_network_added(iter, interface);
1009 } else if (g_strcmp0(key, "BSSs") == 0) {
1010 supplicant_dbus_array_foreach(iter, interface_bss_added,
1012 } else if (g_strcmp0(key, "Blobs") == 0) {
1013 } else if (g_strcmp0(key, "Networks") == 0) {
1014 supplicant_dbus_array_foreach(iter, interface_network_added,
1017 DBG("key %s type %c",
1018 key, dbus_message_iter_get_arg_type(iter));
1021 static struct supplicant_interface *interface_alloc(const char *path)
1023 struct supplicant_interface *interface;
1025 interface = g_try_new0(struct supplicant_interface, 1);
1026 if (interface == NULL)
1029 interface->path = g_strdup(path);
1031 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1032 NULL, remove_network);
1034 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1037 g_hash_table_replace(interface_table, interface->path, interface);
1042 static void interface_added(DBusMessageIter *iter, void *user_data)
1044 struct supplicant_interface *interface;
1045 const char *path = NULL;
1047 dbus_message_iter_get_basic(iter, &path);
1051 if (g_strcmp0(path, "/") == 0)
1054 interface = g_hash_table_lookup(interface_table, path);
1055 if (interface != NULL)
1058 interface = interface_alloc(path);
1059 if (interface == NULL)
1062 dbus_message_iter_next(iter);
1063 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1064 supplicant_dbus_property_foreach(iter, interface_property,
1066 interface_property(NULL, NULL, interface);
1070 supplicant_dbus_property_get_all(path,
1071 SUPPLICANT_INTERFACE ".Interface",
1072 interface_property, interface);
1075 static void interface_removed(DBusMessageIter *iter, void *user_data)
1077 const char *path = NULL;
1079 dbus_message_iter_get_basic(iter, &path);
1083 g_hash_table_remove(interface_table, path);
1086 static void eap_method(DBusMessageIter *iter, void *user_data)
1088 const char *str = NULL;
1091 dbus_message_iter_get_basic(iter, &str);
1095 for (i = 0; eap_method_map[i].str != NULL; i++)
1096 if (strcmp(str, eap_method_map[i].str) == 0) {
1097 eap_methods |= eap_method_map[i].val;
1102 static void service_property(const char *key, DBusMessageIter *iter,
1106 callback_system_ready();
1110 if (g_strcmp0(key, "DebugParams") == 0) {
1111 DBusMessageIter list;
1113 dbus_message_iter_recurse(iter, &list);
1114 dbus_message_iter_get_basic(&list, &debug_level);
1116 dbus_message_iter_next(&list);
1117 dbus_message_iter_get_basic(&list, &debug_timestamp);
1119 dbus_message_iter_next(&list);
1120 dbus_message_iter_get_basic(&list, &debug_showkeys);
1122 DBG("Debug level %d (timestamp %u show keys %u)",
1123 debug_level, debug_timestamp, debug_showkeys);
1124 } else if (g_strcmp0(key, "DebugLevel") == 0) {
1125 dbus_message_iter_get_basic(iter, &debug_level);
1126 DBG("Debug level %d", debug_level);
1127 } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
1128 dbus_message_iter_get_basic(iter, &debug_timestamp);
1129 DBG("Debug timestamp %u", debug_timestamp);
1130 } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1131 dbus_message_iter_get_basic(iter, &debug_showkeys);
1132 DBG("Debug show keys %u", debug_showkeys);
1133 } else if (g_strcmp0(key, "Interfaces") == 0) {
1134 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1135 } else if (g_strcmp0(key, "EapMethods") == 0) {
1136 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1137 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1139 DBG("key %s type %c",
1140 key, dbus_message_iter_get_arg_type(iter));
1143 static void supplicant_bootstrap(void)
1145 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1146 SUPPLICANT_INTERFACE,
1147 service_property, NULL);
1150 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1152 const char *name = NULL, *old = NULL, *new = NULL;
1154 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1157 dbus_message_iter_get_basic(iter, &name);
1161 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1164 dbus_message_iter_next(iter);
1165 dbus_message_iter_get_basic(iter, &old);
1166 dbus_message_iter_next(iter);
1167 dbus_message_iter_get_basic(iter, &new);
1169 if (old == NULL || new == NULL)
1172 if (strlen(old) > 0 && strlen(new) == 0) {
1173 system_available = FALSE;
1174 g_hash_table_remove_all(interface_table);
1175 callback_system_killed();
1178 if (strlen(new) > 0 && strlen(old) == 0) {
1179 system_available = TRUE;
1180 supplicant_bootstrap();
1184 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1186 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1189 supplicant_dbus_property_foreach(iter, service_property, NULL);
1192 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1194 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1195 interface_added(iter, NULL);
1198 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1200 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1201 interface_removed(iter, NULL);
1204 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1206 struct supplicant_interface *interface;
1208 interface = g_hash_table_lookup(interface_table, path);
1209 if (interface == NULL)
1212 interface_bss_added(iter, interface);
1215 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1217 struct supplicant_interface *interface;
1219 interface = g_hash_table_lookup(interface_table, path);
1220 if (interface == NULL)
1223 interface_bss_removed(iter, interface);
1226 static void signal_network_added(const char *path, DBusMessageIter *iter)
1228 struct supplicant_interface *interface;
1230 interface = g_hash_table_lookup(interface_table, path);
1231 if (interface == NULL)
1234 interface_network_added(iter, interface);
1237 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1239 struct supplicant_interface *interface;
1241 interface = g_hash_table_lookup(interface_table, path);
1242 if (interface == NULL)
1245 interface_network_removed(iter, interface);
1249 const char *interface;
1251 void (*function) (const char *path, DBusMessageIter *iter);
1253 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1255 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1256 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1257 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1258 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1260 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1261 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1262 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1263 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1268 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1269 DBusMessage *message, void *data)
1271 DBusMessageIter iter;
1275 path = dbus_message_get_path(message);
1277 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1279 if (dbus_message_iter_init(message, &iter) == FALSE)
1280 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1282 for (i = 0; signal_map[i].interface != NULL; i++) {
1283 if (dbus_message_has_interface(message,
1284 signal_map[i].interface) == FALSE)
1287 if (dbus_message_has_member(message,
1288 signal_map[i].member) == FALSE)
1291 signal_map[i].function(path, &iter);
1295 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1298 static const char *supplicant_rule0 = "type=signal,"
1299 "path=" DBUS_PATH_DBUS ","
1300 "sender=" DBUS_SERVICE_DBUS ","
1301 "interface=" DBUS_INTERFACE_DBUS ","
1302 "member=NameOwnerChanged,"
1303 "arg0=" SUPPLICANT_SERVICE;
1304 static const char *supplicant_rule1 = "type=signal,"
1305 "interface=" SUPPLICANT_INTERFACE;
1306 static const char *supplicant_rule2 = "type=signal,"
1307 "interface=" SUPPLICANT_INTERFACE ".Interface";
1308 static const char *supplicant_rule3 = "type=signal,"
1309 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1310 static const char *supplicant_rule4 = "type=signal,"
1311 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1312 static const char *supplicant_rule5 = "type=signal,"
1313 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1314 static const char *supplicant_rule6 = "type=signal,"
1315 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1317 int supplicant_register(const struct supplicant_callbacks *callbacks)
1319 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1320 if (connection == NULL)
1323 if (dbus_connection_add_filter(connection,
1324 supplicant_filter, NULL, NULL) == FALSE) {
1325 dbus_connection_unref(connection);
1330 callbacks_pointer = callbacks;
1333 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1334 NULL, remove_interface);
1336 supplicant_dbus_setup(connection);
1338 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1339 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1340 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1341 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1342 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1343 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1344 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1345 dbus_connection_flush(connection);
1347 if (dbus_bus_name_has_owner(connection,
1348 SUPPLICANT_SERVICE, NULL) == TRUE) {
1349 system_available = TRUE;
1350 supplicant_bootstrap();
1356 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1358 if (connection != NULL) {
1359 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1360 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1361 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1362 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1363 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1364 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1365 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1366 dbus_connection_flush(connection);
1368 dbus_connection_remove_filter(connection,
1369 supplicant_filter, NULL);
1372 if (interface_table != NULL) {
1373 g_hash_table_destroy(interface_table);
1374 interface_table = NULL;
1377 if (system_available == TRUE)
1378 callback_system_killed();
1380 if (connection != NULL) {
1381 dbus_connection_unref(connection);
1385 callbacks_pointer = NULL;
1389 static void debug_level_result(const char *error,
1390 DBusMessageIter *iter, void *user_data)
1393 DBG("debug level failure: %s", error);
1396 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1398 dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1399 DBusMessageIter entry;
1401 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1404 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1405 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1407 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1410 dbus_message_iter_close_container(iter, &entry);
1413 void supplicant_set_debug_level(unsigned int level)
1415 if (system_available == FALSE)
1418 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1419 "DebugParams", "(ibb)", add_debug_level,
1420 debug_level_result, GUINT_TO_POINTER(level));
1423 struct interface_create_data {
1426 struct supplicant_interface *interface;
1427 supplicant_interface_create_callback callback;
1431 static void interface_create_property(const char *key, DBusMessageIter *iter,
1434 struct interface_create_data *data = user_data;
1435 struct supplicant_interface *interface = data->interface;
1438 if (data->callback != NULL)
1439 data->callback(0, data->interface, data->user_data);
1444 interface_property(key, iter, interface);
1447 static void interface_create_result(const char *error,
1448 DBusMessageIter *iter, void *user_data)
1450 struct interface_create_data *data = user_data;
1451 const char *path = NULL;
1454 if (error != NULL) {
1459 dbus_message_iter_get_basic(iter, &path);
1465 if (system_available == FALSE) {
1470 data->interface = g_hash_table_lookup(interface_table, path);
1471 if (data->interface == NULL) {
1472 data->interface = interface_alloc(path);
1473 if (data->interface == NULL) {
1479 err = supplicant_dbus_property_get_all(path,
1480 SUPPLICANT_INTERFACE ".Interface",
1481 interface_create_property, data);
1486 if (data->callback != NULL)
1487 data->callback(err, NULL, data->user_data);
1492 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1494 struct interface_create_data *data = user_data;
1495 DBusMessageIter dict;
1497 supplicant_dbus_dict_open(iter, &dict);
1499 supplicant_dbus_dict_append_basic(&dict, "Ifname",
1500 DBUS_TYPE_STRING, &data->ifname);
1501 supplicant_dbus_dict_append_basic(&dict, "Driver",
1502 DBUS_TYPE_STRING, &data->driver);
1504 supplicant_dbus_dict_close(iter, &dict);
1507 static void interface_get_result(const char *error,
1508 DBusMessageIter *iter, void *user_data)
1510 struct interface_create_data *data = user_data;
1511 struct supplicant_interface *interface;
1512 const char *path = NULL;
1515 if (error != NULL) {
1520 dbus_message_iter_get_basic(iter, &path);
1526 interface = g_hash_table_lookup(interface_table, path);
1527 if (interface == NULL) {
1532 if (data->callback != NULL)
1533 data->callback(0, interface, data->user_data);
1540 if (system_available == FALSE) {
1545 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1546 SUPPLICANT_INTERFACE,
1548 interface_create_params,
1549 interface_create_result, data);
1554 if (data->callback != NULL)
1555 data->callback(err, NULL, data->user_data);
1560 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1562 struct interface_create_data *data = user_data;
1564 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1567 int supplicant_interface_create(const char *ifname, const char *driver,
1568 supplicant_interface_create_callback callback,
1571 struct interface_create_data *data;
1573 if (system_available == FALSE)
1576 data = dbus_malloc0(sizeof(*data));
1580 data->ifname = ifname;
1581 data->driver = driver;
1582 data->callback = callback;
1583 data->user_data = user_data;
1585 return supplicant_dbus_method_call(SUPPLICANT_PATH,
1586 SUPPLICANT_INTERFACE,
1588 interface_get_params,
1589 interface_get_result, data);
1592 int supplicant_interface_remove(struct supplicant_interface *interface,
1593 supplicant_interface_remove_callback callback,
1596 if (system_available == FALSE)