3 * WPA supplicant library with GLib integration
5 * Copyright (C) 2010 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
38 #include "gsupplicant.h"
42 #define IEEE80211_CAP_ESS 0x0001
43 #define IEEE80211_CAP_IBSS 0x0002
44 #define IEEE80211_CAP_PRIVACY 0x0010
46 static DBusConnection *connection;
48 static const GSupplicantCallbacks *callbacks_pointer;
50 static dbus_bool_t system_available = FALSE;
51 static dbus_bool_t system_ready = FALSE;
53 static dbus_int32_t debug_level;
54 static dbus_bool_t debug_timestamp = FALSE;
55 static dbus_bool_t debug_showkeys = FALSE;
57 static const char *debug_strings[] = {
58 "msgdump", "debug", "info", "warning", "error", NULL
61 static unsigned int eap_methods;
68 static struct strvalmap eap_method_map[] = {
69 { "MD5", G_SUPPLICANT_EAP_METHOD_MD5 },
70 { "TLS", G_SUPPLICANT_EAP_METHOD_TLS },
71 { "MSCHAPV2", G_SUPPLICANT_EAP_METHOD_MSCHAPV2 },
72 { "PEAP", G_SUPPLICANT_EAP_METHOD_PEAP },
73 { "TTLS", G_SUPPLICANT_EAP_METHOD_TTLS },
74 { "GTC", G_SUPPLICANT_EAP_METHOD_GTC },
75 { "OTP", G_SUPPLICANT_EAP_METHOD_OTP },
76 { "LEAP", G_SUPPLICANT_EAP_METHOD_LEAP },
77 { "WSC", G_SUPPLICANT_EAP_METHOD_WSC },
81 static struct strvalmap keymgmt_map[] = {
82 { "none", G_SUPPLICANT_KEYMGMT_NONE },
83 { "ieee8021x", G_SUPPLICANT_KEYMGMT_IEEE8021X },
84 { "wpa-none", G_SUPPLICANT_KEYMGMT_WPA_NONE },
85 { "wpa-psk", G_SUPPLICANT_KEYMGMT_WPA_PSK },
86 { "wpa-psk-sha256", G_SUPPLICANT_KEYMGMT_WPA_PSK_256 },
87 { "wpa-ft-psk", G_SUPPLICANT_KEYMGMT_WPA_FT_PSK },
88 { "wpa-ft-eap", G_SUPPLICANT_KEYMGMT_WPA_FT_EAP },
89 { "wpa-eap", G_SUPPLICANT_KEYMGMT_WPA_EAP },
90 { "wpa-eap-sha256", G_SUPPLICANT_KEYMGMT_WPA_EAP_256 },
91 { "wps", G_SUPPLICANT_KEYMGMT_WPS },
95 static struct strvalmap authalg_capa_map[] = {
96 { "open", G_SUPPLICANT_CAPABILITY_AUTHALG_OPEN },
97 { "shared", G_SUPPLICANT_CAPABILITY_AUTHALG_SHARED },
98 { "leap", G_SUPPLICANT_CAPABILITY_AUTHALG_LEAP },
102 static struct strvalmap proto_capa_map[] = {
103 { "wpa", G_SUPPLICANT_CAPABILITY_PROTO_WPA },
104 { "rsn", G_SUPPLICANT_CAPABILITY_PROTO_RSN },
108 static struct strvalmap group_map[] = {
109 { "wep40", G_SUPPLICANT_GROUP_WEP40 },
110 { "wep104", G_SUPPLICANT_GROUP_WEP104 },
111 { "tkip", G_SUPPLICANT_GROUP_TKIP },
112 { "ccmp", G_SUPPLICANT_GROUP_CCMP },
116 static struct strvalmap pairwise_map[] = {
117 { "none", G_SUPPLICANT_PAIRWISE_NONE },
118 { "tkip", G_SUPPLICANT_PAIRWISE_TKIP },
119 { "ccmp", G_SUPPLICANT_PAIRWISE_CCMP },
123 static struct strvalmap scan_capa_map[] = {
124 { "active", G_SUPPLICANT_CAPABILITY_SCAN_ACTIVE },
125 { "passive", G_SUPPLICANT_CAPABILITY_SCAN_PASSIVE },
126 { "ssid", G_SUPPLICANT_CAPABILITY_SCAN_SSID },
130 static struct strvalmap mode_capa_map[] = {
131 { "infrastructure", G_SUPPLICANT_CAPABILITY_MODE_INFRA },
132 { "ad-hoc", G_SUPPLICANT_CAPABILITY_MODE_IBSS },
133 { "ap", G_SUPPLICANT_CAPABILITY_MODE_AP },
137 static GHashTable *interface_table;
138 static GHashTable *bss_mapping;
140 struct _GSupplicantWpsCredentials {
141 unsigned char ssid[32];
142 unsigned int ssid_len;
146 struct _GSupplicantInterface {
149 unsigned int keymgmt_capa;
150 unsigned int authalg_capa;
151 unsigned int proto_capa;
152 unsigned int group_capa;
153 unsigned int pairwise_capa;
154 unsigned int scan_capa;
155 unsigned int mode_capa;
157 GSupplicantState state;
158 dbus_bool_t scanning;
159 GSupplicantInterfaceCallback scan_callback;
165 struct _GSupplicantWpsCredentials wps_cred;
166 GSupplicantWpsState wps_state;
167 GHashTable *network_table;
168 GHashTable *net_mapping;
169 GHashTable *bss_mapping;
173 struct g_supplicant_bss {
174 GSupplicantInterface *interface;
176 unsigned char bssid[6];
177 unsigned char ssid[32];
178 unsigned int ssid_len;
179 dbus_uint16_t frequency;
180 dbus_uint32_t maxrate;
182 GSupplicantMode mode;
183 GSupplicantSecurity security;
184 unsigned int keymgmt;
185 unsigned int pairwise;
189 dbus_bool_t ieee8021x;
192 struct _GSupplicantNetwork {
193 GSupplicantInterface *interface;
197 unsigned char ssid[32];
198 unsigned int ssid_len;
200 dbus_uint16_t frequency;
201 struct g_supplicant_bss *best_bss;
202 GSupplicantMode mode;
203 GSupplicantSecurity security;
205 GHashTable *bss_table;
206 GHashTable *config_table;
209 static inline void debug(const char *format, ...)
214 if (callbacks_pointer->debug == NULL)
217 va_start(ap, format);
219 if (vsnprintf(str, sizeof(str), format, ap) > 0)
220 callbacks_pointer->debug(str);
225 #define SUPPLICANT_DBG(fmt, arg...) \
226 debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg);
228 static GSupplicantMode string2mode(const char *mode)
231 return G_SUPPLICANT_MODE_UNKNOWN;
233 if (g_str_equal(mode, "infrastructure") == TRUE)
234 return G_SUPPLICANT_MODE_INFRA;
235 else if (g_str_equal(mode, "ad-hoc") == TRUE)
236 return G_SUPPLICANT_MODE_IBSS;
238 return G_SUPPLICANT_MODE_UNKNOWN;
241 static const char *mode2string(GSupplicantMode mode)
244 case G_SUPPLICANT_MODE_UNKNOWN:
246 case G_SUPPLICANT_MODE_INFRA:
248 case G_SUPPLICANT_MODE_IBSS:
250 case G_SUPPLICANT_MODE_MASTER:
257 static const char *security2string(GSupplicantSecurity security)
260 case G_SUPPLICANT_SECURITY_UNKNOWN:
262 case G_SUPPLICANT_SECURITY_NONE:
264 case G_SUPPLICANT_SECURITY_WEP:
266 case G_SUPPLICANT_SECURITY_PSK:
268 case G_SUPPLICANT_SECURITY_IEEE8021X:
275 static GSupplicantState string2state(const char *state)
278 return G_SUPPLICANT_STATE_UNKNOWN;
280 if (g_str_equal(state, "unknown") == TRUE)
281 return G_SUPPLICANT_STATE_UNKNOWN;
282 else if (g_str_equal(state, "disconnected") == TRUE)
283 return G_SUPPLICANT_STATE_DISCONNECTED;
284 else if (g_str_equal(state, "inactive") == TRUE)
285 return G_SUPPLICANT_STATE_INACTIVE;
286 else if (g_str_equal(state, "scanning") == TRUE)
287 return G_SUPPLICANT_STATE_SCANNING;
288 else if (g_str_equal(state, "authenticating") == TRUE)
289 return G_SUPPLICANT_STATE_AUTHENTICATING;
290 else if (g_str_equal(state, "associating") == TRUE)
291 return G_SUPPLICANT_STATE_ASSOCIATING;
292 else if (g_str_equal(state, "associated") == TRUE)
293 return G_SUPPLICANT_STATE_ASSOCIATED;
294 else if (g_str_equal(state, "group_handshake") == TRUE)
295 return G_SUPPLICANT_STATE_GROUP_HANDSHAKE;
296 else if (g_str_equal(state, "4way_handshake") == TRUE)
297 return G_SUPPLICANT_STATE_4WAY_HANDSHAKE;
298 else if (g_str_equal(state, "completed") == TRUE)
299 return G_SUPPLICANT_STATE_COMPLETED;
301 return G_SUPPLICANT_STATE_UNKNOWN;
304 static void callback_system_ready(void)
306 if (system_ready == TRUE)
311 if (callbacks_pointer == NULL)
314 if (callbacks_pointer->system_ready == NULL)
317 callbacks_pointer->system_ready();
320 static void callback_system_killed(void)
322 system_ready = FALSE;
324 if (callbacks_pointer == NULL)
327 if (callbacks_pointer->system_killed == NULL)
330 callbacks_pointer->system_killed();
333 static void callback_interface_added(GSupplicantInterface *interface)
337 if (callbacks_pointer == NULL)
340 if (callbacks_pointer->interface_added == NULL)
343 callbacks_pointer->interface_added(interface);
346 static void callback_interface_state(GSupplicantInterface *interface)
348 if (callbacks_pointer == NULL)
351 if (callbacks_pointer->interface_state == NULL)
354 callbacks_pointer->interface_state(interface);
357 static void callback_interface_removed(GSupplicantInterface *interface)
359 if (callbacks_pointer == NULL)
362 if (callbacks_pointer->interface_removed == NULL)
365 callbacks_pointer->interface_removed(interface);
368 static void callback_scan_started(GSupplicantInterface *interface)
370 if (callbacks_pointer == NULL)
373 if (callbacks_pointer->scan_started == NULL)
376 callbacks_pointer->scan_started(interface);
379 static void callback_scan_finished(GSupplicantInterface *interface)
381 if (callbacks_pointer == NULL)
384 if (callbacks_pointer->scan_finished == NULL)
387 callbacks_pointer->scan_finished(interface);
390 static void callback_network_added(GSupplicantNetwork *network)
392 if (callbacks_pointer == NULL)
395 if (callbacks_pointer->network_added == NULL)
398 callbacks_pointer->network_added(network);
401 static void callback_network_removed(GSupplicantNetwork *network)
403 if (callbacks_pointer == NULL)
406 if (callbacks_pointer->network_removed == NULL)
409 callbacks_pointer->network_removed(network);
412 static void callback_network_changed(GSupplicantNetwork *network,
413 const char *property)
415 if (callbacks_pointer == NULL)
418 if (callbacks_pointer->network_changed == NULL)
421 callbacks_pointer->network_changed(network, property);
424 static void remove_interface(gpointer data)
426 GSupplicantInterface *interface = data;
428 g_hash_table_destroy(interface->bss_mapping);
429 g_hash_table_destroy(interface->net_mapping);
430 g_hash_table_destroy(interface->network_table);
432 callback_interface_removed(interface);
434 g_free(interface->wps_cred.key);
435 g_free(interface->path);
436 g_free(interface->network_path);
437 g_free(interface->ifname);
438 g_free(interface->driver);
439 g_free(interface->bridge);
443 static void remove_network(gpointer data)
445 GSupplicantNetwork *network = data;
447 g_hash_table_destroy(network->bss_table);
449 callback_network_removed(network);
451 g_hash_table_destroy(network->config_table);
453 g_free(network->path);
454 g_free(network->group);
455 g_free(network->name);
459 static void remove_bss(gpointer data)
461 struct g_supplicant_bss *bss = data;
467 static void debug_strvalmap(const char *label, struct strvalmap *map,
472 for (i = 0; map[i].str != NULL; i++) {
473 if (val & map[i].val)
474 SUPPLICANT_DBG("%s: %s", label, map[i].str);
478 static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
480 GSupplicantInterface *interface = user_data;
481 const char *str = NULL;
484 dbus_message_iter_get_basic(iter, &str);
488 for (i = 0; keymgmt_map[i].str != NULL; i++)
489 if (strcmp(str, keymgmt_map[i].str) == 0) {
490 interface->keymgmt_capa |= keymgmt_map[i].val;
495 static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
497 GSupplicantInterface *interface = user_data;
498 const char *str = NULL;
501 dbus_message_iter_get_basic(iter, &str);
505 for (i = 0; authalg_capa_map[i].str != NULL; i++)
506 if (strcmp(str, authalg_capa_map[i].str) == 0) {
507 interface->authalg_capa |= authalg_capa_map[i].val;
512 static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
514 GSupplicantInterface *interface = user_data;
515 const char *str = NULL;
518 dbus_message_iter_get_basic(iter, &str);
522 for (i = 0; proto_capa_map[i].str != NULL; i++)
523 if (strcmp(str, proto_capa_map[i].str) == 0) {
524 interface->proto_capa |= proto_capa_map[i].val;
529 static void interface_capability_pairwise(DBusMessageIter *iter,
532 GSupplicantInterface *interface = user_data;
533 const char *str = NULL;
536 dbus_message_iter_get_basic(iter, &str);
540 for (i = 0; pairwise_map[i].str != NULL; i++)
541 if (strcmp(str, pairwise_map[i].str) == 0) {
542 interface->pairwise_capa |= pairwise_map[i].val;
547 static void interface_capability_group(DBusMessageIter *iter, void *user_data)
549 GSupplicantInterface *interface = user_data;
550 const char *str = NULL;
553 dbus_message_iter_get_basic(iter, &str);
557 for (i = 0; group_map[i].str != NULL; i++)
558 if (strcmp(str, group_map[i].str) == 0) {
559 interface->group_capa |= group_map[i].val;
564 static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
566 GSupplicantInterface *interface = user_data;
567 const char *str = NULL;
570 dbus_message_iter_get_basic(iter, &str);
574 for (i = 0; scan_capa_map[i].str != NULL; i++)
575 if (strcmp(str, scan_capa_map[i].str) == 0) {
576 interface->scan_capa |= scan_capa_map[i].val;
581 static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
583 GSupplicantInterface *interface = user_data;
584 const char *str = NULL;
587 dbus_message_iter_get_basic(iter, &str);
591 for (i = 0; mode_capa_map[i].str != NULL; i++)
592 if (strcmp(str, mode_capa_map[i].str) == 0) {
593 interface->mode_capa |= mode_capa_map[i].val;
598 static void interface_capability(const char *key, DBusMessageIter *iter,
601 GSupplicantInterface *interface = user_data;
606 if (g_strcmp0(key, "KeyMgmt") == 0)
607 supplicant_dbus_array_foreach(iter,
608 interface_capability_keymgmt, interface);
609 else if (g_strcmp0(key, "AuthAlg") == 0)
610 supplicant_dbus_array_foreach(iter,
611 interface_capability_authalg, interface);
612 else if (g_strcmp0(key, "Protocol") == 0)
613 supplicant_dbus_array_foreach(iter,
614 interface_capability_proto, interface);
615 else if (g_strcmp0(key, "Pairwise") == 0)
616 supplicant_dbus_array_foreach(iter,
617 interface_capability_pairwise, interface);
618 else if (g_strcmp0(key, "Group") == 0)
619 supplicant_dbus_array_foreach(iter,
620 interface_capability_group, interface);
621 else if (g_strcmp0(key, "Scan") == 0)
622 supplicant_dbus_array_foreach(iter,
623 interface_capability_scan, interface);
624 else if (g_strcmp0(key, "Modes") == 0)
625 supplicant_dbus_array_foreach(iter,
626 interface_capability_mode, interface);
628 SUPPLICANT_DBG("key %s type %c",
629 key, dbus_message_iter_get_arg_type(iter));
632 static void set_apscan(DBusMessageIter *iter, void *user_data)
634 unsigned int ap_scan = *(unsigned int *)user_data;
636 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan);
639 int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
640 unsigned int ap_scan)
642 return supplicant_dbus_property_set(interface->path,
643 SUPPLICANT_INTERFACE ".Interface",
644 "ApScan", DBUS_TYPE_UINT32_AS_STRING,
645 set_apscan, NULL, &ap_scan);
648 void g_supplicant_interface_set_data(GSupplicantInterface *interface,
651 if (interface == NULL)
654 interface->data = data;
657 void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
659 if (interface == NULL)
662 return interface->data;
665 const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface)
667 if (interface == NULL)
670 return interface->ifname;
673 const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface)
675 if (interface == NULL)
678 return interface->driver;
681 GSupplicantState g_supplicant_interface_get_state(
682 GSupplicantInterface *interface)
684 if (interface == NULL)
685 return G_SUPPLICANT_STATE_UNKNOWN;
687 return interface->state;
690 const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface)
692 if (interface == NULL)
695 return (const char *)interface->wps_cred.key;
698 const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface,
699 unsigned int *ssid_len)
701 if (ssid_len == NULL)
704 if (interface == NULL || interface->wps_cred.ssid == NULL) {
709 *ssid_len = interface->wps_cred.ssid_len;
710 return interface->wps_cred.ssid;
713 GSupplicantWpsState g_supplicant_interface_get_wps_state(
714 GSupplicantInterface *interface)
716 if (interface == NULL)
717 return G_SUPPLICANT_WPS_STATE_UNKNOWN;
719 return interface->wps_state;
722 unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface)
724 if (interface == NULL)
727 return interface->mode_capa;
730 GSupplicantInterface *g_supplicant_network_get_interface(
731 GSupplicantNetwork *network)
736 return network->interface;
739 const char *g_supplicant_network_get_name(GSupplicantNetwork *network)
741 if (network == NULL || network->name == NULL)
744 return network->name;
747 const char *g_supplicant_network_get_identifier(GSupplicantNetwork *network)
749 if (network == NULL || network->group == NULL)
752 return network->group;
755 const char *g_supplicant_network_get_path(GSupplicantNetwork *network)
757 if (network == NULL || network->path == NULL)
760 return network->path;
763 const char *g_supplicant_network_get_mode(GSupplicantNetwork *network)
766 return G_SUPPLICANT_MODE_UNKNOWN;
768 return mode2string(network->mode);
771 const char *g_supplicant_network_get_security(GSupplicantNetwork *network)
774 return G_SUPPLICANT_SECURITY_UNKNOWN;
776 return security2string(network->security);
779 const void *g_supplicant_network_get_ssid(GSupplicantNetwork *network,
780 unsigned int *ssid_len)
782 if (network == NULL || network->ssid == NULL) {
787 *ssid_len = network->ssid_len;
788 return network->ssid;
791 dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network)
796 return network->signal;
799 dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network)
804 return network->frequency;
807 dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
815 static void merge_network(GSupplicantNetwork *network)
818 const char *ssid, *mode, *key_mgmt;
819 unsigned int i, ssid_len;
822 ssid = g_hash_table_lookup(network->config_table, "ssid");
823 mode = g_hash_table_lookup(network->config_table, "mode");
824 key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
826 SUPPLICANT_DBG("ssid %s mode %s", ssid, mode);
829 ssid_len = strlen(ssid);
833 str = g_string_sized_new((ssid_len * 2) + 24);
837 for (i = 0; i < ssid_len; i++)
838 g_string_append_printf(str, "%02x", ssid[i]);
840 if (g_strcmp0(mode, "0") == 0)
841 g_string_append_printf(str, "_managed");
842 else if (g_strcmp0(mode, "1") == 0)
843 g_string_append_printf(str, "_adhoc");
845 if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
846 g_string_append_printf(str, "_psk");
848 group = g_string_free(str, FALSE);
850 SUPPLICANT_DBG("%s", group);
854 g_hash_table_destroy(network->config_table);
856 g_free(network->path);
860 static void network_property(const char *key, DBusMessageIter *iter,
863 GSupplicantNetwork *network = user_data;
865 if (network->interface == NULL)
869 merge_network(network);
873 if (g_strcmp0(key, "Enabled") == 0) {
874 dbus_bool_t enabled = FALSE;
876 dbus_message_iter_get_basic(iter, &enabled);
877 } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
878 const char *str = NULL;
880 dbus_message_iter_get_basic(iter, &str);
882 g_hash_table_replace(network->config_table,
883 g_strdup(key), g_strdup(str));
886 SUPPLICANT_DBG("key %s type %c",
887 key, dbus_message_iter_get_arg_type(iter));
890 static void interface_network_added(DBusMessageIter *iter, void *user_data)
892 GSupplicantInterface *interface = user_data;
893 GSupplicantNetwork *network;
894 const char *path = NULL;
898 dbus_message_iter_get_basic(iter, &path);
902 if (g_strcmp0(path, "/") == 0)
905 network = g_hash_table_lookup(interface->net_mapping, path);
909 network = g_try_new0(GSupplicantNetwork, 1);
913 network->interface = interface;
914 network->path = g_strdup(path);
916 network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
919 dbus_message_iter_next(iter);
920 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
921 supplicant_dbus_property_foreach(iter, network_property,
923 network_property(NULL, NULL, network);
927 supplicant_dbus_property_get_all(path,
928 SUPPLICANT_INTERFACE ".Network",
929 network_property, network);
932 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
934 GSupplicantInterface *interface = user_data;
935 GSupplicantNetwork *network;
936 const char *path = NULL;
938 dbus_message_iter_get_basic(iter, &path);
942 network = g_hash_table_lookup(interface->net_mapping, path);
946 g_hash_table_remove(interface->net_mapping, path);
949 static char *create_name(unsigned char *ssid, int ssid_len)
954 if (ssid_len < 1 || ssid[0] == '\0')
957 name = g_try_malloc0(ssid_len + 1);
962 for (i = 0; i < ssid_len; i++) {
963 if (g_ascii_isprint(ssid[i]))
972 static char *create_group(struct g_supplicant_bss *bss)
976 const char *mode, *security;
978 str = g_string_sized_new((bss->ssid_len * 2) + 24);
982 if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
983 for (i = 0; i < bss->ssid_len; i++)
984 g_string_append_printf(str, "%02x", bss->ssid[i]);
986 g_string_append_printf(str, "hidden");
988 mode = mode2string(bss->mode);
990 g_string_append_printf(str, "_%s", mode);
992 security = security2string(bss->security);
993 if (security != NULL)
994 g_string_append_printf(str, "_%s", security);
996 return g_string_free(str, FALSE);
999 static void add_bss_to_network(struct g_supplicant_bss *bss)
1001 GSupplicantInterface *interface = bss->interface;
1002 GSupplicantNetwork *network;
1005 group = create_group(bss);
1009 network = g_hash_table_lookup(interface->network_table, group);
1010 if (network != NULL) {
1015 network = g_try_new0(GSupplicantNetwork, 1);
1016 if (network == NULL) {
1021 network->interface = interface;
1022 if (network->path == NULL)
1023 network->path = g_strdup(bss->path);
1024 network->group = group;
1025 network->name = create_name(bss->ssid, bss->ssid_len);
1026 network->mode = bss->mode;
1027 network->security = bss->security;
1028 network->ssid_len = bss->ssid_len;
1029 memcpy(network->ssid, bss->ssid, bss->ssid_len);
1030 network->signal = bss->signal;
1031 network->frequency = bss->frequency;
1032 network->best_bss = bss;
1034 network->wps = FALSE;
1035 if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0)
1036 network->wps = TRUE;
1038 network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1041 network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
1044 g_hash_table_replace(interface->network_table,
1045 network->group, network);
1047 callback_network_added(network);
1050 if (bss->signal > network->signal) {
1051 network->signal = bss->signal;
1052 network->best_bss = bss;
1053 callback_network_changed(network, "Signal");
1056 g_hash_table_replace(interface->bss_mapping, bss->path, network);
1057 g_hash_table_replace(network->bss_table, bss->path, bss);
1059 g_hash_table_replace(bss_mapping, bss->path, interface);
1062 static void bss_rates(DBusMessageIter *iter, void *user_data)
1064 struct g_supplicant_bss *bss = user_data;
1065 dbus_uint32_t rate = 0;
1067 dbus_message_iter_get_basic(iter, &rate);
1071 if (rate > bss->maxrate)
1072 bss->maxrate = rate;
1075 static void bss_keymgmt(DBusMessageIter *iter, void *user_data)
1077 struct g_supplicant_bss *bss = user_data;
1078 const char *str = NULL;
1081 dbus_message_iter_get_basic(iter, &str);
1085 for (i = 0; keymgmt_map[i].str != NULL; i++)
1086 if (strcmp(str, keymgmt_map[i].str) == 0) {
1087 bss->keymgmt |= keymgmt_map[i].val;
1092 static void bss_group(DBusMessageIter *iter, void *user_data)
1094 struct g_supplicant_bss *bss = user_data;
1095 const char *str = NULL;
1098 dbus_message_iter_get_basic(iter, &str);
1102 for (i = 0; group_map[i].str != NULL; i++)
1103 if (strcmp(str, group_map[i].str) == 0) {
1104 bss->group |= group_map[i].val;
1109 static void bss_pairwise(DBusMessageIter *iter, void *user_data)
1111 struct g_supplicant_bss *bss = user_data;
1112 const char *str = NULL;
1115 dbus_message_iter_get_basic(iter, &str);
1119 for (i = 0; pairwise_map[i].str != NULL; i++)
1120 if (strcmp(str, pairwise_map[i].str) == 0) {
1121 bss->pairwise |= pairwise_map[i].val;
1126 static void bss_wpa(const char *key, DBusMessageIter *iter,
1129 if (g_strcmp0(key, "KeyMgmt") == 0)
1130 supplicant_dbus_array_foreach(iter, bss_keymgmt, user_data);
1131 else if (g_strcmp0(key, "Group") == 0)
1132 supplicant_dbus_array_foreach(iter, bss_group, user_data);
1133 else if (g_strcmp0(key, "Pairwise") == 0)
1134 supplicant_dbus_array_foreach(iter, bss_pairwise, user_data);
1138 static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size,
1141 unsigned int len = 0;
1143 while (len + 4 < ie_size) {
1144 unsigned int hi = ie[len];
1145 unsigned int lo = ie[len + 1];
1146 unsigned int tmp_type = (hi << 8) + lo;
1147 unsigned int v_len = 0;
1149 /* hi and lo are used to recreate an unsigned int
1150 * based on 2 8bits length unsigned int. */
1154 v_len = (hi << 8) + lo;
1156 if (tmp_type == type) {
1157 unsigned int ret_value = 0;
1158 unsigned char *value = (unsigned char *)&ret_value;
1160 SUPPLICANT_DBG("IE: match type 0x%x", type);
1162 /* Verifying length relevance */
1163 if (v_len > sizeof(unsigned int) ||
1164 len + 4 + v_len > ie_size)
1167 memcpy(value, ie + len + 4, v_len);
1169 SUPPLICANT_DBG("returning 0x%x", ret_value);
1176 SUPPLICANT_DBG("returning 0");
1180 static void bss_process_ies(DBusMessageIter *iter, void *user_data)
1182 struct g_supplicant_bss *bss = user_data;
1183 const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
1184 unsigned char *ie, *ie_end;
1185 DBusMessageIter array;
1188 #define WMM_WPA1_WPS_INFO 221
1189 #define WPS_INFO_MIN_LEN 6
1190 #define WPS_VERSION_TLV 0x104A
1191 #define WPS_STATE_TLV 0x1044
1192 #define WPS_VERSION 0x10
1194 dbus_message_iter_recurse(iter, &array);
1195 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1197 if (ie == NULL || ie_len < 2)
1200 for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end;
1203 if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
1204 memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
1207 SUPPLICANT_DBG("IE: match WPS_OUI");
1209 if (get_tlv(&ie[6], ie[1],
1210 WPS_VERSION_TLV) == WPS_VERSION &&
1211 get_tlv(&ie[6], ie[1],
1212 WPS_STATE_TLV) != 0)
1213 bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS;
1217 static void bss_property(const char *key, DBusMessageIter *iter,
1220 struct g_supplicant_bss *bss = user_data;
1222 if (bss->interface == NULL)
1225 SUPPLICANT_DBG("key %s", key);
1228 if (bss->ieee8021x == TRUE)
1229 bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
1230 else if (bss->psk == TRUE)
1231 bss->security = G_SUPPLICANT_SECURITY_PSK;
1232 else if (bss->privacy == TRUE)
1233 bss->security = G_SUPPLICANT_SECURITY_WEP;
1235 bss->security = G_SUPPLICANT_SECURITY_NONE;
1237 add_bss_to_network(bss);
1241 if (g_strcmp0(key, "BSSID") == 0) {
1242 DBusMessageIter array;
1243 unsigned char *addr;
1246 dbus_message_iter_recurse(iter, &array);
1247 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
1250 memcpy(bss->bssid, addr, addr_len);
1251 } else if (g_strcmp0(key, "SSID") == 0) {
1252 DBusMessageIter array;
1253 unsigned char *ssid;
1256 dbus_message_iter_recurse(iter, &array);
1257 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1259 if (ssid_len > 0 && ssid_len < 33) {
1260 memcpy(bss->ssid, ssid, ssid_len);
1261 bss->ssid_len = ssid_len;
1263 memset(bss->ssid, 0, sizeof(bss->ssid));
1266 } else if (g_strcmp0(key, "Capabilities") == 0) {
1267 dbus_uint16_t capabilities = 0x0000;
1269 dbus_message_iter_get_basic(iter, &capabilities);
1271 if (capabilities & IEEE80211_CAP_ESS)
1272 bss->mode = G_SUPPLICANT_MODE_INFRA;
1273 else if (capabilities & IEEE80211_CAP_IBSS)
1274 bss->mode = G_SUPPLICANT_MODE_IBSS;
1276 if (capabilities & IEEE80211_CAP_PRIVACY)
1277 bss->privacy = TRUE;
1278 } else if (g_strcmp0(key, "Mode") == 0) {
1279 const char *mode = NULL;
1281 dbus_message_iter_get_basic(iter, &mode);
1282 bss->mode = string2mode(mode);
1283 } else if (g_strcmp0(key, "Frequency") == 0) {
1284 dbus_uint16_t frequency = 0;
1286 dbus_message_iter_get_basic(iter, &frequency);
1287 bss->frequency = frequency;
1288 } else if (g_strcmp0(key, "Signal") == 0) {
1289 dbus_int16_t signal = 0;
1291 dbus_message_iter_get_basic(iter, &signal);
1293 bss->signal = signal;
1294 } else if (g_strcmp0(key, "Level") == 0) {
1295 dbus_int32_t level = 0;
1297 dbus_message_iter_get_basic(iter, &level);
1298 } else if (g_strcmp0(key, "Rates") == 0) {
1299 supplicant_dbus_array_foreach(iter, bss_rates, bss);
1300 } else if (g_strcmp0(key, "MaxRate") == 0) {
1301 dbus_uint32_t maxrate = 0;
1303 dbus_message_iter_get_basic(iter, &maxrate);
1305 bss->maxrate = maxrate;
1306 } else if (g_strcmp0(key, "Privacy") == 0) {
1307 dbus_bool_t privacy = FALSE;
1309 dbus_message_iter_get_basic(iter, &privacy);
1310 bss->privacy = privacy;
1311 } else if ((g_strcmp0(key, "RSN") == 0) ||
1312 (g_strcmp0(key, "WPA") == 0)) {
1313 supplicant_dbus_property_foreach(iter, bss_wpa, bss);
1316 (G_SUPPLICANT_KEYMGMT_WPA_EAP |
1317 G_SUPPLICANT_KEYMGMT_WPA_FT_EAP |
1318 G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
1319 bss->ieee8021x = TRUE;
1322 (G_SUPPLICANT_KEYMGMT_WPA_PSK |
1323 G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
1324 G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
1326 } else if (g_strcmp0(key, "IEs") == 0)
1327 bss_process_ies(iter, bss);
1329 SUPPLICANT_DBG("key %s type %c",
1330 key, dbus_message_iter_get_arg_type(iter));
1333 static struct g_supplicant_bss *interface_bss_added(DBusMessageIter *iter,
1336 GSupplicantInterface *interface = user_data;
1337 GSupplicantNetwork *network;
1338 struct g_supplicant_bss *bss;
1339 const char *path = NULL;
1343 dbus_message_iter_get_basic(iter, &path);
1347 if (g_strcmp0(path, "/") == 0)
1350 SUPPLICANT_DBG("%s", path);
1352 network = g_hash_table_lookup(interface->bss_mapping, path);
1353 if (network != NULL) {
1354 bss = g_hash_table_lookup(network->bss_table, path);
1359 bss = g_try_new0(struct g_supplicant_bss, 1);
1363 bss->interface = interface;
1364 bss->path = g_strdup(path);
1369 static void interface_bss_added_with_keys(DBusMessageIter *iter,
1372 struct g_supplicant_bss *bss;
1376 bss = interface_bss_added(iter, user_data);
1380 dbus_message_iter_next(iter);
1382 if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID)
1385 supplicant_dbus_property_foreach(iter, bss_property, bss);
1386 bss_property(NULL, NULL, bss);
1389 static void interface_bss_added_without_keys(DBusMessageIter *iter,
1392 struct g_supplicant_bss *bss;
1396 bss = interface_bss_added(iter, user_data);
1400 supplicant_dbus_property_get_all(bss->path,
1401 SUPPLICANT_INTERFACE ".BSS",
1405 static void update_signal(gpointer key, gpointer value,
1408 struct g_supplicant_bss *bss = value;
1409 GSupplicantNetwork *network = user_data;
1411 if (bss->signal > network->signal) {
1412 network->signal = bss->signal;
1413 network->best_bss = bss;
1417 static void update_network_signal(GSupplicantNetwork *network)
1419 if (g_hash_table_size(network->bss_table) <= 1)
1422 g_hash_table_foreach(network->bss_table,
1423 update_signal, network);
1425 SUPPLICANT_DBG("New network signal %d", network->signal);
1428 static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
1430 GSupplicantInterface *interface = user_data;
1431 GSupplicantNetwork *network;
1432 const char *path = NULL;
1434 dbus_message_iter_get_basic(iter, &path);
1438 network = g_hash_table_lookup(interface->bss_mapping, path);
1439 if (network == NULL)
1442 g_hash_table_remove(bss_mapping, path);
1444 g_hash_table_remove(interface->bss_mapping, path);
1445 g_hash_table_remove(network->bss_table, path);
1447 update_network_signal(network);
1449 if (g_hash_table_size(network->bss_table) == 0)
1450 g_hash_table_remove(interface->network_table, network->group);
1453 static void interface_property(const char *key, DBusMessageIter *iter,
1456 GSupplicantInterface *interface = user_data;
1458 if (interface == NULL)
1461 SUPPLICANT_DBG("%s", key);
1464 debug_strvalmap("KeyMgmt capability", keymgmt_map,
1465 interface->keymgmt_capa);
1466 debug_strvalmap("AuthAlg capability", authalg_capa_map,
1467 interface->authalg_capa);
1468 debug_strvalmap("Protocol capability", proto_capa_map,
1469 interface->proto_capa);
1470 debug_strvalmap("Pairwise capability", pairwise_map,
1471 interface->pairwise_capa);
1472 debug_strvalmap("Group capability", group_map,
1473 interface->group_capa);
1474 debug_strvalmap("Scan capability", scan_capa_map,
1475 interface->scan_capa);
1476 debug_strvalmap("Mode capability", mode_capa_map,
1477 interface->mode_capa);
1479 interface->ready = TRUE;
1480 callback_interface_added(interface);
1484 if (g_strcmp0(key, "Capabilities") == 0) {
1485 supplicant_dbus_property_foreach(iter, interface_capability,
1487 } else if (g_strcmp0(key, "State") == 0) {
1488 const char *str = NULL;
1490 dbus_message_iter_get_basic(iter, &str);
1492 if (string2state(str) != interface->state) {
1493 interface->state = string2state(str);
1494 callback_interface_state(interface);
1497 SUPPLICANT_DBG("state %s (%d)", str, interface->state);
1498 } else if (g_strcmp0(key, "Scanning") == 0) {
1499 dbus_bool_t scanning = FALSE;
1501 dbus_message_iter_get_basic(iter, &scanning);
1502 interface->scanning = scanning;
1504 if (interface->ready == TRUE) {
1505 if (interface->scanning == TRUE)
1506 callback_scan_started(interface);
1508 callback_scan_finished(interface);
1510 } else if (g_strcmp0(key, "ApScan") == 0) {
1513 dbus_message_iter_get_basic(iter, &apscan);
1514 interface->apscan = apscan;
1515 } else if (g_strcmp0(key, "Ifname") == 0) {
1516 const char *str = NULL;
1518 dbus_message_iter_get_basic(iter, &str);
1520 g_free(interface->ifname);
1521 interface->ifname = g_strdup(str);
1523 } else if (g_strcmp0(key, "Driver") == 0) {
1524 const char *str = NULL;
1526 dbus_message_iter_get_basic(iter, &str);
1528 g_free(interface->driver);
1529 interface->driver = g_strdup(str);
1531 } else if (g_strcmp0(key, "BridgeIfname") == 0) {
1532 const char *str = NULL;
1534 dbus_message_iter_get_basic(iter, &str);
1536 g_free(interface->bridge);
1537 interface->bridge = g_strdup(str);
1539 } else if (g_strcmp0(key, "CurrentBSS") == 0) {
1540 interface_bss_added_without_keys(iter, interface);
1541 } else if (g_strcmp0(key, "CurrentNetwork") == 0) {
1542 interface_network_added(iter, interface);
1543 } else if (g_strcmp0(key, "BSSs") == 0) {
1544 supplicant_dbus_array_foreach(iter, interface_bss_added_without_keys,
1546 } else if (g_strcmp0(key, "Blobs") == 0) {
1548 } else if (g_strcmp0(key, "Networks") == 0) {
1549 supplicant_dbus_array_foreach(iter, interface_network_added,
1552 SUPPLICANT_DBG("key %s type %c",
1553 key, dbus_message_iter_get_arg_type(iter));
1556 static void scan_network_update(DBusMessageIter *iter, void *user_data)
1558 GSupplicantInterface *interface = user_data;
1559 GSupplicantNetwork *network;
1565 dbus_message_iter_get_basic(iter, &path);
1570 if (g_strcmp0(path, "/") == 0)
1573 /* Update the network details based on scan BSS data */
1574 network = g_hash_table_lookup(interface->bss_mapping, path);
1575 if (network != NULL)
1576 callback_network_added(network);
1579 static void scan_bss_data(const char *key, DBusMessageIter *iter,
1582 GSupplicantInterface *interface = user_data;
1585 supplicant_dbus_array_foreach(iter, scan_network_update,
1588 if (interface->scan_callback != NULL)
1589 interface->scan_callback(0, interface, interface->scan_data);
1591 interface->scan_callback = NULL;
1592 interface->scan_data = NULL;
1595 static GSupplicantInterface *interface_alloc(const char *path)
1597 GSupplicantInterface *interface;
1599 interface = g_try_new0(GSupplicantInterface, 1);
1600 if (interface == NULL)
1603 interface->path = g_strdup(path);
1605 interface->network_table = g_hash_table_new_full(g_str_hash,
1606 g_str_equal, NULL, remove_network);
1608 interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1610 interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
1613 g_hash_table_replace(interface_table, interface->path, interface);
1618 static void interface_added(DBusMessageIter *iter, void *user_data)
1620 GSupplicantInterface *interface;
1621 const char *path = NULL;
1625 dbus_message_iter_get_basic(iter, &path);
1629 if (g_strcmp0(path, "/") == 0)
1632 interface = g_hash_table_lookup(interface_table, path);
1633 if (interface != NULL)
1636 interface = interface_alloc(path);
1637 if (interface == NULL)
1640 dbus_message_iter_next(iter);
1641 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
1642 supplicant_dbus_property_foreach(iter, interface_property,
1644 interface_property(NULL, NULL, interface);
1648 supplicant_dbus_property_get_all(path,
1649 SUPPLICANT_INTERFACE ".Interface",
1650 interface_property, interface);
1653 static void interface_removed(DBusMessageIter *iter, void *user_data)
1655 const char *path = NULL;
1657 dbus_message_iter_get_basic(iter, &path);
1661 g_hash_table_remove(interface_table, path);
1664 static void eap_method(DBusMessageIter *iter, void *user_data)
1666 const char *str = NULL;
1669 dbus_message_iter_get_basic(iter, &str);
1673 for (i = 0; eap_method_map[i].str != NULL; i++)
1674 if (strcmp(str, eap_method_map[i].str) == 0) {
1675 eap_methods |= eap_method_map[i].val;
1680 static void service_property(const char *key, DBusMessageIter *iter,
1684 callback_system_ready();
1688 if (g_strcmp0(key, "DebugLevel") == 0) {
1689 const char *str = NULL;
1692 dbus_message_iter_get_basic(iter, &str);
1693 for (i = 0; debug_strings[i] != NULL; i++)
1694 if (g_strcmp0(debug_strings[i], str) == 0) {
1698 SUPPLICANT_DBG("Debug level %d", debug_level);
1699 } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
1700 dbus_message_iter_get_basic(iter, &debug_timestamp);
1701 SUPPLICANT_DBG("Debug timestamp %u", debug_timestamp);
1702 } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
1703 dbus_message_iter_get_basic(iter, &debug_showkeys);
1704 SUPPLICANT_DBG("Debug show keys %u", debug_showkeys);
1705 } else if (g_strcmp0(key, "Interfaces") == 0) {
1706 supplicant_dbus_array_foreach(iter, interface_added, NULL);
1707 } else if (g_strcmp0(key, "EapMethods") == 0) {
1708 supplicant_dbus_array_foreach(iter, eap_method, NULL);
1709 debug_strvalmap("EAP method", eap_method_map, eap_methods);
1710 } else if (g_strcmp0(key, "Country") == 0) {
1711 const char *country = NULL;
1713 dbus_message_iter_get_basic(iter, &country);
1714 SUPPLICANT_DBG("Country %s", country);
1716 SUPPLICANT_DBG("key %s type %c",
1717 key, dbus_message_iter_get_arg_type(iter));
1720 static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
1722 const char *name = NULL, *old = NULL, *new = NULL;
1726 if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
1729 dbus_message_iter_get_basic(iter, &name);
1733 if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
1736 dbus_message_iter_next(iter);
1737 dbus_message_iter_get_basic(iter, &old);
1738 dbus_message_iter_next(iter);
1739 dbus_message_iter_get_basic(iter, &new);
1741 if (old == NULL || new == NULL)
1744 if (strlen(old) > 0 && strlen(new) == 0) {
1745 system_available = FALSE;
1746 g_hash_table_remove_all(bss_mapping);
1747 g_hash_table_remove_all(interface_table);
1748 callback_system_killed();
1751 if (strlen(new) > 0 && strlen(old) == 0) {
1752 system_available = TRUE;
1753 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
1754 SUPPLICANT_INTERFACE,
1755 service_property, NULL);
1759 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
1763 if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
1766 supplicant_dbus_property_foreach(iter, service_property, NULL);
1769 static void signal_interface_added(const char *path, DBusMessageIter *iter)
1771 SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
1773 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1774 interface_added(iter, NULL);
1777 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
1781 if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
1782 interface_removed(iter, NULL);
1785 static void signal_interface_changed(const char *path, DBusMessageIter *iter)
1787 GSupplicantInterface *interface;
1791 interface = g_hash_table_lookup(interface_table, path);
1792 if (interface == NULL)
1795 supplicant_dbus_property_foreach(iter, interface_property, interface);
1798 static void signal_scan_done(const char *path, DBusMessageIter *iter)
1800 GSupplicantInterface *interface;
1801 dbus_bool_t success = FALSE;
1805 interface = g_hash_table_lookup(interface_table, path);
1806 if (interface == NULL)
1809 dbus_message_iter_get_basic(iter, &success);
1812 * If scan is unsuccessful return -EIO else get the scanned BSSs
1813 * and update the network details accordingly
1815 if (success == FALSE) {
1816 if (interface->scan_callback != NULL)
1817 interface->scan_callback(-EIO, interface,
1818 interface->scan_data);
1820 interface->scan_callback = NULL;
1821 interface->scan_data = NULL;
1826 supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
1827 "BSSs", scan_bss_data, interface);
1830 static void signal_bss_added(const char *path, DBusMessageIter *iter)
1832 GSupplicantInterface *interface;
1836 interface = g_hash_table_lookup(interface_table, path);
1837 if (interface == NULL)
1840 interface_bss_added_with_keys(iter, interface);
1843 static void signal_bss_removed(const char *path, DBusMessageIter *iter)
1845 GSupplicantInterface *interface;
1849 interface = g_hash_table_lookup(interface_table, path);
1850 if (interface == NULL)
1853 interface_bss_removed(iter, interface);
1856 static void signal_network_added(const char *path, DBusMessageIter *iter)
1858 GSupplicantInterface *interface;
1862 interface = g_hash_table_lookup(interface_table, path);
1863 if (interface == NULL)
1866 interface_network_added(iter, interface);
1869 static void signal_network_removed(const char *path, DBusMessageIter *iter)
1871 GSupplicantInterface *interface;
1875 interface = g_hash_table_lookup(interface_table, path);
1876 if (interface == NULL)
1879 interface_network_removed(iter, interface);
1882 static void signal_bss_changed(const char *path, DBusMessageIter *iter)
1884 GSupplicantInterface *interface;
1885 GSupplicantNetwork *network;
1886 struct g_supplicant_bss *bss;
1890 interface = g_hash_table_lookup(bss_mapping, path);
1891 if (interface == NULL)
1894 network = g_hash_table_lookup(interface->bss_mapping, path);
1895 if (network == NULL)
1898 bss = g_hash_table_lookup(network->bss_table, path);
1902 supplicant_dbus_property_foreach(iter, bss_property, bss);
1904 if (bss->signal == network->signal)
1908 * If the new signal is lower than the SSID signal, we need
1909 * to check for the new maximum.
1911 if (bss->signal < network->signal) {
1912 if (bss != network->best_bss)
1914 network->signal = bss->signal;
1915 update_network_signal(network);
1917 network->signal = bss->signal;
1918 network->best_bss = bss;
1921 SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid, network->signal);
1923 callback_network_changed(network, "Signal");
1926 static void wps_credentials(const char *key, DBusMessageIter *iter,
1929 GSupplicantInterface *interface = user_data;
1934 SUPPLICANT_DBG("key %s", key);
1936 if (g_strcmp0(key, "Key") == 0) {
1937 DBusMessageIter array;
1941 dbus_message_iter_recurse(iter, &array);
1942 dbus_message_iter_get_fixed_array(&array, &key, &key_len);
1944 g_free(interface->wps_cred.key);
1945 interface->wps_cred.key = g_try_malloc0(
1946 sizeof(char) * key_len+1);
1948 if (interface->wps_cred.key == NULL)
1951 memcpy(interface->wps_cred.key, key, sizeof(char) * key_len);
1953 SUPPLICANT_DBG("WPS key present");
1954 } else if (g_strcmp0(key, "SSID") == 0) {
1955 DBusMessageIter array;
1956 unsigned char *ssid;
1959 dbus_message_iter_recurse(iter, &array);
1960 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1962 if (ssid_len > 0 && ssid_len < 33) {
1963 memcpy(interface->wps_cred.ssid, ssid, ssid_len);
1964 interface->wps_cred.ssid_len = ssid_len;
1966 memset(interface->wps_cred.ssid, 0, 32);
1967 interface->wps_cred.ssid_len = 0;
1972 static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
1974 GSupplicantInterface *interface;
1978 interface = g_hash_table_lookup(interface_table, path);
1979 if (interface == NULL)
1982 supplicant_dbus_property_foreach(iter, wps_credentials, interface);
1985 static void wps_event_args(const char *key, DBusMessageIter *iter,
1988 GSupplicantInterface *interface = user_data;
1990 if (key == NULL || interface == NULL)
1993 SUPPLICANT_DBG("Arg Key %s", key);
1996 static void signal_wps_event(const char *path, DBusMessageIter *iter)
1998 GSupplicantInterface *interface;
1999 const char *name = NULL;
2003 interface = g_hash_table_lookup(interface_table, path);
2004 if (interface == NULL)
2007 dbus_message_iter_get_basic(iter, &name);
2009 SUPPLICANT_DBG("Name: %s", name);
2011 if (g_strcmp0(name, "success") == 0)
2012 interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
2013 else if (g_strcmp0(name, "failed") == 0)
2014 interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
2016 interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
2018 if (!dbus_message_iter_has_next(iter))
2021 dbus_message_iter_next(iter);
2023 supplicant_dbus_property_foreach(iter, wps_event_args, interface);
2027 const char *interface;
2029 void (*function) (const char *path, DBusMessageIter *iter);
2031 { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
2033 { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
2034 { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
2035 { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
2036 { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
2038 { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
2039 { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done },
2040 { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
2041 { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
2042 { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
2043 { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
2045 { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed },
2047 { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
2048 { SUPPLICANT_INTERFACE ".Interface.WPS", "Event", signal_wps_event },
2053 static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
2054 DBusMessage *message, void *data)
2056 DBusMessageIter iter;
2060 path = dbus_message_get_path(message);
2062 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2064 if (dbus_message_iter_init(message, &iter) == FALSE)
2065 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2067 for (i = 0; signal_map[i].interface != NULL; i++) {
2068 if (dbus_message_has_interface(message,
2069 signal_map[i].interface) == FALSE)
2072 if (dbus_message_has_member(message,
2073 signal_map[i].member) == FALSE)
2076 signal_map[i].function(path, &iter);
2080 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2083 struct supplicant_regdom {
2084 GSupplicantCountryCallback callback;
2085 const void *user_data;
2088 static void country_result(const char *error,
2089 DBusMessageIter *iter, void *user_data)
2091 struct supplicant_regdom *regdom = user_data;
2094 SUPPLICANT_DBG("Country setting result");
2096 if (user_data == NULL)
2099 if (error == NULL) {
2100 alpha2 = (char *)regdom->user_data;
2102 SUPPLICANT_DBG("Country setting failure %s", error);
2106 if (regdom->callback)
2107 regdom->callback(alpha2);
2112 static void country_params(DBusMessageIter *iter, void *user_data)
2114 struct supplicant_regdom *regdom = user_data;
2115 const char *country;
2117 country = regdom->user_data;
2119 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &country);
2122 int g_supplicant_set_country(const char *alpha2,
2123 GSupplicantCountryCallback callback,
2124 const void *user_data)
2126 struct supplicant_regdom *regdom;
2128 SUPPLICANT_DBG("Country setting %s", alpha2);
2130 if (system_available == FALSE)
2133 regdom = dbus_malloc0(sizeof(*regdom));
2137 regdom->callback = callback;
2138 regdom->user_data = user_data;
2140 return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
2141 "Country", DBUS_TYPE_STRING_AS_STRING,
2142 country_params, country_result,
2146 struct interface_data {
2147 GSupplicantInterface *interface;
2148 GSupplicantInterfaceCallback callback;
2152 struct interface_create_data {
2156 GSupplicantInterface *interface;
2157 GSupplicantInterfaceCallback callback;
2161 struct interface_connect_data {
2162 GSupplicantInterface *interface;
2163 GSupplicantInterfaceCallback callback;
2164 GSupplicantSSID *ssid;
2168 static void interface_create_property(const char *key, DBusMessageIter *iter,
2171 struct interface_create_data *data = user_data;
2172 GSupplicantInterface *interface = data->interface;
2175 if (data->callback != NULL)
2176 data->callback(0, data->interface, data->user_data);
2181 interface_property(key, iter, interface);
2184 static void interface_create_result(const char *error,
2185 DBusMessageIter *iter, void *user_data)
2187 struct interface_create_data *data = user_data;
2188 const char *path = NULL;
2193 if (error != NULL) {
2194 g_critical("error %s", error);
2199 dbus_message_iter_get_basic(iter, &path);
2205 if (system_available == FALSE) {
2210 data->interface = g_hash_table_lookup(interface_table, path);
2211 if (data->interface == NULL) {
2212 data->interface = interface_alloc(path);
2213 if (data->interface == NULL) {
2219 err = supplicant_dbus_property_get_all(path,
2220 SUPPLICANT_INTERFACE ".Interface",
2221 interface_create_property, data);
2226 if (data->callback != NULL)
2227 data->callback(err, NULL, data->user_data);
2232 static void interface_create_params(DBusMessageIter *iter, void *user_data)
2234 struct interface_create_data *data = user_data;
2235 DBusMessageIter dict;
2239 supplicant_dbus_dict_open(iter, &dict);
2241 supplicant_dbus_dict_append_basic(&dict, "Ifname",
2242 DBUS_TYPE_STRING, &data->ifname);
2244 if (data->driver != NULL)
2245 supplicant_dbus_dict_append_basic(&dict, "Driver",
2246 DBUS_TYPE_STRING, &data->driver);
2248 if (data->bridge != NULL)
2249 supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
2250 DBUS_TYPE_STRING, &data->bridge);
2252 supplicant_dbus_dict_close(iter, &dict);
2255 static void interface_get_result(const char *error,
2256 DBusMessageIter *iter, void *user_data)
2258 struct interface_create_data *data = user_data;
2259 GSupplicantInterface *interface;
2260 const char *path = NULL;
2265 if (error != NULL) {
2266 SUPPLICANT_DBG("Interface not created yet");
2271 dbus_message_iter_get_basic(iter, &path);
2277 interface = g_hash_table_lookup(interface_table, path);
2278 if (interface == NULL) {
2283 if (data->callback != NULL)
2284 data->callback(0, interface, data->user_data);
2291 if (system_available == FALSE) {
2296 SUPPLICANT_DBG("Creating interface");
2298 err = supplicant_dbus_method_call(SUPPLICANT_PATH,
2299 SUPPLICANT_INTERFACE,
2301 interface_create_params,
2302 interface_create_result, data);
2307 if (data->callback != NULL)
2308 data->callback(err, NULL, data->user_data);
2313 static void interface_get_params(DBusMessageIter *iter, void *user_data)
2315 struct interface_create_data *data = user_data;
2319 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
2322 int g_supplicant_interface_create(const char *ifname, const char *driver,
2324 GSupplicantInterfaceCallback callback,
2327 struct interface_create_data *data;
2329 SUPPLICANT_DBG("ifname %s", ifname);
2334 if (system_available == FALSE)
2337 data = dbus_malloc0(sizeof(*data));
2341 data->ifname = ifname;
2342 data->driver = driver;
2343 data->bridge = bridge;
2344 data->callback = callback;
2345 data->user_data = user_data;
2347 return supplicant_dbus_method_call(SUPPLICANT_PATH,
2348 SUPPLICANT_INTERFACE,
2350 interface_get_params,
2351 interface_get_result, data);
2354 static void interface_remove_result(const char *error,
2355 DBusMessageIter *iter, void *user_data)
2357 struct interface_data *data = user_data;
2360 if (error != NULL) {
2365 if (system_available == FALSE) {
2371 * The gsupplicant interface is already freed by the InterfaceRemoved
2372 * signal callback. Simply invoke the interface_data callback.
2377 if (data->callback != NULL)
2378 data->callback(err, NULL, data->user_data);
2384 static void interface_remove_params(DBusMessageIter *iter, void *user_data)
2386 struct interface_data *data = user_data;
2388 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2389 &data->interface->path);
2393 int g_supplicant_interface_remove(GSupplicantInterface *interface,
2394 GSupplicantInterfaceCallback callback,
2397 struct interface_data *data;
2399 if (interface == NULL)
2402 if (system_available == FALSE)
2405 data = dbus_malloc0(sizeof(*data));
2409 data->interface = interface;
2410 data->callback = callback;
2411 data->user_data = user_data;
2413 return supplicant_dbus_method_call(SUPPLICANT_PATH,
2414 SUPPLICANT_INTERFACE,
2416 interface_remove_params,
2417 interface_remove_result, data);
2420 static void interface_scan_result(const char *error,
2421 DBusMessageIter *iter, void *user_data)
2423 struct interface_data *data = user_data;
2425 if (error != NULL) {
2426 if (data->callback != NULL)
2427 data->callback(-EIO, data->interface, data->user_data);
2429 data->interface->scan_callback = data->callback;
2430 data->interface->scan_data = data->user_data;
2436 static void interface_scan_params(DBusMessageIter *iter, void *user_data)
2438 DBusMessageIter dict;
2439 const char *type = "passive";
2441 supplicant_dbus_dict_open(iter, &dict);
2443 supplicant_dbus_dict_append_basic(&dict, "Type",
2444 DBUS_TYPE_STRING, &type);
2446 supplicant_dbus_dict_close(iter, &dict);
2449 int g_supplicant_interface_scan(GSupplicantInterface *interface,
2450 GSupplicantInterfaceCallback callback,
2453 struct interface_data *data;
2455 if (interface == NULL)
2458 if (system_available == FALSE)
2461 if (interface->scanning == TRUE)
2464 switch (interface->state) {
2465 case G_SUPPLICANT_STATE_AUTHENTICATING:
2466 case G_SUPPLICANT_STATE_ASSOCIATING:
2467 case G_SUPPLICANT_STATE_ASSOCIATED:
2468 case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
2469 case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
2471 case G_SUPPLICANT_STATE_UNKNOWN:
2472 case G_SUPPLICANT_STATE_DISCONNECTED:
2473 case G_SUPPLICANT_STATE_INACTIVE:
2474 case G_SUPPLICANT_STATE_SCANNING:
2475 case G_SUPPLICANT_STATE_COMPLETED:
2479 data = dbus_malloc0(sizeof(*data));
2483 data->interface = interface;
2484 data->callback = callback;
2485 data->user_data = user_data;
2487 return supplicant_dbus_method_call(interface->path,
2488 SUPPLICANT_INTERFACE ".Interface", "Scan",
2489 interface_scan_params, interface_scan_result, data);
2492 static int parse_supplicant_error(DBusMessageIter *iter)
2494 int err = -ECANCELED;
2497 while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
2498 dbus_message_iter_get_basic(iter, &key);
2499 if (strncmp(key, "psk", 4) == 0 ||
2500 strncmp(key, "wep_key", 7) == 0) {
2504 dbus_message_iter_next(iter);
2510 static void interface_select_network_result(const char *error,
2511 DBusMessageIter *iter, void *user_data)
2513 struct interface_connect_data *data = user_data;
2519 if (error != NULL) {
2520 SUPPLICANT_DBG("SelectNetwork error %s", error);
2521 err = parse_supplicant_error(iter);
2524 if (data->callback != NULL)
2525 data->callback(err, data->interface, data->user_data);
2531 static void interface_select_network_params(DBusMessageIter *iter,
2534 struct interface_connect_data *data = user_data;
2535 GSupplicantInterface *interface = data->interface;
2537 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
2538 &interface->network_path);
2541 static void interface_add_network_result(const char *error,
2542 DBusMessageIter *iter, void *user_data)
2544 struct interface_connect_data *data = user_data;
2545 GSupplicantInterface *interface = data->interface;
2552 dbus_message_iter_get_basic(iter, &path);
2556 SUPPLICANT_DBG("PATH: %s", path);
2558 g_free(interface->network_path);
2559 interface->network_path = g_strdup(path);
2561 supplicant_dbus_method_call(data->interface->path,
2562 SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
2563 interface_select_network_params,
2564 interface_select_network_result, data);
2569 SUPPLICANT_DBG("AddNetwork error %s", error);
2570 err = parse_supplicant_error(iter);
2571 if (data->callback != NULL)
2572 data->callback(err, data->interface, data->user_data);
2574 g_free(interface->network_path);
2575 interface->network_path = NULL;
2580 static void add_network_security_wep(DBusMessageIter *dict,
2581 GSupplicantSSID *ssid)
2583 const char *auth_alg = "OPEN SHARED";
2584 const char *key_index = "0";
2586 supplicant_dbus_dict_append_basic(dict, "auth_alg",
2587 DBUS_TYPE_STRING, &auth_alg);
2589 if (ssid->passphrase) {
2590 int size = strlen(ssid->passphrase);
2591 if (size == 10 || size == 26) {
2592 unsigned char *key = g_try_malloc(13);
2596 memset(tmp, 0, sizeof(tmp));
2600 for (i = 0; i < size / 2; i++) {
2601 memcpy(tmp, ssid->passphrase + (i * 2), 2);
2602 key[i] = (unsigned char) strtol(tmp, NULL, 16);
2605 supplicant_dbus_dict_append_fixed_array(dict,
2610 } else if (size == 5 || size == 13) {
2611 unsigned char *key = g_try_malloc(13);
2617 for (i = 0; i < size; i++)
2618 key[i] = (unsigned char) ssid->passphrase[i];
2620 supplicant_dbus_dict_append_fixed_array(dict,
2626 supplicant_dbus_dict_append_basic(dict,
2631 supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx",
2632 DBUS_TYPE_STRING, &key_index);
2636 static dbus_bool_t is_psk_raw_key(const char *psk)
2640 /* A raw key is always 64 bytes length... */
2641 if (strlen(psk) != 64)
2644 /* ... and its content is in hex representation */
2645 for (i = 0; i < 64; i++)
2646 if (!isxdigit((unsigned char) psk[i]))
2652 static void add_network_security_psk(DBusMessageIter *dict,
2653 GSupplicantSSID *ssid)
2655 if (ssid->passphrase && strlen(ssid->passphrase) > 0) {
2657 if (is_psk_raw_key(ssid->passphrase) == TRUE)
2658 supplicant_dbus_property_append_fixed_array(dict,
2659 "psk", DBUS_TYPE_BYTE,
2660 &ssid->passphrase, 64);
2662 supplicant_dbus_dict_append_basic(dict, "psk",
2668 static void add_network_security_tls(DBusMessageIter *dict,
2669 GSupplicantSSID *ssid)
2672 * For TLS, we at least need:
2673 * The client certificate
2674 * The client private key file
2675 * The client private key file password
2677 * The Authority certificate is optional.
2679 if (ssid->client_cert_path == NULL)
2682 if (ssid->private_key_path == NULL)
2685 if (ssid->private_key_passphrase == NULL)
2688 if (ssid->ca_cert_path)
2689 supplicant_dbus_dict_append_basic(dict, "ca_cert",
2690 DBUS_TYPE_STRING, &ssid->ca_cert_path);
2692 supplicant_dbus_dict_append_basic(dict, "private_key",
2694 &ssid->private_key_path);
2695 supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
2697 &ssid->private_key_passphrase);
2698 supplicant_dbus_dict_append_basic(dict, "client_cert",
2700 &ssid->client_cert_path);
2703 static void add_network_security_peap(DBusMessageIter *dict,
2704 GSupplicantSSID *ssid)
2709 * For PEAP/TTLS, we at least need
2710 * The authority certificate
2711 * The 2nd phase authentication method
2712 * The 2nd phase passphrase
2714 * The Client certificate is optional although strongly recommended
2715 * When setting it, we need in addition
2716 * The Client private key file
2717 * The Client private key file password
2719 if (ssid->passphrase == NULL)
2722 if (ssid->phase2_auth == NULL)
2725 if (ssid->client_cert_path) {
2726 if (ssid->private_key_path == NULL)
2729 if (ssid->private_key_passphrase == NULL)
2732 supplicant_dbus_dict_append_basic(dict, "client_cert",
2734 &ssid->client_cert_path);
2736 supplicant_dbus_dict_append_basic(dict, "private_key",
2738 &ssid->private_key_path);
2740 supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
2742 &ssid->private_key_passphrase);
2746 if (g_str_has_prefix(ssid->phase2_auth, "EAP-") == TRUE) {
2747 phase2_auth = g_strdup_printf("autheap=%s",
2748 ssid->phase2_auth + strlen("EAP-"));
2750 phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth);
2752 supplicant_dbus_dict_append_basic(dict, "password",
2756 if (ssid->ca_cert_path)
2757 supplicant_dbus_dict_append_basic(dict, "ca_cert",
2759 &ssid->ca_cert_path);
2761 supplicant_dbus_dict_append_basic(dict, "phase2",
2765 g_free(phase2_auth);
2768 static void add_network_security_eap(DBusMessageIter *dict,
2769 GSupplicantSSID *ssid)
2773 if (ssid->eap == NULL || ssid->identity == NULL)
2776 if (g_strcmp0(ssid->eap, "tls") == 0) {
2777 add_network_security_tls(dict, ssid);
2778 } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
2779 g_strcmp0(ssid->eap, "ttls") == 0) {
2780 add_network_security_peap(dict, ssid);
2784 eap_value = g_ascii_strup(ssid->eap, -1);
2786 supplicant_dbus_dict_append_basic(dict, "eap",
2789 supplicant_dbus_dict_append_basic(dict, "identity",
2796 static void add_network_security_ciphers(DBusMessageIter *dict,
2797 GSupplicantSSID *ssid)
2799 unsigned int p_cipher, g_cipher, i;
2800 char *pairwise, *group;
2801 char *pair_ciphers[4];
2802 char *group_ciphers[5];
2804 p_cipher = ssid->pairwise_cipher;
2805 g_cipher = ssid->group_cipher;
2807 if (p_cipher == 0 && g_cipher == 0)
2812 if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP)
2813 pair_ciphers[i++] = "CCMP";
2815 if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP)
2816 pair_ciphers[i++] = "TKIP";
2818 if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE)
2819 pair_ciphers[i++] = "NONE";
2821 pair_ciphers[i] = NULL;
2825 if (g_cipher & G_SUPPLICANT_GROUP_CCMP)
2826 group_ciphers[i++] = "CCMP";
2828 if (g_cipher & G_SUPPLICANT_GROUP_TKIP)
2829 group_ciphers[i++] = "TKIP";
2831 if (g_cipher & G_SUPPLICANT_GROUP_WEP104)
2832 group_ciphers[i++] = "WEP104";
2834 if (g_cipher & G_SUPPLICANT_GROUP_WEP40)
2835 group_ciphers[i++] = "WEP40";
2837 group_ciphers[i] = NULL;
2839 pairwise = g_strjoinv(" ", pair_ciphers);
2840 group = g_strjoinv(" ", group_ciphers);
2842 SUPPLICANT_DBG("cipher %s %s", pairwise, group);
2844 supplicant_dbus_dict_append_basic(dict, "pairwise",
2847 supplicant_dbus_dict_append_basic(dict, "group",
2855 static void add_network_security_proto(DBusMessageIter *dict,
2856 GSupplicantSSID *ssid)
2858 unsigned int protocol, i;
2862 protocol = ssid->protocol;
2869 if (protocol & G_SUPPLICANT_PROTO_RSN)
2870 protos[i++] = "RSN";
2872 if (protocol & G_SUPPLICANT_PROTO_WPA)
2873 protos[i++] = "WPA";
2877 proto = g_strjoinv(" ", protos);
2879 SUPPLICANT_DBG("proto %s", proto);
2881 supplicant_dbus_dict_append_basic(dict, "proto",
2888 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
2892 switch (ssid->security) {
2893 case G_SUPPLICANT_SECURITY_UNKNOWN:
2894 case G_SUPPLICANT_SECURITY_NONE:
2895 case G_SUPPLICANT_SECURITY_WEP:
2897 add_network_security_wep(dict, ssid);
2898 add_network_security_ciphers(dict, ssid);
2900 case G_SUPPLICANT_SECURITY_PSK:
2901 key_mgmt = "WPA-PSK";
2902 add_network_security_psk(dict, ssid);
2903 add_network_security_ciphers(dict, ssid);
2904 add_network_security_proto(dict, ssid);
2906 case G_SUPPLICANT_SECURITY_IEEE8021X:
2907 key_mgmt = "WPA-EAP";
2908 add_network_security_eap(dict, ssid);
2909 add_network_security_ciphers(dict, ssid);
2910 add_network_security_proto(dict, ssid);
2914 supplicant_dbus_dict_append_basic(dict, "key_mgmt",
2915 DBUS_TYPE_STRING, &key_mgmt);
2918 static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
2922 switch (ssid->mode) {
2923 case G_SUPPLICANT_MODE_UNKNOWN:
2924 case G_SUPPLICANT_MODE_INFRA:
2927 case G_SUPPLICANT_MODE_IBSS:
2930 case G_SUPPLICANT_MODE_MASTER:
2935 supplicant_dbus_dict_append_basic(dict, "mode",
2936 DBUS_TYPE_UINT32, &mode);
2939 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
2941 DBusMessageIter dict;
2942 struct interface_connect_data *data = user_data;
2943 GSupplicantSSID *ssid = data->ssid;
2945 supplicant_dbus_dict_open(iter, &dict);
2947 if (ssid->scan_ssid)
2948 supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
2949 DBUS_TYPE_UINT32, &ssid->scan_ssid);
2952 supplicant_dbus_dict_append_basic(&dict, "frequency",
2953 DBUS_TYPE_UINT32, &ssid->freq);
2955 add_network_mode(&dict, ssid);
2957 add_network_security(&dict, ssid);
2959 supplicant_dbus_dict_append_fixed_array(&dict, "ssid",
2960 DBUS_TYPE_BYTE, &ssid->ssid,
2963 supplicant_dbus_dict_close(iter, &dict);
2966 static void interface_wps_start_result(const char *error,
2967 DBusMessageIter *iter, void *user_data)
2969 struct interface_connect_data *data = user_data;
2973 SUPPLICANT_DBG("error: %s", error);
2979 static void interface_add_wps_params(DBusMessageIter *iter, void *user_data)
2981 struct interface_connect_data *data = user_data;
2982 GSupplicantSSID *ssid = data->ssid;
2983 const char *role = "enrollee", *type;
2984 DBusMessageIter dict;
2988 supplicant_dbus_dict_open(iter, &dict);
2990 supplicant_dbus_dict_append_basic(&dict, "Role",
2991 DBUS_TYPE_STRING, &role);
2994 if (ssid->pin_wps != NULL) {
2996 supplicant_dbus_dict_append_basic(&dict, "Pin",
2997 DBUS_TYPE_STRING, &ssid->pin_wps);
3000 supplicant_dbus_dict_append_basic(&dict, "Type",
3001 DBUS_TYPE_STRING, &type);
3003 supplicant_dbus_dict_close(iter, &dict);
3006 static void wps_start(const char *error, DBusMessageIter *iter, void *user_data)
3008 struct interface_connect_data *data = user_data;
3012 if (error != NULL) {
3013 SUPPLICANT_DBG("error: %s", error);
3019 supplicant_dbus_method_call(data->interface->path,
3020 SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
3021 interface_add_wps_params,
3022 interface_wps_start_result, data);
3025 static void wps_process_credentials(DBusMessageIter *iter, void *user_data)
3027 dbus_bool_t credentials = TRUE;
3031 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials);
3035 int g_supplicant_interface_connect(GSupplicantInterface *interface,
3036 GSupplicantSSID *ssid,
3037 GSupplicantInterfaceCallback callback,
3040 struct interface_connect_data *data;
3043 if (interface == NULL)
3046 if (system_available == FALSE)
3049 /* TODO: Check if we're already connected and switch */
3051 data = dbus_malloc0(sizeof(*data));
3055 data->interface = interface;
3056 data->callback = callback;
3058 data->user_data = user_data;
3060 if (ssid->use_wps == TRUE) {
3061 g_free(interface->wps_cred.key);
3062 memset(&interface->wps_cred, 0,
3063 sizeof(struct _GSupplicantWpsCredentials));
3065 ret = supplicant_dbus_property_set(interface->path,
3066 SUPPLICANT_INTERFACE ".Interface.WPS",
3067 "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
3068 wps_process_credentials, wps_start, data);
3070 ret = supplicant_dbus_method_call(interface->path,
3071 SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
3072 interface_add_network_params,
3073 interface_add_network_result, data);
3078 return -EINPROGRESS;
3081 static void network_remove_result(const char *error,
3082 DBusMessageIter *iter, void *user_data)
3084 struct interface_data *data = user_data;
3092 if (data->callback != NULL)
3093 data->callback(result, data->interface, data->user_data);
3098 static void network_remove_params(DBusMessageIter *iter, void *user_data)
3100 struct interface_data *data = user_data;
3101 const char *path = data->interface->network_path;
3103 SUPPLICANT_DBG("path %s", path);
3105 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
3108 static int network_remove(struct interface_data *data)
3110 GSupplicantInterface *interface = data->interface;
3114 return supplicant_dbus_method_call(interface->path,
3115 SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
3116 network_remove_params, network_remove_result, data);
3119 static void interface_disconnect_result(const char *error,
3120 DBusMessageIter *iter, void *user_data)
3122 struct interface_data *data = user_data;
3126 if (error != NULL && data->callback != NULL)
3127 data->callback(-EIO, data->interface, data->user_data);
3129 /* If we are disconnecting from previous WPS successful
3130 * association. i.e.: it did not went through AddNetwork,
3131 * and interface->network_path was never set. */
3132 if (data->interface->network_path == NULL)
3135 network_remove(data);
3138 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
3139 GSupplicantInterfaceCallback callback,
3142 struct interface_data *data;
3146 if (interface == NULL)
3149 if (system_available == FALSE)
3152 data = dbus_malloc0(sizeof(*data));
3156 data->interface = interface;
3157 data->callback = callback;
3158 data->user_data = user_data;
3160 return supplicant_dbus_method_call(interface->path,
3161 SUPPLICANT_INTERFACE ".Interface", "Disconnect",
3162 NULL, interface_disconnect_result, data);
3166 static const char *g_supplicant_rule0 = "type=signal,"
3167 "path=" DBUS_PATH_DBUS ","
3168 "sender=" DBUS_SERVICE_DBUS ","
3169 "interface=" DBUS_INTERFACE_DBUS ","
3170 "member=NameOwnerChanged,"
3171 "arg0=" SUPPLICANT_SERVICE;
3172 static const char *g_supplicant_rule1 = "type=signal,"
3173 "interface=" SUPPLICANT_INTERFACE;
3174 static const char *g_supplicant_rule2 = "type=signal,"
3175 "interface=" SUPPLICANT_INTERFACE ".Interface";
3176 static const char *g_supplicant_rule3 = "type=signal,"
3177 "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
3178 static const char *g_supplicant_rule4 = "type=signal,"
3179 "interface=" SUPPLICANT_INTERFACE ".BSS";
3180 static const char *g_supplicant_rule5 = "type=signal,"
3181 "interface=" SUPPLICANT_INTERFACE ".Network";
3183 static void invoke_introspect_method(void)
3185 DBusMessage *message;
3187 message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
3189 DBUS_INTERFACE_INTROSPECTABLE,
3192 if (message == NULL)
3195 dbus_message_set_no_reply(message, TRUE);
3196 dbus_connection_send(connection, message, NULL);
3197 dbus_message_unref(message);
3200 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
3202 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
3203 if (connection == NULL)
3206 if (dbus_connection_add_filter(connection,
3207 g_supplicant_filter, NULL, NULL) == FALSE) {
3208 dbus_connection_unref(connection);
3213 callbacks_pointer = callbacks;
3216 interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
3217 NULL, remove_interface);
3219 bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
3222 supplicant_dbus_setup(connection);
3224 dbus_bus_add_match(connection, g_supplicant_rule0, NULL);
3225 dbus_bus_add_match(connection, g_supplicant_rule1, NULL);
3226 dbus_bus_add_match(connection, g_supplicant_rule2, NULL);
3227 dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
3228 dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
3229 dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
3230 dbus_connection_flush(connection);
3232 if (dbus_bus_name_has_owner(connection,
3233 SUPPLICANT_SERVICE, NULL) == TRUE) {
3234 system_available = TRUE;
3235 supplicant_dbus_property_get_all(SUPPLICANT_PATH,
3236 SUPPLICANT_INTERFACE,
3237 service_property, NULL);
3239 invoke_introspect_method();
3244 static void unregister_interface_remove_params(DBusMessageIter *iter,
3247 const char *path = user_data;
3249 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
3254 static void unregister_remove_interface(gpointer key, gpointer value,
3257 GSupplicantInterface *interface = value;
3259 supplicant_dbus_method_call(SUPPLICANT_PATH,
3260 SUPPLICANT_INTERFACE,
3262 unregister_interface_remove_params,
3263 NULL, interface->path);
3266 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
3270 if (connection != NULL) {
3271 dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
3272 dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
3273 dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);
3274 dbus_bus_remove_match(connection, g_supplicant_rule2, NULL);
3275 dbus_bus_remove_match(connection, g_supplicant_rule1, NULL);
3276 dbus_bus_remove_match(connection, g_supplicant_rule0, NULL);
3277 dbus_connection_flush(connection);
3279 dbus_connection_remove_filter(connection,
3280 g_supplicant_filter, NULL);
3283 if (bss_mapping != NULL) {
3284 g_hash_table_destroy(bss_mapping);
3288 if (system_available == TRUE)
3289 callback_system_killed();
3291 if (interface_table != NULL) {
3292 g_hash_table_foreach(interface_table,
3293 unregister_remove_interface, NULL);
3294 g_hash_table_destroy(interface_table);
3295 interface_table = NULL;
3298 if (connection != NULL) {
3299 dbus_connection_unref(connection);
3303 callbacks_pointer = NULL;