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;
53 static dbus_int32_t debug_level = 0;
54 static dbus_bool_t debug_show_timestamps = FALSE;
55 static dbus_bool_t debug_show_keys = FALSE;
57 static unsigned int eap_methods;
64 static struct strvalmap eap_method_map[] = {
65 { "MD5", SUPPLICANT_EAP_METHOD_MD5 },
66 { "TLS", SUPPLICANT_EAP_METHOD_TLS },
67 { "MSCHAPV2", SUPPLICANT_EAP_METHOD_MSCHAPV2 },
68 { "PEAP", SUPPLICANT_EAP_METHOD_PEAP },
69 { "TTLS", SUPPLICANT_EAP_METHOD_TTLS },
70 { "GTC", SUPPLICANT_EAP_METHOD_GTC },
71 { "OTP", SUPPLICANT_EAP_METHOD_OTP },
72 { "LEAP", SUPPLICANT_EAP_METHOD_LEAP },
76 static struct strvalmap auth_capa_map[] = {
77 { "open", SUPPLICANT_CAPABILITY_AUTH_OPEN },
78 { "shared", SUPPLICANT_CAPABILITY_AUTH_SHARED },
79 { "leap", SUPPLICANT_CAPABILITY_AUTH_LEAP },
83 static struct strvalmap scan_capa_map[] = {
84 { "active", SUPPLICANT_CAPABILITY_SCAN_ACTIVE },
85 { "passive", SUPPLICANT_CAPABILITY_SCAN_PASSIVE },
86 { "ssid", SUPPLICANT_CAPABILITY_SCAN_SSID },
90 static struct strvalmap mode_capa_map[] = {
91 { "infrastructure", SUPPLICANT_CAPABILITY_MODE_INFRA },
92 { "ad-hoc", SUPPLICANT_CAPABILITY_MODE_IBSS },
93 { "ap", SUPPLICANT_CAPABILITY_MODE_AP },
97 static GHashTable *interface_table;
99 struct supplicant_interface {
101 unsigned int auth_capa;
102 unsigned int scan_capa;
103 unsigned int mode_capa;
104 enum supplicant_state state;
105 dbus_bool_t scanning;
110 GHashTable *network_table;
111 GHashTable *bss_mapping;
114 struct supplicant_network {
115 struct supplicant_interface *interface;
118 enum supplicant_mode mode;
119 GHashTable *bss_table;
122 struct supplicant_bss {
123 struct supplicant_interface *interface;
125 unsigned char bssid[6];
126 unsigned char ssid[32];
127 unsigned int ssid_len;
128 unsigned int frequency;
129 enum supplicant_mode mode;
130 enum supplicant_security security;
133 dbus_bool_t ieee8021x;
136 static const char *mode2string(enum supplicant_mode mode)
139 case SUPPLICANT_MODE_UNKNOWN:
141 case SUPPLICANT_MODE_INFRA:
143 case SUPPLICANT_MODE_IBSS:
150 static const char *security2string(enum supplicant_security security)
153 case SUPPLICANT_SECURITY_UNKNOWN:
155 case SUPPLICANT_SECURITY_NONE:
157 case SUPPLICANT_SECURITY_WEP:
159 case SUPPLICANT_SECURITY_PSK:
161 case SUPPLICANT_SECURITY_IEEE8021X:
168 static enum supplicant_state string2state(const char *state)
171 return SUPPLICANT_STATE_UNKNOWN;
173 if (g_str_equal(state, "unknown") == TRUE)
174 return SUPPLICANT_STATE_UNKNOWN;
175 else if (g_str_equal(state, "disconnected") == TRUE)
176 return SUPPLICANT_STATE_DISCONNECTED;
177 else if (g_str_equal(state, "inactive") == TRUE)
178 return SUPPLICANT_STATE_INACTIVE;
179 else if (g_str_equal(state, "scanning") == TRUE)
180 return SUPPLICANT_STATE_SCANNING;
181 else if (g_str_equal(state, "authenticating") == TRUE)
182 return SUPPLICANT_STATE_AUTHENTICATING;
183 else if (g_str_equal(state, "associating") == TRUE)
184 return SUPPLICANT_STATE_ASSOCIATING;
185 else if (g_str_equal(state, "associated") == TRUE)
186 return SUPPLICANT_STATE_ASSOCIATED;
187 else if (g_str_equal(state, "group_handshake") == TRUE)
188 return SUPPLICANT_STATE_GROUP_HANDSHAKE;
189 else if (g_str_equal(state, "4way_handshake") == TRUE)
190 return SUPPLICANT_STATE_4WAY_HANDSHAKE;
191 else if (g_str_equal(state, "completed") == TRUE)
192 return SUPPLICANT_STATE_COMPLETED;
194 return SUPPLICANT_STATE_UNKNOWN;
197 static void callback_system_ready(void)
199 if (callbacks_pointer == NULL)
202 if (callbacks_pointer->system_ready == NULL)
205 callbacks_pointer->system_ready();
208 static void callback_system_killed(void)
210 if (callbacks_pointer == NULL)
213 if (callbacks_pointer->system_killed == NULL)
216 callbacks_pointer->system_killed();
219 static void callback_interface_added(struct supplicant_interface *interface)
221 if (callbacks_pointer == NULL)
224 if (callbacks_pointer->interface_added == NULL)
227 callbacks_pointer->interface_added(interface);
230 static void callback_interface_removed(struct supplicant_interface *interface)
232 if (callbacks_pointer == NULL)
235 if (callbacks_pointer->interface_removed == NULL)
238 callbacks_pointer->interface_removed(interface);
241 static void callback_network_added(struct supplicant_network *network)
243 if (callbacks_pointer == NULL)
246 if (callbacks_pointer->network_added == NULL)
249 callbacks_pointer->network_added(network);
252 static void callback_network_removed(struct supplicant_network *network)
254 if (callbacks_pointer == NULL)
257 if (callbacks_pointer->network_removed == NULL)
260 callbacks_pointer->network_removed(network);
263 static void remove_interface(gpointer data)
265 struct supplicant_interface *interface = data;
267 callback_interface_removed(interface);
269 g_hash_table_destroy(interface->bss_mapping);
270 g_hash_table_destroy(interface->network_table);
272 g_free(interface->path);
273 g_free(interface->ifname);
274 g_free(interface->driver);
275 g_free(interface->bridge);
279 static void remove_network(gpointer data)
281 struct supplicant_network *network = data;
283 callback_network_removed(network);
285 g_free(network->group);
286 g_free(network->name);
290 static void remove_bss(gpointer data)
292 struct supplicant_bss *bss = data;
298 static void debug_strvalmap(const char *label, struct strvalmap *map,
303 for (i = 0; map[i].str != NULL; i++) {
304 if (val & map[i].val)
305 DBG("%s: %s", label, map[i].str);
309 static void interface_capability_auth(DBusMessageIter *iter, void *user_data)
311 struct supplicant_interface *interface = user_data;
312 const char *str = NULL;
315 dbus_message_iter_get_basic(iter, &str);
319 for (i = 0; auth_capa_map[i].str != NULL; i++)
320 if (strcmp(str, auth_capa_map[i].str) == 0) {
321 interface->auth_capa |= auth_capa_map[i].val;
326 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
328 struct supplicant_interface *interface = user_data;
329 const char *str = NULL;
332 dbus_message_iter_get_basic(iter, &str);
336 for (i = 0; scan_capa_map[i].str != NULL; i++)
337 if (strcmp(str, scan_capa_map[i].str) == 0) {
338 interface->scan_capa |= scan_capa_map[i].val;
343 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
345 struct supplicant_interface *interface = user_data;
346 const char *str = NULL;
349 dbus_message_iter_get_basic(iter, &str);
353 for (i = 0; mode_capa_map[i].str != NULL; i++)
354 if (strcmp(str, mode_capa_map[i].str) == 0) {
355 interface->mode_capa |= mode_capa_map[i].val;
360 static void interface_capability(const char *key, DBusMessageIter *iter,
363 struct supplicant_interface *interface = user_data;
368 if (g_strcmp0(key, "AuthAlg") == 0)
369 supplicant_dbus_array_foreach(iter, interface_capability_auth,
371 else if (g_strcmp0(key, "Scan") == 0)
372 supplicant_dbus_array_foreach(iter, interface_capability_scan,
374 else if (g_strcmp0(key, "Modes") == 0)
375 supplicant_dbus_array_foreach(iter, interface_capability_mode,
378 DBG("key %s type %c",
379 key, dbus_message_iter_get_arg_type(iter));
382 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
384 if (interface == NULL)
387 return interface->ifname;
390 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
395 return network->interface;
398 const char *supplicant_network_get_name(struct supplicant_network *network)
400 if (network == NULL || network->name == NULL)
403 return network->name;
406 const char *supplicant_network_get_identifier(struct supplicant_network *network)
408 if (network == NULL || network->group == NULL)
411 return network->group;
414 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
417 return SUPPLICANT_MODE_UNKNOWN;
419 return network->mode;
422 static void network_property(const char *key, DBusMessageIter *iter,
428 DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
431 static void interface_network_added(DBusMessageIter *iter, void *user_data)
433 const char *path = NULL;
435 dbus_message_iter_get_basic(iter, &path);
439 DBG("path %s", path);
441 supplicant_dbus_property_get_all(path,
442 SUPPLICANT_INTERFACE ".Interface.Network",
443 network_property, NULL);
446 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
448 const char *path = NULL;
450 dbus_message_iter_get_basic(iter, &path);
454 DBG("path %s", path);
457 static char *create_name(unsigned char *ssid, int ssid_len)
462 if (ssid_len < 1 || ssid[0] == '\0')
465 name = g_try_malloc0(ssid_len + 1);
470 for (i = 0; i < ssid_len; i++) {
471 if (g_ascii_isprint(ssid[i]))
480 static char *create_group(struct supplicant_bss *bss)
484 const char *mode, *security;
486 str = g_string_sized_new((bss->ssid_len * 2) + 24);
490 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
491 for (i = 0; i < bss->ssid_len; i++)
492 g_string_append_printf(str, "%02x", bss->ssid[i]);
494 g_string_append_printf(str, "hidden");
496 mode = mode2string(bss->mode);
498 g_string_append_printf(str, "_%s", mode);
500 security = security2string(bss->security);
501 if (security != NULL)
502 g_string_append_printf(str, "_%s", security);
504 return g_string_free(str, FALSE);
507 static void add_bss_to_network(struct supplicant_bss *bss)
509 struct supplicant_interface *interface = bss->interface;
510 struct supplicant_network *network;
513 group = create_group(bss);
517 network = g_hash_table_lookup(interface->network_table, group);
518 if (network != NULL) {
523 network = g_try_new0(struct supplicant_network, 1);
524 if (network == NULL) {
529 network->group = group;
530 network->name = create_name(bss->ssid, bss->ssid_len);
531 network->mode = bss->mode;
533 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
536 g_hash_table_replace(interface->network_table,
537 network->group, network);
539 callback_network_added(network);
542 g_hash_table_replace(interface->bss_mapping, bss->path, network);
543 g_hash_table_replace(network->bss_table, bss->path, bss);
546 static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
547 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
549 static void extract_rsn(struct supplicant_bss *bss,
550 const unsigned char *buf, int len)
569 /* Pairwise cipher */
573 count = buf[0] | (buf[1] << 8);
574 if (2 + (count * 4) > len)
577 buf += 2 + (count * 4);
578 len -= 2 + (count * 4);
584 count = buf[0] | (buf[1] << 8);
585 if (2 + (count * 4) > len)
588 for (i = 0; i < count; i++) {
589 const unsigned char *ptr = buf + 2 + (i * 4);
591 if (memcmp(ptr, wifi_oui, 3) == 0) {
594 bss->ieee8021x = TRUE;
600 } else if (memcmp(ptr, ieee80211_oui, 3) == 0) {
603 bss->ieee8021x = TRUE;
612 buf += 2 + (count * 4);
613 len -= 2 + (count * 4);
616 static void bss_property(const char *key, DBusMessageIter *iter,
619 struct supplicant_bss *bss = user_data;
621 if (bss->interface == NULL)
625 if (bss->ieee8021x == TRUE)
626 bss->security = SUPPLICANT_SECURITY_IEEE8021X;
627 else if (bss->psk == TRUE)
628 bss->security = SUPPLICANT_SECURITY_PSK;
629 else if (bss->privacy == TRUE)
630 bss->security = SUPPLICANT_SECURITY_WEP;
632 bss->security = SUPPLICANT_SECURITY_NONE;
634 add_bss_to_network(bss);
638 if (g_strcmp0(key, "BSSID") == 0) {
639 DBusMessageIter array;
643 dbus_message_iter_recurse(iter, &array);
644 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
647 memcpy(bss->bssid, addr, addr_len);
648 } else if (g_strcmp0(key, "SSID") == 0) {
649 DBusMessageIter array;
653 dbus_message_iter_recurse(iter, &array);
654 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
656 if (ssid_len > 0 && ssid_len < 33) {
657 memcpy(bss->ssid, ssid, ssid_len);
658 bss->ssid_len = ssid_len;
660 memset(bss->ssid, 0, sizeof(bss->ssid));
663 } else if (g_strcmp0(key, "Capabilities") == 0) {
664 dbus_uint16_t capabilities = 0x0000;
666 dbus_message_iter_get_basic(iter, &capabilities);
668 if (capabilities & IEEE80211_CAP_ESS)
669 bss->mode = SUPPLICANT_MODE_INFRA;
670 else if (capabilities & IEEE80211_CAP_IBSS)
671 bss->mode = SUPPLICANT_MODE_IBSS;
673 if (capabilities & IEEE80211_CAP_PRIVACY)
675 } else if (g_strcmp0(key, "Frequency") == 0) {
676 dbus_int32_t frequency = 0;
678 dbus_message_iter_get_basic(iter, &frequency);
679 bss->frequency = frequency;
680 } else if (g_strcmp0(key, "Level") == 0) {
681 dbus_int32_t level = 0;
683 dbus_message_iter_get_basic(iter, &level);
684 } else if (g_strcmp0(key, "MaxRate") == 0) {
685 dbus_int32_t maxrate = 0;
687 dbus_message_iter_get_basic(iter, &maxrate);
688 } else if (g_strcmp0(key, "RSNIE") == 0) {
689 DBusMessageIter array;
693 dbus_message_iter_recurse(iter, &array);
694 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
697 extract_rsn(bss, ie + 2, ie_len - 2);
698 } else if (g_strcmp0(key, "WPAIE") == 0) {
699 DBusMessageIter array;
703 dbus_message_iter_recurse(iter, &array);
704 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
707 extract_rsn(bss, ie + 6, ie_len - 6);
708 } else if (g_strcmp0(key, "WPSIE") == 0) {
709 DBusMessageIter array;
713 dbus_message_iter_recurse(iter, &array);
714 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
716 DBG("key %s type %c",
717 key, dbus_message_iter_get_arg_type(iter));
720 static void interface_bss_added(DBusMessageIter *iter, void *user_data)
722 struct supplicant_interface *interface = user_data;
723 struct supplicant_network *network;
724 struct supplicant_bss *bss;
725 const char *path = NULL;
727 dbus_message_iter_get_basic(iter, &path);
731 network = g_hash_table_lookup(interface->bss_mapping, path);
732 if (network != NULL) {
733 bss = g_hash_table_lookup(network->bss_table, path);
738 bss = g_try_new0(struct supplicant_bss, 1);
742 bss->interface = interface;
743 bss->path = g_strdup(path);
745 supplicant_dbus_property_get_all(path,
746 SUPPLICANT_INTERFACE ".Interface.BSS",
750 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
752 struct supplicant_interface *interface = user_data;
753 struct supplicant_network *network;
754 const char *path = NULL;
756 dbus_message_iter_get_basic(iter, &path);
760 network = g_hash_table_lookup(interface->bss_mapping, path);
764 g_hash_table_remove(interface->bss_mapping, path);
765 g_hash_table_remove(network->bss_table, path);
767 if (g_hash_table_size(network->bss_table) == 0)
768 g_hash_table_remove(interface->network_table, network->group);
771 static void interface_property(const char *key, DBusMessageIter *iter,
774 struct supplicant_interface *interface = user_data;
776 if (interface == NULL)
780 debug_strvalmap("Auth capability", auth_capa_map,
781 interface->auth_capa);
782 debug_strvalmap("Scan capability", scan_capa_map,
783 interface->scan_capa);
784 debug_strvalmap("Mode capability", mode_capa_map,
785 interface->mode_capa);
787 g_hash_table_replace(interface_table,
788 interface->path, interface);
790 callback_interface_added(interface);
794 if (g_strcmp0(key, "Capabilities") == 0) {
795 supplicant_dbus_property_foreach(iter, interface_capability,
797 } else if (g_strcmp0(key, "State") == 0) {
798 const char *str = NULL;
800 dbus_message_iter_get_basic(iter, &str);
802 interface->state = string2state(str);
803 } else if (g_strcmp0(key, "Scanning") == 0) {
804 dbus_bool_t scanning = FALSE;
806 dbus_message_iter_get_basic(iter, &scanning);
807 interface->scanning = scanning;
808 } else if (g_strcmp0(key, "ApScan") == 0) {
811 dbus_message_iter_get_basic(iter, &apscan);
812 interface->apscan = apscan;
813 } else if (g_strcmp0(key, "Ifname") == 0) {
814 const char *str = NULL;
816 dbus_message_iter_get_basic(iter, &str);
818 interface->ifname = g_strdup(str);
819 } else if (g_strcmp0(key, "Driver") == 0) {
820 const char *str = NULL;
822 dbus_message_iter_get_basic(iter, &str);
824 interface->driver = g_strdup(str);
825 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
826 const char *str = NULL;
828 dbus_message_iter_get_basic(iter, &str);
830 interface->bridge = g_strdup(str);
831 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
832 interface_bss_added(iter, interface);
833 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
834 interface_network_added(iter, interface);
835 } else if (g_strcmp0(key, "BSSs") == 0) {
836 supplicant_dbus_array_foreach(iter, interface_bss_added,
838 } else if (g_strcmp0(key, "Blobs") == 0) {
839 } else if (g_strcmp0(key, "Networks") == 0) {
840 supplicant_dbus_array_foreach(iter, interface_network_added,
843 DBG("key %s type %c",
844 key, dbus_message_iter_get_arg_type(iter));
847 static void interface_added(DBusMessageIter *iter, void *user_data)
849 struct supplicant_interface *interface;
850 const char *path = NULL;
852 dbus_message_iter_get_basic(iter, &path);
856 interface = g_hash_table_lookup(interface_table, path);
857 if (interface != NULL)
860 interface = g_try_new0(struct supplicant_interface, 1);
861 if (interface == NULL)
864 interface->path = g_strdup(path);
866 interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
867 NULL, remove_network);
869 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
872 supplicant_dbus_property_get_all(path,
873 SUPPLICANT_INTERFACE ".Interface",
874 interface_property, interface);
877 static void interface_removed(DBusMessageIter *iter, void *user_data)
879 const char *path = NULL;
881 dbus_message_iter_get_basic(iter, &path);
885 g_hash_table_remove(interface_table, path);
888 static void eap_method(DBusMessageIter *iter, void *user_data)
890 const char *str = NULL;
893 dbus_message_iter_get_basic(iter, &str);
897 for (i = 0; eap_method_map[i].str != NULL; i++)
898 if (strcmp(str, eap_method_map[i].str) == 0) {
899 eap_methods |= eap_method_map[i].val;
904 static void service_property(const char *key, DBusMessageIter *iter,
908 callback_system_ready();
912 if (g_strcmp0(key, "DebugParams") == 0) {
913 DBusMessageIter list;
915 dbus_message_iter_recurse(iter, &list);
916 dbus_message_iter_get_basic(&list, &debug_level);
918 dbus_message_iter_next(&list);
919 dbus_message_iter_get_basic(&list, &debug_show_timestamps);
921 dbus_message_iter_next(&list);
922 dbus_message_iter_get_basic(&list, &debug_show_keys);
924 DBG("Debug level %d (timestamps %u keys %u)", debug_level,
925 debug_show_timestamps, debug_show_keys);
926 } else if (g_strcmp0(key, "Interfaces") == 0) {
927 supplicant_dbus_array_foreach(iter, interface_added, user_data);
928 } else if (g_strcmp0(key, "EapMethods") == 0) {
929 supplicant_dbus_array_foreach(iter, eap_method, user_data);
930 debug_strvalmap("EAP method", eap_method_map, eap_methods);
934 static void supplicant_bootstrap(void)
936 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
937 SUPPLICANT_INTERFACE,
938 service_property, NULL);
941 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
943 const char *name = NULL, *old = NULL, *new = NULL;
945 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
948 dbus_message_iter_get_basic(iter, &name);
952 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
955 dbus_message_iter_next(iter);
956 dbus_message_iter_get_basic(iter, &old);
957 dbus_message_iter_next(iter);
958 dbus_message_iter_get_basic(iter, &new);
960 if (old == NULL || new == NULL)
963 if (strlen(old) > 0 && strlen(new) == 0) {
964 system_available = FALSE;
965 g_hash_table_remove_all(interface_table);
966 callback_system_killed();
969 if (strlen(new) > 0 && strlen(old) == 0) {
970 system_available = TRUE;
971 supplicant_bootstrap();
975 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
977 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
980 supplicant_dbus_property_foreach(iter, service_property, NULL);
983 static void signal_interface_added(const char *path, DBusMessageIter *iter)
985 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
986 interface_added(iter, NULL);
989 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
991 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
992 interface_removed(iter, NULL);
995 static void signal_bss_added(const char *path, DBusMessageIter *iter)
997 struct supplicant_interface *interface;
999 interface = g_hash_table_lookup(interface_table, path);
1000 if (interface == NULL)
1003 interface_bss_added(iter, interface);
1006 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1008 struct supplicant_interface *interface;
1010 interface = g_hash_table_lookup(interface_table, path);
1011 if (interface == NULL)
1014 interface_bss_removed(iter, interface);
1017 static void signal_network_added(const char *path, DBusMessageIter *iter)
1019 struct supplicant_interface *interface;
1021 interface = g_hash_table_lookup(interface_table, path);
1022 if (interface == NULL)
1025 interface_network_added(iter, interface);
1028 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1030 struct supplicant_interface *interface;
1032 interface = g_hash_table_lookup(interface_table, path);
1033 if (interface == NULL)
1036 interface_network_removed(iter, interface);
1040 const char *interface;
1042 void (*function) (const char *path, DBusMessageIter *iter);
1044 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
1046 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
1047 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
1048 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
1049 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
1051 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
1052 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
1053 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
1054 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
1059 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1060 DBusMessage *message, void *data)
1062 DBusMessageIter iter;
1066 path = dbus_message_get_path(message);
1068 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1070 if (dbus_message_iter_init(message, &iter) == FALSE)
1071 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1073 for (i = 0; signal_map[i].interface != NULL; i++) {
1074 if (dbus_message_has_interface(message,
1075 signal_map[i].interface) == FALSE)
1078 if (dbus_message_has_member(message,
1079 signal_map[i].member) == FALSE)
1082 signal_map[i].function(path, &iter);
1086 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1089 static const char *supplicant_rule0 = "type=signal,"
1090 "path=" DBUS_PATH_DBUS ","
1091 "sender=" DBUS_SERVICE_DBUS ","
1092 "interface=" DBUS_INTERFACE_DBUS ","
1093 "member=NameOwnerChanged,"
1094 "arg0=" SUPPLICANT_SERVICE;
1095 static const char *supplicant_rule1 = "type=signal,"
1096 "interface=" SUPPLICANT_INTERFACE;
1097 static const char *supplicant_rule2 = "type=signal,"
1098 "interface=" SUPPLICANT_INTERFACE ".Interface";
1099 static const char *supplicant_rule3 = "type=signal,"
1100 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
1101 static const char *supplicant_rule4 = "type=signal,"
1102 "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
1103 static const char *supplicant_rule5 = "type=signal,"
1104 "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
1105 static const char *supplicant_rule6 = "type=signal,"
1106 "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
1108 int supplicant_register(const struct supplicant_callbacks *callbacks)
1110 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1111 if (connection == NULL)
1114 if (dbus_connection_add_filter(connection,
1115 supplicant_filter, NULL, NULL) == FALSE) {
1116 dbus_connection_unref(connection);
1121 callbacks_pointer = callbacks;
1124 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1125 NULL, remove_interface);
1127 supplicant_dbus_setup(connection);
1129 dbus_bus_add_match(connection, supplicant_rule0, NULL);
1130 dbus_bus_add_match(connection, supplicant_rule1, NULL);
1131 dbus_bus_add_match(connection, supplicant_rule2, NULL);
1132 dbus_bus_add_match(connection, supplicant_rule3, NULL);
1133 dbus_bus_add_match(connection, supplicant_rule4, NULL);
1134 dbus_bus_add_match(connection, supplicant_rule5, NULL);
1135 dbus_bus_add_match(connection, supplicant_rule6, NULL);
1136 dbus_connection_flush(connection);
1138 if (dbus_bus_name_has_owner(connection,
1139 SUPPLICANT_SERVICE, NULL) == TRUE) {
1140 system_available = TRUE;
1141 supplicant_bootstrap();
1147 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
1149 if (connection != NULL) {
1150 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
1151 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
1152 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
1153 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
1154 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
1155 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
1156 dbus_bus_remove_match(connection, supplicant_rule0, NULL);
1157 dbus_connection_flush(connection);
1159 dbus_connection_remove_filter(connection,
1160 supplicant_filter, NULL);
1163 if (interface_table != NULL) {
1164 g_hash_table_destroy(interface_table);
1165 interface_table = NULL;
1168 if (system_available == TRUE)
1169 callback_system_killed();
1171 if (connection != NULL) {
1172 dbus_connection_unref(connection);
1176 callbacks_pointer = NULL;
1180 static void debug_level_result(const char *error,
1181 DBusMessageIter *iter, void *user_data)
1184 DBG("debug level failure: %s", error);
1187 static void add_debug_level(DBusMessageIter *iter, void *user_data)
1189 dbus_int32_t level = GPOINTER_TO_UINT(user_data);
1190 DBusMessageIter entry;
1192 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1195 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
1196 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1197 &debug_show_timestamps);
1198 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1201 dbus_message_iter_close_container(iter, &entry);
1204 void supplicant_set_debug_level(unsigned int level)
1206 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1207 "DebugParams", "(ibb)", add_debug_level,
1208 debug_level_result, GUINT_TO_POINTER(level));
1211 static void add_show_timestamps(DBusMessageIter *iter, void *user_data)
1213 dbus_bool_t show_timestamps = GPOINTER_TO_UINT(user_data);
1214 DBusMessageIter entry;
1216 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
1219 dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &debug_level);
1220 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1222 dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
1225 dbus_message_iter_close_container(iter, &entry);
1228 void supplicant_set_debug_show_timestamps(dbus_bool_t enabled)
1230 supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
1231 "DebugParams", "(ibb)", add_show_timestamps,
1232 NULL, GUINT_TO_POINTER(enabled));