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 //struct supplicant_interface *interface = user_data;
513 const char *path = NULL;
515 dbus_message_iter_get_basic(iter, &path);
519 if (g_strcmp0(path, "/") == 0)
522 dbus_message_iter_next(iter);
523 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
524 supplicant_dbus_property_foreach(iter, network_property, NULL);
525 network_property(NULL, NULL, NULL);
529 supplicant_dbus_property_get_all(path,
530 SUPPLICANT_INTERFACE ".Interface.Network",
531 network_property, NULL);
534 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
536 const char *path = NULL;
538 dbus_message_iter_get_basic(iter, &path);
542 DBG("path %s", path);
545 static char *create_name(unsigned char *ssid, int ssid_len)
550 if (ssid_len < 1 || ssid[0] == '\0')
553 name = g_try_malloc0(ssid_len + 1);
558 for (i = 0; i < ssid_len; i++) {
559 if (g_ascii_isprint(ssid[i]))
568 static char *create_group(struct supplicant_bss *bss)
572 const char *mode, *security;
574 str = g_string_sized_new((bss->ssid_len * 2) + 24);
578 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
579 for (i = 0; i < bss->ssid_len; i++)
580 g_string_append_printf(str, "%02x", bss->ssid[i]);
582 g_string_append_printf(str, "hidden");
584 mode = mode2string(bss->mode);
586 g_string_append_printf(str, "_%s", mode);
588 security = security2string(bss->security);
589 if (security != NULL)
590 g_string_append_printf(str, "_%s", security);
592 return g_string_free(str, FALSE);
595 static void add_bss_to_network(struct supplicant_bss *bss)
597 struct supplicant_interface *interface = bss->interface;
598 struct supplicant_network *network;
601 group = create_group(bss);
605 network = g_hash_table_lookup(interface->network_table, group);
606 if (network != NULL) {
611 network = g_try_new0(struct supplicant_network, 1);
612 if (network == NULL) {
617 network->group = group;
618 network->name = create_name(bss->ssid, bss->ssid_len);
619 network->mode = bss->mode;
621 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
624 g_hash_table_replace(interface->network_table,
625 network->group, network);
627 callback_network_added(network);
630 g_hash_table_replace(interface->bss_mapping, bss->path, network);
631 g_hash_table_replace(network->bss_table, bss->path, bss);
634 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
635 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
637 static void extract_rsn(struct supplicant_bss *bss,
638 const unsigned char *buf, int len)
657 /* Pairwise cipher */
661 count = buf[0] | (buf[1] << 8);
662 if (2 + (count * 4) > len)
665 buf += 2 + (count * 4);
666 len -= 2 + (count * 4);
672 count = buf[0] | (buf[1] << 8);
673 if (2 + (count * 4) > len)
676 for (i = 0; i < count; i++) {
677 const unsigned char *ptr = buf + 2 + (i * 4);
679 if (memcmp(ptr, wifi_oui, 3) == 0) {
682 bss->ieee8021x = TRUE;
688 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
691 bss->ieee8021x = TRUE;
700 buf += 2 + (count * 4);
701 len -= 2 + (count * 4);
704 static void bss_property(const char *key, DBusMessageIter *iter,
707 struct supplicant_bss *bss = user_data;
709 if (bss->interface == NULL)
713 if (bss->ieee8021x == TRUE)
714 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
715 else if (bss->psk == TRUE)
716 bss->security = SUPPLICANT_SECURITY_PSK;
717 else if (bss->privacy == TRUE)
718 bss->security = SUPPLICANT_SECURITY_WEP;
720 bss->security = SUPPLICANT_SECURITY_NONE;
722 add_bss_to_network(bss);
726 if (g_strcmp0(key, "BSSID") == 0) {
727 DBusMessageIter array;
731 dbus_message_iter_recurse(iter, &array);
732 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
735 memcpy(bss->bssid, addr, addr_len);
736 } else if (g_strcmp0(key, "SSID") == 0) {
737 DBusMessageIter array;
741 dbus_message_iter_recurse(iter, &array);
742 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
744 if (ssid_len > 0 && ssid_len < 33) {
745 memcpy(bss->ssid, ssid, ssid_len);
746 bss->ssid_len = ssid_len;
748 memset(bss->ssid, 0, sizeof(bss->ssid));
751 } else if (g_strcmp0(key, "Capabilities") == 0) {
752 dbus_uint16_t capabilities = 0x0000;
754 dbus_message_iter_get_basic(iter, &capabilities);
756 if (capabilities & IEEE80211_CAP_ESS)
757 bss->mode = SUPPLICANT_MODE_INFRA;
758 else if (capabilities & IEEE80211_CAP_IBSS)
759 bss->mode = SUPPLICANT_MODE_IBSS;
761 if (capabilities & IEEE80211_CAP_PRIVACY)
763 } else if (g_strcmp0(key, "Mode") == 0) {
764 const char *mode = NULL;
766 dbus_message_iter_get_basic(iter, &mode);
767 bss->mode = string2mode(mode);
768 } else if (g_strcmp0(key, "Frequency") == 0) {
769 dbus_uint16_t frequency = 0;
771 dbus_message_iter_get_basic(iter, &frequency);
772 bss->frequency = frequency;
773 } else if (g_strcmp0(key, "Signal") == 0) {
774 dbus_int16_t signal = 0;
776 dbus_message_iter_get_basic(iter, &signal);
777 } else if (g_strcmp0(key, "Level") == 0) {
778 dbus_int32_t level = 0;
780 dbus_message_iter_get_basic(iter, &level);
781 } else if (g_strcmp0(key, "MaxRate") == 0) {
782 dbus_uint16_t maxrate = 0;
784 dbus_message_iter_get_basic(iter, &maxrate);
785 } else if (g_strcmp0(key, "Privacy") == 0) {
786 dbus_bool_t privacy = FALSE;
788 dbus_message_iter_get_basic(iter, &privacy);
789 bss->privacy = privacy;
790 } else if (g_strcmp0(key, "RSNIE") == 0) {
791 DBusMessageIter array;
795 dbus_message_iter_recurse(iter, &array);
796 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
799 extract_rsn(bss, ie + 2, ie_len - 2);
800 } else if (g_strcmp0(key, "WPAIE") == 0) {
801 DBusMessageIter array;
805 dbus_message_iter_recurse(iter, &array);
806 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
809 extract_rsn(bss, ie + 6, ie_len - 6);
810 } else if (g_strcmp0(key, "WPSIE") == 0) {
811 DBusMessageIter array;
815 dbus_message_iter_recurse(iter, &array);
816 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
818 DBG("key %s type %c",
819 key, dbus_message_iter_get_arg_type(iter));
822 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
824 struct supplicant_interface *interface = user_data;
825 struct supplicant_network *network;
826 struct supplicant_bss *bss;
827 const char *path = NULL;
829 dbus_message_iter_get_basic(iter, &path);
833 if (g_strcmp0(path, "/") == 0)
836 network = g_hash_table_lookup(interface->bss_mapping, path);
837 if (network != NULL) {
838 bss = g_hash_table_lookup(network->bss_table, path);
843 bss = g_try_new0(struct supplicant_bss, 1);
847 bss->interface = interface;
848 bss->path = g_strdup(path);
850 dbus_message_iter_next(iter);
851 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
852 supplicant_dbus_property_foreach(iter, bss_property, bss);
853 bss_property(NULL, NULL, bss);
857 supplicant_dbus_property_get_all(path,
858 SUPPLICANT_INTERFACE ".Interface.BSS",
862 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
864 struct supplicant_interface *interface = user_data;
865 struct supplicant_network *network;
866 const char *path = NULL;
868 dbus_message_iter_get_basic(iter, &path);
872 network = g_hash_table_lookup(interface->bss_mapping, path);
876 g_hash_table_remove(interface->bss_mapping, path);
877 g_hash_table_remove(network->bss_table, path);
879 if (g_hash_table_size(network->bss_table) == 0)
880 g_hash_table_remove(interface->network_table, network->group);
883 static void interface_property(const char *key, DBusMessageIter *iter,
886 struct supplicant_interface *interface = user_data;
888 if (interface == NULL)
892 debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
893 interface->keymgmt_capa);
894 debug_strvalmap("AuthAlg capability", authalg_capa_map,
895 interface->authalg_capa);
896 debug_strvalmap("Protocol capability", proto_capa_map,
897 interface->proto_capa);
898 debug_strvalmap("Scan capability", scan_capa_map,
899 interface->scan_capa);
900 debug_strvalmap("Mode capability", mode_capa_map,
901 interface->mode_capa);
903 callback_interface_added(interface);
907 if (g_strcmp0(key, "Capabilities") == 0) {
908 supplicant_dbus_property_foreach(iter, interface_capability,
910 } else if (g_strcmp0(key, "State") == 0) {
911 const char *str = NULL;
913 dbus_message_iter_get_basic(iter, &str);
915 interface->state = string2state(str);
916 } else if (g_strcmp0(key, "Scanning") == 0) {
917 dbus_bool_t scanning = FALSE;
919 dbus_message_iter_get_basic(iter, &scanning);
920 interface->scanning = scanning;
921 } else if (g_strcmp0(key, "ApScan") == 0) {
924 dbus_message_iter_get_basic(iter, &apscan);
925 interface->apscan = apscan;
926 } else if (g_strcmp0(key, "Ifname") == 0) {
927 const char *str = NULL;
929 dbus_message_iter_get_basic(iter, &str);
931 interface->ifname = g_strdup(str);
932 } else if (g_strcmp0(key, "Driver") == 0) {
933 const char *str = NULL;
935 dbus_message_iter_get_basic(iter, &str);
937 interface->driver = g_strdup(str);
938 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
939 const char *str = NULL;
941 dbus_message_iter_get_basic(iter, &str);
943 interface->bridge = g_strdup(str);
944 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
945 interface_bss_added(iter, interface);
946 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
947 interface_network_added(iter, interface);
948 } else if (g_strcmp0(key, "BSSs") == 0) {
949 supplicant_dbus_array_foreach(iter, interface_bss_added,
951 } else if (g_strcmp0(key, "Blobs") == 0) {
952 } else if (g_strcmp0(key, "Networks") == 0) {
953 supplicant_dbus_array_foreach(iter, interface_network_added,
956 DBG("key %s type %c",
957 key, dbus_message_iter_get_arg_type(iter));
960 static struct supplicant_interface *interface_alloc(const char *path)
962 struct supplicant_interface *interface;
964 interface = g_try_new0(struct supplicant_interface, 1);
965 if (interface == NULL)
968 interface->path = g_strdup(path);
970 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
971 NULL, remove_network);
973 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
976 g_hash_table_replace(interface_table, interface->path, interface);
981 static void interface_added(DBusMessageIter *iter, void *user_data)
983 struct supplicant_interface *interface;
984 const char *path = NULL;
986 dbus_message_iter_get_basic(iter, &path);
990 if (g_strcmp0(path, "/") == 0)
993 interface = g_hash_table_lookup(interface_table, path);
994 if (interface != NULL)
997 interface = interface_alloc(path);
998 if (interface == NULL)
1001 dbus_message_iter_next(iter);
1002 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1003 supplicant_dbus_property_foreach(iter, interface_property,
1005 interface_property(NULL, NULL, interface);
1009 supplicant_dbus_property_get_all(path,
1010 SUPPLICANT_INTERFACE ".Interface",
1011 interface_property, interface);
1014 static void interface_removed(DBusMessageIter *iter, void *user_data)
1016 const char *path = NULL;
1018 dbus_message_iter_get_basic(iter, &path);
1022 g_hash_table_remove(interface_table, path);
1025 static void eap_method(DBusMessageIter *iter, void *user_data)
1027 const char *str = NULL;
1030 dbus_message_iter_get_basic(iter, &str);
1034 for (i = 0; eap_method_map[i].str != NULL; i++)
1035 if (strcmp(str, eap_method_map[i].str) == 0) {
1036 eap_methods |= eap_method_map[i].val;
1041 static void service_property(const char *key, DBusMessageIter *iter,
1045 callback_system_ready();
1049 if (g_strcmp0(key, "DebugParams") == 0) {
1050 DBusMessageIter list;
1052 dbus_message_iter_recurse(iter, &list);
1053 dbus_message_iter_get_basic(&list, &debug_level);
1055 dbus_message_iter_next(&list);
1056 dbus_message_iter_get_basic(&list, &debug_timestamp);
1058 dbus_message_iter_next(&list);
1059 dbus_message_iter_get_basic(&list, &debug_showkeys);
1061 DBG("Debug level %d (timestamp %u show keys %u)",
1062 debug_level, debug_timestamp, debug_showkeys);
1063 } else if (g_strcmp0(key, "DebugLevel") == 0) {
1064 dbus_message_iter_get_basic(iter, &debug_level);
1065 DBG("Debug level %d", debug_level);
1066 } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
1067 dbus_message_iter_get_basic(iter, &debug_timestamp);
1068 DBG("Debug timestamp %u", debug_timestamp);
1069 } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1070 dbus_message_iter_get_basic(iter, &debug_showkeys);
1071 DBG("Debug show keys %u", debug_showkeys);
1072 } else if (g_strcmp0(key, "Interfaces") == 0) {
1073 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1074 } else if (g_strcmp0(key, "EapMethods") == 0) {
1075 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1076 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1078 DBG("key %s type %c",
1079 key, dbus_message_iter_get_arg_type(iter));
1082 static void supplicant_bootstrap(void)
1084 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1085 SUPPLICANT_INTERFACE,
1086 service_property, NULL);
1089 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1091 const char *name = NULL, *old = NULL, *new = NULL;
1093 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1096 dbus_message_iter_get_basic(iter, &name);
1100 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1103 dbus_message_iter_next(iter);
1104 dbus_message_iter_get_basic(iter, &old);
1105 dbus_message_iter_next(iter);
1106 dbus_message_iter_get_basic(iter, &new);
1108 if (old == NULL || new == NULL)
1111 if (strlen(old) > 0 && strlen(new) == 0) {
1112 system_available = FALSE;
1113 g_hash_table_remove_all(interface_table);
1114 callback_system_killed();
1117 if (strlen(new) > 0 && strlen(old) == 0) {
1118 system_available = TRUE;
1119 supplicant_bootstrap();
1123 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1125 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1128 supplicant_dbus_property_foreach(iter, service_property, NULL);
1131 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1133 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1134 interface_added(iter, NULL);
1137 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1139 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1140 interface_removed(iter, NULL);
1143 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1145 struct supplicant_interface *interface;
1147 interface = g_hash_table_lookup(interface_table, path);
1148 if (interface == NULL)
1151 interface_bss_added(iter, interface);
1154 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1156 struct supplicant_interface *interface;
1158 interface = g_hash_table_lookup(interface_table, path);
1159 if (interface == NULL)
1162 interface_bss_removed(iter, interface);
1165 static void signal_network_added(const char *path, DBusMessageIter *iter)
1167 struct supplicant_interface *interface;
1169 interface = g_hash_table_lookup(interface_table, path);
1170 if (interface == NULL)
1173 interface_network_added(iter, interface);
1176 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1178 struct supplicant_interface *interface;
1180 interface = g_hash_table_lookup(interface_table, path);
1181 if (interface == NULL)
1184 interface_network_removed(iter, interface);
1188 const char *interface;
1190 void (*function) (const char *path, DBusMessageIter *iter);
1192 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1194 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1195 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1196 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1197 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1199 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1200 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1201 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1202 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1207 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1208 DBusMessage *message, void *data)
1210 DBusMessageIter iter;
1214 path = dbus_message_get_path(message);
1216 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1218 if (dbus_message_iter_init(message, &iter) == FALSE)
1219 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1221 for (i = 0; signal_map[i].interface != NULL; i++) {
1222 if (dbus_message_has_interface(message,
1223 signal_map[i].interface) == FALSE)
1226 if (dbus_message_has_member(message,
1227 signal_map[i].member) == FALSE)
1230 signal_map[i].function(path, &iter);
1234 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1237 static const char *supplicant_rule0 = "type=signal,"
1238 "path=" DBUS_PATH_DBUS ","
1239 "sender=" DBUS_SERVICE_DBUS ","
1240 "interface=" DBUS_INTERFACE_DBUS ","
1241 "member=NameOwnerChanged,"
1242 "arg0=" SUPPLICANT_SERVICE;
1243 static const char *supplicant_rule1 = "type=signal,"
1244 "interface=" SUPPLICANT_INTERFACE;
1245 static const char *supplicant_rule2 = "type=signal,"
1246 "interface=" SUPPLICANT_INTERFACE ".Interface";
1247 static const char *supplicant_rule3 = "type=signal,"
1248 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1249 static const char *supplicant_rule4 = "type=signal,"
1250 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1251 static const char *supplicant_rule5 = "type=signal,"
1252 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1253 static const char *supplicant_rule6 = "type=signal,"
1254 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1256 int supplicant_register(const struct supplicant_callbacks *callbacks)
1258 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1259 if (connection == NULL)
1262 if (dbus_connection_add_filter(connection,
1263 supplicant_filter, NULL, NULL) == FALSE) {
1264 dbus_connection_unref(connection);
1269 callbacks_pointer = callbacks;
1272 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1273 NULL, remove_interface);
1275 supplicant_dbus_setup(connection);
1277 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1278 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1279 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1280 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1281 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1282 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1283 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1284 dbus_connection_flush(connection);
1286 if (dbus_bus_name_has_owner(connection,
1287 SUPPLICANT_SERVICE, NULL) == TRUE) {
1288 system_available = TRUE;
1289 supplicant_bootstrap();
1295 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1297 if (connection != NULL) {
1298 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1299 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1300 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1301 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1302 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1303 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1304 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1305 dbus_connection_flush(connection);
1307 dbus_connection_remove_filter(connection,
1308 supplicant_filter, NULL);
1311 if (interface_table != NULL) {
1312 g_hash_table_destroy(interface_table);
1313 interface_table = NULL;
1316 if (system_available == TRUE)
1317 callback_system_killed();
1319 if (connection != NULL) {
1320 dbus_connection_unref(connection);
1324 callbacks_pointer = NULL;
1328 static void debug_level_result(const char *error,
1329 DBusMessageIter *iter, void *user_data)
1332 DBG("debug level failure: %s", error);
1335 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1337 dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1338 DBusMessageIter entry;
1340 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1343 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1344 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1346 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1349 dbus_message_iter_close_container(iter, &entry);
1352 void supplicant_set_debug_level(unsigned int level)
1354 if (system_available == FALSE)
1357 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1358 "DebugParams", "(ibb)", add_debug_level,
1359 debug_level_result, GUINT_TO_POINTER(level));
1362 struct interface_create_data {
1365 struct supplicant_interface *interface;
1366 supplicant_interface_create_callback callback;
1370 static void interface_create_property(const char *key, DBusMessageIter *iter,
1373 struct interface_create_data *data = user_data;
1374 struct supplicant_interface *interface = data->interface;
1377 if (data->callback != NULL)
1378 data->callback(0, data->interface, data->user_data);
1383 interface_property(key, iter, interface);
1386 static void interface_create_result(const char *error,
1387 DBusMessageIter *iter, void *user_data)
1389 struct interface_create_data *data = user_data;
1390 const char *path = NULL;
1393 if (error != NULL) {
1398 dbus_message_iter_get_basic(iter, &path);
1404 if (system_available == FALSE) {
1409 data->interface = g_hash_table_lookup(interface_table, path);
1410 if (data->interface == NULL) {
1411 data->interface = interface_alloc(path);
1412 if (data->interface == NULL) {
1418 err = supplicant_dbus_property_get_all(path,
1419 SUPPLICANT_INTERFACE ".Interface",
1420 interface_create_property, data);
1425 if (data->callback != NULL)
1426 data->callback(err, NULL, data->user_data);
1431 static void interface_create_params(DBusMessageIter *iter, void *user_data)
1433 struct interface_create_data *data = user_data;
1434 DBusMessageIter dict;
1436 supplicant_dbus_dict_open(iter, &dict);
1438 supplicant_dbus_dict_append_basic(&dict, "Ifname",
1439 DBUS_TYPE_STRING, &data->ifname);
1440 supplicant_dbus_dict_append_basic(&dict, "Driver",
1441 DBUS_TYPE_STRING, &data->driver);
1443 supplicant_dbus_dict_close(iter, &dict);
1446 static void interface_get_result(const char *error,
1447 DBusMessageIter *iter, void *user_data)
1449 struct interface_create_data *data = user_data;
1450 struct supplicant_interface *interface;
1451 const char *path = NULL;
1454 if (error != NULL) {
1459 dbus_message_iter_get_basic(iter, &path);
1465 interface = g_hash_table_lookup(interface_table, path);
1466 if (interface == NULL) {
1471 if (data->callback != NULL)
1472 data->callback(0, interface, data->user_data);
1479 if (system_available == FALSE) {
1484 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
1485 SUPPLICANT_INTERFACE,
1487 interface_create_params,
1488 interface_create_result, data);
1493 if (data->callback != NULL)
1494 data->callback(err, NULL, data->user_data);
1499 static void interface_get_params(DBusMessageIter *iter, void *user_data)
1501 struct interface_create_data *data = user_data;
1503 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
1506 int supplicant_interface_create(const char *ifname, const char *driver,
1507 supplicant_interface_create_callback callback,
1510 struct interface_create_data *data;
1512 if (system_available == FALSE)
1515 data = dbus_malloc0(sizeof(*data));
1519 data->ifname = ifname;
1520 data->driver = driver;
1521 data->callback = callback;
1522 data->user_data = user_data;
1524 return supplicant_dbus_method_call(SUPPLICANT_PATH,
1525 SUPPLICANT_INTERFACE,
1527 interface_get_params,
1528 interface_get_result, data);
1531 int supplicant_interface_remove(struct supplicant_interface *interface,
1532 supplicant_interface_remove_callback callback,
1535 if (system_available == FALSE)