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
30 #include <net/ethernet.h>
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/device.h>
36 #include <connman/option.h>
37 #include <connman/dbus.h>
38 #include <connman/log.h>
41 #include "supplicant.h"
45 #define IEEE80211_CAP_ESS 0x0001
46 #define IEEE80211_CAP_IBSS 0x0002
47 #define IEEE80211_CAP_PRIVACY 0x0010
49 #define SUPPLICANT_NAME "fi.epitest.hostap.WPASupplicant"
50 #define SUPPLICANT_INTF "fi.epitest.hostap.WPASupplicant"
51 #define SUPPLICANT_PATH "/fi/epitest/hostap/WPASupplicant"
53 /* Taken from "WPA Supplicant - Common definitions" */
54 enum supplicant_state {
56 * WPA_DISCONNECTED - Disconnected state
58 * This state indicates that client is not associated, but is likely to
59 * start looking for an access point. This state is entered when a
65 * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
67 * This state is entered if there are no enabled networks in the
68 * configuration. wpa_supplicant is not trying to associate with a new
69 * network and external interaction (e.g., ctrl_iface call to add or
70 * enable a network) is needed to start association.
75 * WPA_SCANNING - Scanning for a network
77 * This state is entered when wpa_supplicant starts scanning for a
83 * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
85 * This state is entered when wpa_supplicant has found a suitable BSS
86 * to associate with and the driver is configured to try to associate
87 * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
88 * state is entered when the driver is configured to try to associate
89 * with a network using the configured SSID and security policy.
94 * WPA_ASSOCIATED - Association completed
96 * This state is entered when the driver reports that association has
97 * been successfully completed with an AP. If IEEE 802.1X is used
98 * (with or without WPA/WPA2), wpa_supplicant remains in this state
99 * until the IEEE 802.1X/EAPOL authentication has been completed.
104 * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
106 * This state is entered when WPA/WPA2 4-Way Handshake is started. In
107 * case of WPA-PSK, this happens when receiving the first EAPOL-Key
108 * frame after association. In case of WPA-EAP, this state is entered
109 * when the IEEE 802.1X/EAPOL authentication has been completed.
114 * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
116 * This state is entered when 4-Way Key Handshake has been completed
117 * (i.e., when the supplicant sends out message 4/4) and when Group
118 * Key rekeying is started by the AP (i.e., when supplicant receives
124 * WPA_COMPLETED - All authentication completed
126 * This state is entered when the full authentication process is
127 * completed. In case of WPA2, this happens when the 4-Way Handshake is
128 * successfully completed. With WPA, this state is entered after the
129 * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
130 * completed after dynamic keys are received (or if not used, after
131 * the EAP authentication has been completed). With static WEP keys and
132 * plaintext connections, this state is entered when an association
133 * has been completed.
135 * This state indicates that the supplicant has completed its
136 * processing for the association phase and that data connection is
142 * WPA_INVALID - Invalid state (parsing error)
144 * This state is returned if the string input is invalid. It is not
145 * an official wpa_supplicant state.
150 struct supplicant_result {
155 unsigned int ssid_len;
156 dbus_uint16_t capabilities;
162 dbus_int32_t frequency;
163 dbus_int32_t quality;
166 dbus_int32_t maxrate;
169 struct supplicant_task {
172 struct connman_device *device;
173 struct connman_network *network;
177 enum supplicant_state state;
179 GSList *scan_results;
182 static GSList *task_list = NULL;
184 static DBusConnection *connection;
186 static void free_task(struct supplicant_task *task)
188 DBG("task %p", task);
190 g_free(task->ifname);
195 static struct supplicant_task *find_task_by_index(int index)
199 for (list = task_list; list; list = list->next) {
200 struct supplicant_task *task = list->data;
202 if (task->ifindex == index)
209 static struct supplicant_task *find_task_by_path(const char *path)
213 for (list = task_list; list; list = list->next) {
214 struct supplicant_task *task = list->data;
216 if (g_str_equal(task->path, path) == TRUE)
223 static void add_interface_reply(DBusPendingCall *call, void *user_data)
225 struct supplicant_task *task = user_data;
230 DBG("task %p", task);
232 reply = dbus_pending_call_steal_reply(call);
236 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
239 dbus_error_init(&error);
241 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
242 DBUS_TYPE_INVALID) == FALSE) {
243 if (dbus_error_is_set(&error) == TRUE) {
244 connman_error("%s", error.message);
245 dbus_error_free(&error);
247 connman_error("Wrong arguments for add interface");
251 DBG("path %s", path);
253 task->path = g_strdup(path);
254 task->created = TRUE;
256 connman_device_set_powered(task->device, TRUE);
259 dbus_message_unref(reply);
262 static int add_interface(struct supplicant_task *task)
264 const char *driver = connman_option_get_string("wifi");
265 DBusMessage *message;
266 DBusMessageIter array, dict;
267 DBusPendingCall *call;
269 DBG("task %p", task);
271 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
272 SUPPLICANT_INTF, "addInterface");
276 dbus_message_iter_init_append(message, &array);
278 dbus_message_iter_append_basic(&array,
279 DBUS_TYPE_STRING, &task->ifname);
281 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
282 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
283 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
284 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
286 connman_dbus_dict_append_variant(&dict, "driver",
287 DBUS_TYPE_STRING, &driver);
289 dbus_message_iter_close_container(&array, &dict);
291 if (dbus_connection_send_with_reply(connection, message,
292 &call, TIMEOUT) == FALSE) {
293 connman_error("Failed to add interface");
294 dbus_message_unref(message);
299 connman_error("D-Bus connection not available");
300 dbus_message_unref(message);
304 dbus_pending_call_set_notify(call, add_interface_reply, task, NULL);
306 dbus_message_unref(message);
311 static void get_interface_reply(DBusPendingCall *call, void *user_data)
313 struct supplicant_task *task = user_data;
318 DBG("task %p", task);
320 reply = dbus_pending_call_steal_reply(call);
324 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
329 dbus_error_init(&error);
331 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
332 DBUS_TYPE_INVALID) == FALSE) {
333 if (dbus_error_is_set(&error) == TRUE) {
334 connman_error("%s", error.message);
335 dbus_error_free(&error);
337 connman_error("Wrong arguments for get interface");
341 DBG("path %s", path);
343 task->path = g_strdup(path);
344 task->created = FALSE;
346 connman_device_set_powered(task->device, TRUE);
349 dbus_message_unref(reply);
352 static int create_interface(struct supplicant_task *task)
354 DBusMessage *message;
355 DBusPendingCall *call;
357 DBG("task %p", task);
359 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
360 SUPPLICANT_INTF, "getInterface");
364 dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
367 if (dbus_connection_send_with_reply(connection, message,
368 &call, TIMEOUT) == FALSE) {
369 connman_error("Failed to get interface");
370 dbus_message_unref(message);
375 connman_error("D-Bus connection not available");
376 dbus_message_unref(message);
380 dbus_pending_call_set_notify(call, get_interface_reply, task, NULL);
382 dbus_message_unref(message);
387 static void remove_interface_reply(DBusPendingCall *call, void *user_data)
389 struct supplicant_task *task = user_data;
392 DBG("task %p", task);
394 reply = dbus_pending_call_steal_reply(call);
396 connman_device_set_powered(task->device, FALSE);
398 connman_device_unref(task->device);
400 inet_ifdown(task->ifindex);
404 dbus_message_unref(reply);
407 static int remove_interface(struct supplicant_task *task)
409 DBusMessage *message;
410 DBusPendingCall *call;
412 DBG("task %p", task);
414 if (task->created == FALSE) {
415 connman_device_set_powered(task->device, FALSE);
419 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
420 SUPPLICANT_INTF, "removeInterface");
424 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->path,
427 if (dbus_connection_send_with_reply(connection, message,
428 &call, TIMEOUT) == FALSE) {
429 connman_error("Failed to remove interface");
430 dbus_message_unref(message);
435 connman_error("D-Bus connection not available");
436 dbus_message_unref(message);
440 dbus_pending_call_set_notify(call, remove_interface_reply, task, NULL);
442 dbus_message_unref(message);
448 static int set_ap_scan(struct supplicant_task *task)
450 DBusMessage *message, *reply;
454 DBG("task %p", task);
456 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
457 SUPPLICANT_INTF ".Interface", "setAPScan");
461 dbus_message_append_args(message, DBUS_TYPE_UINT32, &ap_scan,
464 dbus_error_init(&error);
466 reply = dbus_connection_send_with_reply_and_block(connection,
467 message, -1, &error);
469 if (dbus_error_is_set(&error) == TRUE) {
470 connman_error("%s", error.message);
471 dbus_error_free(&error);
473 connman_error("Failed to set AP scan");
474 dbus_message_unref(message);
478 dbus_message_unref(message);
480 dbus_message_unref(reply);
486 static int add_network(struct supplicant_task *task)
488 DBusMessage *message, *reply;
492 DBG("task %p", task);
494 if (task->netpath != NULL)
497 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
498 SUPPLICANT_INTF ".Interface", "addNetwork");
502 dbus_error_init(&error);
504 reply = dbus_connection_send_with_reply_and_block(connection,
505 message, -1, &error);
507 if (dbus_error_is_set(&error) == TRUE) {
508 connman_error("%s", error.message);
509 dbus_error_free(&error);
511 connman_error("Failed to add network");
512 dbus_message_unref(message);
516 dbus_message_unref(message);
518 dbus_error_init(&error);
520 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
521 DBUS_TYPE_INVALID) == FALSE) {
522 if (dbus_error_is_set(&error) == TRUE) {
523 connman_error("%s", error.message);
524 dbus_error_free(&error);
526 connman_error("Wrong arguments for network");
527 dbus_message_unref(reply);
531 DBG("path %s", path);
533 task->netpath = g_strdup(path);
535 dbus_message_unref(reply);
540 static int remove_network(struct supplicant_task *task)
542 DBusMessage *message, *reply;
545 DBG("task %p", task);
547 if (task->netpath == NULL)
550 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
551 SUPPLICANT_INTF ".Interface", "removeNetwork");
555 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
558 dbus_error_init(&error);
560 reply = dbus_connection_send_with_reply_and_block(connection,
561 message, -1, &error);
563 if (dbus_error_is_set(&error) == TRUE) {
564 connman_error("%s", error.message);
565 dbus_error_free(&error);
567 connman_error("Failed to remove network");
568 dbus_message_unref(message);
572 dbus_message_unref(message);
574 dbus_message_unref(reply);
576 g_free(task->netpath);
577 task->netpath = NULL;
582 static int select_network(struct supplicant_task *task)
584 DBusMessage *message, *reply;
587 DBG("task %p", task);
589 if (task->netpath == NULL)
592 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
593 SUPPLICANT_INTF ".Interface", "selectNetwork");
597 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
600 dbus_error_init(&error);
602 reply = dbus_connection_send_with_reply_and_block(connection,
603 message, -1, &error);
605 if (dbus_error_is_set(&error) == TRUE) {
606 connman_error("%s", error.message);
607 dbus_error_free(&error);
609 connman_error("Failed to select network");
610 dbus_message_unref(message);
614 dbus_message_unref(message);
616 dbus_message_unref(reply);
621 static int enable_network(struct supplicant_task *task)
623 DBusMessage *message, *reply;
626 DBG("task %p", task);
628 if (task->netpath == NULL)
631 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
632 SUPPLICANT_INTF ".Network", "enable");
636 dbus_error_init(&error);
638 reply = dbus_connection_send_with_reply_and_block(connection,
639 message, -1, &error);
641 if (dbus_error_is_set(&error) == TRUE) {
642 connman_error("%s", error.message);
643 dbus_error_free(&error);
645 connman_error("Failed to enable network");
646 dbus_message_unref(message);
650 dbus_message_unref(message);
652 dbus_message_unref(reply);
657 static int disable_network(struct supplicant_task *task)
659 DBusMessage *message, *reply;
662 DBG("task %p", task);
664 if (task->netpath == NULL)
667 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
668 SUPPLICANT_INTF ".Network", "disable");
672 dbus_error_init(&error);
674 reply = dbus_connection_send_with_reply_and_block(connection,
675 message, -1, &error);
677 if (dbus_error_is_set(&error) == TRUE) {
678 connman_error("%s", error.message);
679 dbus_error_free(&error);
681 connman_error("Failed to disable network");
682 dbus_message_unref(message);
686 dbus_message_unref(message);
688 dbus_message_unref(reply);
693 static int set_network(struct supplicant_task *task,
694 const unsigned char *network, int len,
695 const char *address, const char *security,
696 const char *passphrase)
698 DBusMessage *message, *reply;
699 DBusMessageIter array, dict;
702 DBG("task %p", task);
704 if (task->netpath == NULL)
707 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
708 SUPPLICANT_INTF ".Network", "set");
712 dbus_message_iter_init_append(message, &array);
714 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
715 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
716 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
717 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
719 if (address == NULL) {
720 dbus_uint32_t scan_ssid = 1;
721 connman_dbus_dict_append_variant(&dict, "scan_ssid",
722 DBUS_TYPE_UINT32, &scan_ssid);
724 connman_dbus_dict_append_variant(&dict, "bssid",
725 DBUS_TYPE_STRING, &address);
727 connman_dbus_dict_append_array(&dict, "ssid",
728 DBUS_TYPE_BYTE, &network, len);
730 if (g_ascii_strcasecmp(security, "wpa") == 0 ||
731 g_ascii_strcasecmp(security, "rsn") == 0) {
732 const char *key_mgmt = "WPA-PSK";
733 connman_dbus_dict_append_variant(&dict, "key_mgmt",
734 DBUS_TYPE_STRING, &key_mgmt);
736 if (passphrase && strlen(passphrase) > 0)
737 connman_dbus_dict_append_variant(&dict, "psk",
738 DBUS_TYPE_STRING, &passphrase);
739 } else if (g_ascii_strcasecmp(security, "wep") == 0) {
740 const char *key_mgmt = "NONE", *index = "0";
741 connman_dbus_dict_append_variant(&dict, "key_mgmt",
742 DBUS_TYPE_STRING, &key_mgmt);
745 int size = strlen(passphrase);
746 if (size == 10 || size == 26) {
747 unsigned char *key = malloc(13);
750 memset(tmp, 0, sizeof(tmp));
753 for (i = 0; i < size / 2; i++) {
754 memcpy(tmp, passphrase + (i * 2), 2);
755 key[i] = (unsigned char) strtol(tmp,
758 connman_dbus_dict_append_array(&dict,
759 "wep_key0", DBUS_TYPE_BYTE,
763 connman_dbus_dict_append_variant(&dict,
764 "wep_key0", DBUS_TYPE_STRING,
766 connman_dbus_dict_append_variant(&dict, "wep_tx_keyidx",
767 DBUS_TYPE_STRING, &index);
770 const char *key_mgmt = "NONE";
771 connman_dbus_dict_append_variant(&dict, "key_mgmt",
772 DBUS_TYPE_STRING, &key_mgmt);
775 dbus_message_iter_close_container(&array, &dict);
777 dbus_error_init(&error);
779 reply = dbus_connection_send_with_reply_and_block(connection,
780 message, -1, &error);
782 if (dbus_error_is_set(&error) == TRUE) {
783 connman_error("%s", error.message);
784 dbus_error_free(&error);
786 connman_error("Failed to set network options");
787 dbus_message_unref(message);
791 dbus_message_unref(message);
793 dbus_message_unref(reply);
798 static int initiate_scan(struct supplicant_task *task)
800 DBusMessage *message;
801 DBusPendingCall *call;
803 DBG("task %p", task);
805 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
806 SUPPLICANT_INTF ".Interface", "scan");
810 if (dbus_connection_send_with_reply(connection, message,
811 &call, TIMEOUT) == FALSE) {
812 connman_error("Failed to initiate scan");
813 dbus_message_unref(message);
817 dbus_message_unref(message);
826 { "<hidden>", "hidden" },
827 { "default", "linksys" },
835 { "comcomcom", "3com" },
837 { "Symbol", "symbol" },
838 { "Wireless" , "wireless" },
843 static char *build_group(const char *addr, const char *name,
844 const unsigned char *ssid, unsigned int ssid_len,
845 const char *mode, const char *security)
853 str = g_string_sized_new((ssid_len * 2) + 24);
857 for (i = 0; special_ssid[i].name; i++) {
858 if (g_strcmp0(special_ssid[i].name, name) == 0) {
859 if (special_ssid[i].value == NULL)
860 g_string_append_printf(str, "%s_%s",
863 g_string_append_printf(str, "%s_%s",
864 special_ssid[i].value, addr);
869 if (ssid_len > 0 && ssid[0] != '\0') {
870 for (i = 0; i < ssid_len; i++)
871 g_string_append_printf(str, "%02x", ssid[i]);
873 g_string_append_printf(str, "hidden_%s", addr);
876 g_string_append_printf(str, "_%s_%s", mode, security);
878 return g_string_free(str, FALSE);
881 static void extract_addr(DBusMessageIter *value,
882 struct supplicant_result *result)
884 DBusMessageIter array;
885 struct ether_addr *eth;
889 dbus_message_iter_recurse(value, &array);
890 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
897 result->addr = g_try_malloc0(18);
898 if (result->addr == NULL)
901 snprintf(result->addr, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
902 eth->ether_addr_octet[0],
903 eth->ether_addr_octet[1],
904 eth->ether_addr_octet[2],
905 eth->ether_addr_octet[3],
906 eth->ether_addr_octet[4],
907 eth->ether_addr_octet[5]);
909 result->path = g_try_malloc0(18);
910 if (result->path == NULL)
913 snprintf(result->path, 18, "%02x%02x%02x%02x%02x%02x",
914 eth->ether_addr_octet[0],
915 eth->ether_addr_octet[1],
916 eth->ether_addr_octet[2],
917 eth->ether_addr_octet[3],
918 eth->ether_addr_octet[4],
919 eth->ether_addr_octet[5]);
922 static void extract_ssid(DBusMessageIter *value,
923 struct supplicant_result *result)
925 DBusMessageIter array;
929 dbus_message_iter_recurse(value, &array);
930 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
935 result->ssid = g_try_malloc(ssid_len);
936 if (result->ssid == NULL)
939 memcpy(result->ssid, ssid, ssid_len);
940 result->ssid_len = ssid_len;
942 result->name = g_try_malloc0(ssid_len + 1);
943 if (result->name == NULL)
946 memcpy(result->name, ssid, ssid_len);
949 static void extract_wpaie(DBusMessageIter *value,
950 struct supplicant_result *result)
952 DBusMessageIter array;
956 dbus_message_iter_recurse(value, &array);
957 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
960 result->has_wpa = TRUE;
963 static void extract_rsnie(DBusMessageIter *value,
964 struct supplicant_result *result)
966 DBusMessageIter array;
970 dbus_message_iter_recurse(value, &array);
971 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
974 result->has_rsn = TRUE;
977 static void extract_wpsie(DBusMessageIter *value,
978 struct supplicant_result *result)
980 DBusMessageIter array;
984 dbus_message_iter_recurse(value, &array);
985 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
988 result->has_wps = TRUE;
991 static void extract_capabilites(DBusMessageIter *value,
992 struct supplicant_result *result)
994 dbus_message_iter_get_basic(value, &result->capabilities);
996 if (result->capabilities & IEEE80211_CAP_ESS)
997 result->adhoc = FALSE;
998 else if (result->capabilities & IEEE80211_CAP_IBSS)
999 result->adhoc = TRUE;
1001 if (result->capabilities & IEEE80211_CAP_PRIVACY)
1002 result->has_wep = TRUE;
1005 static unsigned char calculate_strength(struct supplicant_result *result)
1007 if (result->quality < 0) {
1008 unsigned char strength;
1010 if (result->level > 0)
1011 strength = 100 - result->level;
1013 strength = 120 + result->level;
1021 return result->quality;
1024 static unsigned short calculate_channel(struct supplicant_result *result)
1026 if (result->frequency < 0)
1029 return (result->frequency - 2407) / 5;
1032 static void get_properties(struct supplicant_task *task);
1034 static void properties_reply(DBusPendingCall *call, void *user_data)
1036 struct supplicant_task *task = user_data;
1037 struct supplicant_result result;
1038 struct connman_network *network;
1040 DBusMessageIter array, dict;
1041 unsigned char strength;
1042 unsigned short channel, frequency;
1043 const char *mode, *security;
1046 DBG("task %p", task);
1048 reply = dbus_pending_call_steal_reply(call);
1049 if (reply == NULL) {
1050 get_properties(task);
1054 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1055 dbus_message_unref(reply);
1056 get_properties(task);
1060 memset(&result, 0, sizeof(result));
1061 result.frequency = -1;
1062 result.quality = -1;
1066 dbus_message_iter_init(reply, &array);
1068 dbus_message_iter_recurse(&array, &dict);
1070 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1071 DBusMessageIter entry, value;
1074 dbus_message_iter_recurse(&dict, &entry);
1075 dbus_message_iter_get_basic(&entry, &key);
1077 dbus_message_iter_next(&entry);
1079 dbus_message_iter_recurse(&entry, &value);
1081 //type = dbus_message_iter_get_arg_type(&value);
1082 //dbus_message_iter_get_basic(&value, &val);
1090 * frequency : i (105)
1091 * capabilities : q (113)
1098 if (g_str_equal(key, "bssid") == TRUE)
1099 extract_addr(&value, &result);
1100 else if (g_str_equal(key, "ssid") == TRUE)
1101 extract_ssid(&value, &result);
1102 else if (g_str_equal(key, "wpaie") == TRUE)
1103 extract_wpaie(&value, &result);
1104 else if (g_str_equal(key, "rsnie") == TRUE)
1105 extract_rsnie(&value, &result);
1106 else if (g_str_equal(key, "wpsie") == TRUE)
1107 extract_wpsie(&value, &result);
1108 else if (g_str_equal(key, "capabilities") == TRUE)
1109 extract_capabilites(&value, &result);
1110 else if (g_str_equal(key, "frequency") == TRUE)
1111 dbus_message_iter_get_basic(&value, &result.frequency);
1112 else if (g_str_equal(key, "quality") == TRUE)
1113 dbus_message_iter_get_basic(&value, &result.quality);
1114 else if (g_str_equal(key, "noise") == TRUE)
1115 dbus_message_iter_get_basic(&value, &result.noise);
1116 else if (g_str_equal(key, "level") == TRUE)
1117 dbus_message_iter_get_basic(&value, &result.level);
1118 else if (g_str_equal(key, "maxrate") == TRUE)
1119 dbus_message_iter_get_basic(&value, &result.maxrate);
1121 dbus_message_iter_next(&dict);
1124 if (result.path == NULL)
1127 if (result.path[0] == '\0')
1130 if (result.frequency > 0 && result.frequency < 14)
1131 result.frequency = 2407 + (5 * result.frequency);
1132 else if (result.frequency == 14)
1133 result.frequency = 2484;
1135 strength = calculate_strength(&result);
1136 channel = calculate_channel(&result);
1138 frequency = (result.frequency < 0) ? 0 : result.frequency;
1140 if (result.has_rsn == TRUE)
1142 else if (result.has_wpa == TRUE)
1144 else if (result.has_wep == TRUE)
1149 mode = (result.adhoc == TRUE) ? "adhoc" : "managed";
1151 group = build_group(result.path, result.name,
1152 result.ssid, result.ssid_len,
1155 network = connman_device_get_network(task->device, result.path);
1156 if (network == NULL) {
1159 network = connman_network_create(result.path,
1160 CONNMAN_NETWORK_TYPE_WIFI);
1161 if (network == NULL)
1164 index = connman_device_get_index(task->device);
1165 connman_network_set_index(network, index);
1167 connman_network_set_protocol(network,
1168 CONNMAN_NETWORK_PROTOCOL_IP);
1170 connman_network_set_string(network, "Address", result.addr);
1172 if (connman_device_add_network(task->device, network) < 0) {
1173 connman_network_unref(network);
1178 if (result.name != NULL && result.name[0] != '\0')
1179 connman_network_set_string(network, "Name", result.name);
1181 connman_network_set_blob(network, "WiFi.SSID",
1182 result.ssid, result.ssid_len);
1184 connman_network_set_string(network, "WiFi.Mode", mode);
1186 DBG("%s (%s %s) strength %d (%s)",
1187 result.name, mode, security, strength,
1188 (result.has_wps == TRUE) ? "WPS" : "no WPS");
1190 connman_network_set_available(network, TRUE);
1191 connman_network_set_uint8(network, "Strength", strength);
1192 connman_network_set_uint16(network, "Frequency", frequency);
1194 connman_network_set_uint16(network, "WiFi.Channel", channel);
1195 connman_network_set_string(network, "WiFi.Security", security);
1197 connman_network_set_group(network, group);
1202 g_free(result.path);
1203 g_free(result.addr);
1204 g_free(result.name);
1205 g_free(result.ssid);
1207 dbus_message_unref(reply);
1209 get_properties(task);
1212 static void get_properties(struct supplicant_task *task)
1214 DBusMessage *message;
1215 DBusPendingCall *call;
1218 path = g_slist_nth_data(task->scan_results, 0);
1222 message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
1223 SUPPLICANT_INTF ".BSSID",
1226 task->scan_results = g_slist_remove(task->scan_results, path);
1229 if (message == NULL)
1232 if (dbus_connection_send_with_reply(connection, message,
1233 &call, TIMEOUT) == FALSE) {
1234 connman_error("Failed to get network properties");
1235 dbus_message_unref(message);
1240 connman_error("D-Bus connection not available");
1241 dbus_message_unref(message);
1245 dbus_pending_call_set_notify(call, properties_reply, task, NULL);
1247 dbus_message_unref(message);
1252 if (task->noscan == FALSE)
1253 connman_device_set_scanning(task->device, FALSE);
1256 static void scan_results_reply(DBusPendingCall *call, void *user_data)
1258 struct supplicant_task *task = user_data;
1264 DBG("task %p", task);
1266 reply = dbus_pending_call_steal_reply(call);
1270 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
1273 dbus_error_init(&error);
1275 if (dbus_message_get_args(reply, &error,
1276 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
1277 &results, &num_results,
1278 DBUS_TYPE_INVALID) == FALSE) {
1279 if (dbus_error_is_set(&error) == TRUE) {
1280 connman_error("%s", error.message);
1281 dbus_error_free(&error);
1283 connman_error("Wrong arguments for scan result");
1287 if (num_results == 0)
1290 for (i = 0; i < num_results; i++) {
1291 char *path = g_strdup(results[i]);
1295 task->scan_results = g_slist_append(task->scan_results, path);
1298 g_strfreev(results);
1300 dbus_message_unref(reply);
1302 get_properties(task);
1307 dbus_message_unref(reply);
1310 if (task->noscan == FALSE)
1311 connman_device_set_scanning(task->device, FALSE);
1314 static void scan_results_available(struct supplicant_task *task)
1316 DBusMessage *message;
1317 DBusPendingCall *call;
1319 DBG("task %p", task);
1321 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
1322 SUPPLICANT_INTF ".Interface",
1324 if (message == NULL)
1327 if (dbus_connection_send_with_reply(connection, message,
1328 &call, TIMEOUT) == FALSE) {
1329 connman_error("Failed to request scan result");
1333 if (task->noscan == FALSE)
1334 connman_device_set_scanning(task->device, TRUE);
1337 connman_error("D-Bus connection not available");
1341 dbus_pending_call_set_notify(call, scan_results_reply, task, NULL);
1344 dbus_message_unref(message);
1347 static enum supplicant_state string2state(const char *state)
1349 if (g_str_equal(state, "INACTIVE") == TRUE)
1350 return WPA_INACTIVE;
1351 else if (g_str_equal(state, "SCANNING") == TRUE)
1352 return WPA_SCANNING;
1353 else if (g_str_equal(state, "ASSOCIATING") == TRUE)
1354 return WPA_ASSOCIATING;
1355 else if (g_str_equal(state, "ASSOCIATED") == TRUE)
1356 return WPA_ASSOCIATED;
1357 else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
1358 return WPA_GROUP_HANDSHAKE;
1359 else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
1360 return WPA_4WAY_HANDSHAKE;
1361 else if (g_str_equal(state, "COMPLETED") == TRUE)
1362 return WPA_COMPLETED;
1363 else if (g_str_equal(state, "DISCONNECTED") == TRUE)
1364 return WPA_DISCONNECTED;
1369 static void state_change(struct supplicant_task *task, DBusMessage *msg)
1372 const char *newstate, *oldstate;
1373 enum supplicant_state state;
1375 dbus_error_init(&error);
1377 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &newstate,
1378 DBUS_TYPE_STRING, &oldstate,
1379 DBUS_TYPE_INVALID) == FALSE) {
1380 if (dbus_error_is_set(&error) == TRUE) {
1381 connman_error("%s", error.message);
1382 dbus_error_free(&error);
1384 connman_error("Wrong arguments for state change");
1388 DBG("state %s ==> %s", oldstate, newstate);
1390 state = string2state(newstate);
1391 if (state == WPA_INVALID)
1394 task->state = state;
1396 switch (task->state) {
1398 task->noscan = TRUE;
1399 connman_device_set_scanning(task->device, TRUE);
1401 case WPA_ASSOCIATING:
1402 case WPA_ASSOCIATED:
1403 case WPA_4WAY_HANDSHAKE:
1404 case WPA_GROUP_HANDSHAKE:
1405 task->noscan = TRUE;
1408 case WPA_DISCONNECTED:
1409 task->noscan = FALSE;
1412 task->noscan = FALSE;
1413 connman_device_set_scanning(task->device, FALSE);
1419 if (task->network == NULL)
1422 switch (task->state) {
1425 connman_network_set_connected(task->network, TRUE);
1426 connman_device_set_scanning(task->device, FALSE);
1428 case WPA_DISCONNECTED:
1430 connman_network_set_connected(task->network, FALSE);
1431 connman_device_set_scanning(task->device, FALSE);
1433 case WPA_ASSOCIATING:
1434 connman_network_set_associating(task->network, TRUE);
1437 connman_network_set_associating(task->network, FALSE);
1442 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1443 DBusMessage *msg, void *data)
1445 struct supplicant_task *task;
1446 const char *member, *path;
1448 if (dbus_message_has_interface(msg,
1449 SUPPLICANT_INTF ".Interface") == FALSE)
1450 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1452 member = dbus_message_get_member(msg);
1454 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1456 path = dbus_message_get_path(msg);
1458 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1460 task = find_task_by_path(path);
1462 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1464 DBG("task %p member %s", task, member);
1466 if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
1467 scan_results_available(task);
1468 else if (g_str_equal(member, "StateChange") == TRUE)
1469 state_change(task, msg);
1471 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1474 int supplicant_start(struct connman_device *device)
1476 struct supplicant_task *task;
1478 DBG("device %p", device);
1480 task = g_try_new0(struct supplicant_task, 1);
1484 task->ifindex = connman_device_get_index(device);
1485 task->ifname = inet_index2name(task->ifindex);
1487 if (task->ifname == NULL) {
1492 task->device = connman_device_ref(device);
1494 task->created = FALSE;
1495 task->noscan = FALSE;
1496 task->state = WPA_INVALID;
1498 task_list = g_slist_append(task_list, task);
1500 return create_interface(task);
1503 int supplicant_stop(struct connman_device *device)
1505 int index = connman_device_get_index(device);
1506 struct supplicant_task *task;
1508 DBG("device %p", device);
1510 task = find_task_by_index(index);
1514 task_list = g_slist_remove(task_list, task);
1516 disable_network(task);
1518 remove_network(task);
1520 return remove_interface(task);
1523 int supplicant_scan(struct connman_device *device)
1525 int index = connman_device_get_index(device);
1526 struct supplicant_task *task;
1529 DBG("device %p", device);
1531 task = find_task_by_index(index);
1535 switch (task->state) {
1538 case WPA_ASSOCIATING:
1539 case WPA_ASSOCIATED:
1540 case WPA_4WAY_HANDSHAKE:
1541 case WPA_GROUP_HANDSHAKE:
1547 err = initiate_scan(task);
1552 int supplicant_connect(struct connman_network *network)
1554 struct supplicant_task *task;
1555 const char *address, *security, *passphrase;
1557 unsigned int ssid_len;
1560 DBG("network %p", network);
1562 address = connman_network_get_string(network, "Address");
1563 security = connman_network_get_string(network, "WiFi.Security");
1564 passphrase = connman_network_get_string(network, "WiFi.Passphrase");
1566 ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
1568 DBG("address %s security %s passphrase %s",
1569 address, security, passphrase);
1571 if (security == NULL && passphrase == NULL)
1574 if (g_str_equal(security, "none") == FALSE && passphrase == NULL)
1577 index = connman_network_get_index(network);
1579 task = find_task_by_index(index);
1583 task->network = connman_network_ref(network);
1587 select_network(task);
1588 disable_network(task);
1590 set_network(task, ssid, ssid_len, address, security, passphrase);
1592 enable_network(task);
1594 connman_network_set_associating(task->network, TRUE);
1599 int supplicant_disconnect(struct connman_network *network)
1601 struct supplicant_task *task;
1604 DBG("network %p", network);
1606 index = connman_network_get_index(network);
1608 task = find_task_by_index(index);
1612 disable_network(task);
1614 remove_network(task);
1616 connman_network_set_connected(task->network, FALSE);
1618 connman_network_unref(task->network);
1623 static void supplicant_activate(DBusConnection *conn)
1625 DBusMessage *message;
1627 DBG("conn %p", conn);
1629 message = dbus_message_new_method_call(SUPPLICANT_NAME, "/",
1630 DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
1631 if (message == NULL)
1634 dbus_message_set_no_reply(message, TRUE);
1636 dbus_connection_send(conn, message, NULL);
1638 dbus_message_unref(message);
1641 static GSList *driver_list = NULL;
1643 static void supplicant_probe(DBusConnection *conn, void *user_data)
1647 DBG("conn %p", conn);
1649 for (list = driver_list; list; list = list->next) {
1650 struct supplicant_driver *driver = list->data;
1652 DBG("driver %p name %s", driver, driver->name);
1659 static void supplicant_remove(DBusConnection *conn, void *user_data)
1663 DBG("conn %p", conn);
1665 for (list = driver_list; list; list = list->next) {
1666 struct supplicant_driver *driver = list->data;
1668 DBG("driver %p name %s", driver, driver->name);
1675 static const char *supplicant_rule = "type=signal,"
1676 "interface=" SUPPLICANT_INTF ".Interface";
1679 static int supplicant_create(void)
1681 if (g_slist_length(driver_list) > 0)
1684 connection = connman_dbus_get_connection();
1685 if (connection == NULL)
1688 DBG("connection %p", connection);
1690 if (dbus_connection_add_filter(connection,
1691 supplicant_filter, NULL, NULL) == FALSE) {
1692 connection = connman_dbus_get_connection();
1696 dbus_bus_add_match(connection, supplicant_rule, NULL);
1697 dbus_connection_flush(connection);
1699 watch = g_dbus_add_service_watch(connection, SUPPLICANT_NAME,
1700 supplicant_probe, supplicant_remove, NULL, NULL);
1705 static void supplicant_destroy(void)
1707 if (g_slist_length(driver_list) > 0)
1710 DBG("connection %p", connection);
1713 g_dbus_remove_watch(connection, watch);
1715 dbus_bus_remove_match(connection, supplicant_rule, NULL);
1716 dbus_connection_flush(connection);
1718 dbus_connection_remove_filter(connection, supplicant_filter, NULL);
1720 dbus_connection_unref(connection);
1724 int supplicant_register(struct supplicant_driver *driver)
1728 DBG("driver %p name %s", driver, driver->name);
1730 err = supplicant_create();
1734 driver_list = g_slist_append(driver_list, driver);
1736 if (g_dbus_check_service(connection, SUPPLICANT_NAME) == TRUE)
1737 supplicant_probe(connection, NULL);
1739 supplicant_activate(connection);
1744 void supplicant_unregister(struct supplicant_driver *driver)
1746 DBG("driver %p name %s", driver, driver->name);
1748 supplicant_remove(connection, NULL);
1750 driver_list = g_slist_remove(driver_list, driver);
1752 supplicant_destroy();