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
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <linux/if_arp.h>
34 #include <linux/wireless.h>
35 #include <net/ethernet.h>
39 #define CONNMAN_API_SUBJECT_TO_CHANGE
40 #include <connman/device.h>
41 #include <connman/option.h>
42 #include <connman/inet.h>
43 #include <connman/dbus.h>
44 #include <connman/log.h>
46 #include "supplicant.h"
50 #define IEEE80211_CAP_ESS 0x0001
51 #define IEEE80211_CAP_IBSS 0x0002
52 #define IEEE80211_CAP_PRIVACY 0x0010
54 #define SUPPLICANT_NAME "fi.epitest.hostap.WPASupplicant"
55 #define SUPPLICANT_INTF "fi.epitest.hostap.WPASupplicant"
56 #define SUPPLICANT_PATH "/fi/epitest/hostap/WPASupplicant"
58 /* Taken from "WPA Supplicant - Common definitions" */
59 enum supplicant_state {
61 * WPA_DISCONNECTED - Disconnected state
63 * This state indicates that client is not associated, but is likely to
64 * start looking for an access point. This state is entered when a
70 * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
72 * This state is entered if there are no enabled networks in the
73 * configuration. wpa_supplicant is not trying to associate with a new
74 * network and external interaction (e.g., ctrl_iface call to add or
75 * enable a network) is needed to start association.
80 * WPA_SCANNING - Scanning for a network
82 * This state is entered when wpa_supplicant starts scanning for a
88 * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
90 * This state is entered when wpa_supplicant has found a suitable BSS
91 * to associate with and the driver is configured to try to associate
92 * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
93 * state is entered when the driver is configured to try to associate
94 * with a network using the configured SSID and security policy.
99 * WPA_ASSOCIATED - Association completed
101 * This state is entered when the driver reports that association has
102 * been successfully completed with an AP. If IEEE 802.1X is used
103 * (with or without WPA/WPA2), wpa_supplicant remains in this state
104 * until the IEEE 802.1X/EAPOL authentication has been completed.
109 * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
111 * This state is entered when WPA/WPA2 4-Way Handshake is started. In
112 * case of WPA-PSK, this happens when receiving the first EAPOL-Key
113 * frame after association. In case of WPA-EAP, this state is entered
114 * when the IEEE 802.1X/EAPOL authentication has been completed.
119 * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
121 * This state is entered when 4-Way Key Handshake has been completed
122 * (i.e., when the supplicant sends out message 4/4) and when Group
123 * Key rekeying is started by the AP (i.e., when supplicant receives
129 * WPA_COMPLETED - All authentication completed
131 * This state is entered when the full authentication process is
132 * completed. In case of WPA2, this happens when the 4-Way Handshake is
133 * successfully completed. With WPA, this state is entered after the
134 * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
135 * completed after dynamic keys are received (or if not used, after
136 * the EAP authentication has been completed). With static WEP keys and
137 * plaintext connections, this state is entered when an association
138 * has been completed.
140 * This state indicates that the supplicant has completed its
141 * processing for the association phase and that data connection is
147 * WPA_INVALID - Invalid state (parsing error)
149 * This state is returned if the string input is invalid. It is not
150 * an official wpa_supplicant state.
155 struct supplicant_result {
159 unsigned int addr_len;
161 unsigned int ssid_len;
162 dbus_uint16_t capabilities;
168 dbus_int32_t frequency;
169 dbus_int32_t quality;
172 dbus_int32_t maxrate;
175 struct supplicant_task {
178 struct connman_device *device;
179 struct connman_network *network;
180 struct connman_network *pending_network;
184 enum supplicant_state state;
186 GSList *scan_results;
187 struct iw_range *range;
188 gboolean disconnecting;
191 static GSList *task_list = NULL;
193 static DBusConnection *connection;
195 static void free_task(struct supplicant_task *task)
197 DBG("task %p", task);
199 g_free(task->ifname);
204 static struct supplicant_task *find_task_by_index(int index)
208 for (list = task_list; list; list = list->next) {
209 struct supplicant_task *task = list->data;
211 if (task->ifindex == index)
218 static struct supplicant_task *find_task_by_path(const char *path)
222 for (list = task_list; list; list = list->next) {
223 struct supplicant_task *task = list->data;
225 if (g_strcmp0(task->path, path) == 0)
232 static int get_range(struct supplicant_task *task)
237 fd = socket(PF_INET, SOCK_DGRAM, 0);
241 memset(&wrq, 0, sizeof(struct iwreq));
242 strncpy(wrq.ifr_name, task->ifname, IFNAMSIZ);
243 wrq.u.data.pointer = task->range;
244 wrq.u.data.length = sizeof(struct iw_range);
246 err = ioctl(fd, SIOCGIWRANGE, &wrq);
253 static char *get_bssid(struct connman_device *device)
256 unsigned char ioctl_bssid[ETH_ALEN];
260 if (connman_device_get_type(device) != CONNMAN_DEVICE_TYPE_WIFI)
263 fd = socket(PF_INET, SOCK_DGRAM, 0);
267 memset(&wrq, 0, sizeof(wrq));
268 strncpy(wrq.ifr_name, connman_device_get_interface(device), IFNAMSIZ);
270 ret = ioctl(fd, SIOCGIWAP, &wrq);
275 memcpy(ioctl_bssid, wrq.u.ap_addr.sa_data, ETH_ALEN);
277 bssid = g_try_malloc0(13);
281 snprintf(bssid, 13, "%02x%02x%02x%02x%02x%02x",
282 ioctl_bssid[0], ioctl_bssid[1],
283 ioctl_bssid[2], ioctl_bssid[3],
284 ioctl_bssid[4], ioctl_bssid[5]);
289 static void add_interface_reply(DBusPendingCall *call, void *user_data)
291 struct supplicant_task *task = user_data;
296 DBG("task %p", task);
298 reply = dbus_pending_call_steal_reply(call);
302 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
305 dbus_error_init(&error);
307 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
308 DBUS_TYPE_INVALID) == FALSE) {
309 if (dbus_error_is_set(&error) == TRUE) {
310 connman_error("%s", error.message);
311 dbus_error_free(&error);
313 connman_error("Wrong arguments for add interface");
317 DBG("path %s", path);
319 task->path = g_strdup(path);
320 task->created = TRUE;
322 connman_device_set_powered(task->device, TRUE);
324 dbus_message_unref(reply);
329 task_list = g_slist_remove(task_list, task);
331 connman_device_unref(task->device);
336 static int add_interface(struct supplicant_task *task)
338 const char *driver = connman_option_get_string("wifi");
339 DBusMessage *message;
340 DBusMessageIter array, dict;
341 DBusPendingCall *call;
343 DBG("task %p", task);
345 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
346 SUPPLICANT_INTF, "addInterface");
350 dbus_message_iter_init_append(message, &array);
352 dbus_message_iter_append_basic(&array,
353 DBUS_TYPE_STRING, &task->ifname);
355 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
356 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
357 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
358 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
360 connman_dbus_dict_append_variant(&dict, "driver",
361 DBUS_TYPE_STRING, &driver);
363 dbus_message_iter_close_container(&array, &dict);
365 if (dbus_connection_send_with_reply(connection, message,
366 &call, TIMEOUT) == FALSE) {
367 connman_error("Failed to add interface");
368 dbus_message_unref(message);
373 connman_error("D-Bus connection not available");
374 dbus_message_unref(message);
378 dbus_pending_call_set_notify(call, add_interface_reply, task, NULL);
380 dbus_message_unref(message);
385 static void get_interface_reply(DBusPendingCall *call, void *user_data)
387 struct supplicant_task *task = user_data;
392 DBG("task %p", task);
394 reply = dbus_pending_call_steal_reply(call);
398 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
403 dbus_error_init(&error);
405 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
406 DBUS_TYPE_INVALID) == FALSE) {
407 if (dbus_error_is_set(&error) == TRUE) {
408 connman_error("%s", error.message);
409 dbus_error_free(&error);
411 connman_error("Wrong arguments for get interface");
415 DBG("path %s", path);
417 task->path = g_strdup(path);
418 task->created = FALSE;
420 connman_device_set_powered(task->device, TRUE);
423 dbus_message_unref(reply);
426 static int create_interface(struct supplicant_task *task)
428 DBusMessage *message;
429 DBusPendingCall *call;
431 DBG("task %p", task);
433 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
434 SUPPLICANT_INTF, "getInterface");
438 dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
441 if (dbus_connection_send_with_reply(connection, message,
442 &call, TIMEOUT) == FALSE) {
443 connman_error("Failed to get interface");
444 dbus_message_unref(message);
449 connman_error("D-Bus connection not available");
450 dbus_message_unref(message);
454 dbus_pending_call_set_notify(call, get_interface_reply, task, NULL);
456 dbus_message_unref(message);
461 static void remove_interface_reply(DBusPendingCall *call, void *user_data)
463 struct supplicant_task *task = user_data;
466 DBG("task %p", task);
468 reply = dbus_pending_call_steal_reply(call);
470 connman_device_set_powered(task->device, FALSE);
472 connman_device_unref(task->device);
474 connman_inet_ifdown(task->ifindex);
478 dbus_message_unref(reply);
481 static int remove_interface(struct supplicant_task *task)
483 DBusMessage *message;
484 DBusPendingCall *call;
486 DBG("task %p", task);
488 if (task->created == FALSE) {
489 connman_device_set_powered(task->device, FALSE);
493 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
494 SUPPLICANT_INTF, "removeInterface");
498 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->path,
501 if (dbus_connection_send_with_reply(connection, message,
502 &call, TIMEOUT) == FALSE) {
503 connman_error("Failed to remove interface");
504 dbus_message_unref(message);
509 connman_error("D-Bus connection not available");
510 dbus_message_unref(message);
514 dbus_pending_call_set_notify(call, remove_interface_reply, task, NULL);
516 dbus_message_unref(message);
522 static int set_ap_scan(struct supplicant_task *task)
524 DBusMessage *message, *reply;
528 DBG("task %p", task);
530 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
531 SUPPLICANT_INTF ".Interface", "setAPScan");
535 dbus_message_append_args(message, DBUS_TYPE_UINT32, &ap_scan,
538 dbus_error_init(&error);
540 reply = dbus_connection_send_with_reply_and_block(connection,
541 message, -1, &error);
543 if (dbus_error_is_set(&error) == TRUE) {
544 connman_error("%s", error.message);
545 dbus_error_free(&error);
547 connman_error("Failed to set AP scan");
548 dbus_message_unref(message);
552 dbus_message_unref(message);
554 dbus_message_unref(reply);
560 static int add_network(struct supplicant_task *task)
562 DBusMessage *message, *reply;
566 DBG("task %p", task);
568 if (task->netpath != NULL)
571 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
572 SUPPLICANT_INTF ".Interface", "addNetwork");
576 dbus_error_init(&error);
578 reply = dbus_connection_send_with_reply_and_block(connection,
579 message, -1, &error);
581 if (dbus_error_is_set(&error) == TRUE) {
582 connman_error("%s", error.message);
583 dbus_error_free(&error);
585 connman_error("Failed to add network");
586 dbus_message_unref(message);
590 dbus_message_unref(message);
592 dbus_error_init(&error);
594 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
595 DBUS_TYPE_INVALID) == FALSE) {
596 if (dbus_error_is_set(&error) == TRUE) {
597 connman_error("%s", error.message);
598 dbus_error_free(&error);
600 connman_error("Wrong arguments for network");
601 dbus_message_unref(reply);
605 DBG("path %s", path);
607 task->netpath = g_strdup(path);
609 dbus_message_unref(reply);
614 static int remove_network(struct supplicant_task *task)
616 DBusMessage *message, *reply;
619 DBG("task %p", task);
621 if (task->netpath == NULL)
624 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
625 SUPPLICANT_INTF ".Interface", "removeNetwork");
629 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
632 dbus_error_init(&error);
634 reply = dbus_connection_send_with_reply_and_block(connection,
635 message, -1, &error);
637 if (dbus_error_is_set(&error) == TRUE) {
638 connman_error("%s", error.message);
639 dbus_error_free(&error);
641 connman_error("Failed to remove network");
642 dbus_message_unref(message);
646 dbus_message_unref(message);
648 dbus_message_unref(reply);
650 g_free(task->netpath);
651 task->netpath = NULL;
656 static int select_network(struct supplicant_task *task)
658 DBusMessage *message, *reply;
661 DBG("task %p", task);
663 if (task->netpath == NULL)
666 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
667 SUPPLICANT_INTF ".Interface", "selectNetwork");
671 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath,
674 dbus_error_init(&error);
676 reply = dbus_connection_send_with_reply_and_block(connection,
677 message, -1, &error);
679 if (dbus_error_is_set(&error) == TRUE) {
680 connman_error("%s", error.message);
681 dbus_error_free(&error);
683 connman_error("Failed to select network");
684 dbus_message_unref(message);
688 dbus_message_unref(message);
690 dbus_message_unref(reply);
695 static int enable_network(struct supplicant_task *task)
697 DBusMessage *message, *reply;
700 DBG("task %p", task);
702 if (task->netpath == NULL)
705 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
706 SUPPLICANT_INTF ".Network", "enable");
710 dbus_error_init(&error);
712 reply = dbus_connection_send_with_reply_and_block(connection,
713 message, -1, &error);
715 if (dbus_error_is_set(&error) == TRUE) {
716 connman_error("%s", error.message);
717 dbus_error_free(&error);
719 connman_error("Failed to enable network");
720 dbus_message_unref(message);
724 dbus_message_unref(message);
726 dbus_message_unref(reply);
731 static int disable_network(struct supplicant_task *task)
733 DBusMessage *message, *reply;
736 DBG("task %p", task);
738 if (task->netpath == NULL)
741 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
742 SUPPLICANT_INTF ".Network", "disable");
746 dbus_error_init(&error);
748 reply = dbus_connection_send_with_reply_and_block(connection,
749 message, -1, &error);
751 if (dbus_error_is_set(&error) == TRUE) {
752 connman_error("%s", error.message);
753 dbus_error_free(&error);
755 connman_error("Failed to disable network");
756 dbus_message_unref(message);
760 dbus_message_unref(message);
762 dbus_message_unref(reply);
767 static int set_network(struct supplicant_task *task,
768 const unsigned char *network, int len,
769 const char *address, const char *security,
770 const char *passphrase)
772 DBusMessage *message, *reply;
773 DBusMessageIter array, dict;
775 dbus_uint32_t scan_ssid = 1;
777 DBG("task %p", task);
779 if (task->netpath == NULL)
782 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath,
783 SUPPLICANT_INTF ".Network", "set");
787 dbus_message_iter_init_append(message, &array);
789 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
790 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
791 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
792 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
794 connman_dbus_dict_append_variant(&dict, "scan_ssid",
795 DBUS_TYPE_UINT32, &scan_ssid);
798 connman_dbus_dict_append_variant(&dict, "bssid",
799 DBUS_TYPE_STRING, &address);
801 connman_dbus_dict_append_array(&dict, "ssid",
802 DBUS_TYPE_BYTE, &network, len);
804 if (g_ascii_strcasecmp(security, "wpa") == 0 ||
805 g_ascii_strcasecmp(security, "rsn") == 0) {
806 const char *key_mgmt = "WPA-PSK";
807 connman_dbus_dict_append_variant(&dict, "key_mgmt",
808 DBUS_TYPE_STRING, &key_mgmt);
810 if (passphrase && strlen(passphrase) > 0)
811 connman_dbus_dict_append_variant(&dict, "psk",
812 DBUS_TYPE_STRING, &passphrase);
813 } else if (g_ascii_strcasecmp(security, "wep") == 0) {
814 const char *key_mgmt = "NONE";
815 const char *auth_alg = "OPEN SHARED";
816 const char *key_index = "0";
818 connman_dbus_dict_append_variant(&dict, "auth_alg",
819 DBUS_TYPE_STRING, &auth_alg);
821 connman_dbus_dict_append_variant(&dict, "key_mgmt",
822 DBUS_TYPE_STRING, &key_mgmt);
825 int size = strlen(passphrase);
826 if (size == 10 || size == 26) {
827 unsigned char *key = malloc(13);
830 memset(tmp, 0, sizeof(tmp));
833 for (i = 0; i < size / 2; i++) {
834 memcpy(tmp, passphrase + (i * 2), 2);
835 key[i] = (unsigned char) strtol(tmp,
838 connman_dbus_dict_append_array(&dict,
839 "wep_key0", DBUS_TYPE_BYTE,
843 connman_dbus_dict_append_variant(&dict,
844 "wep_key0", DBUS_TYPE_STRING,
847 connman_dbus_dict_append_variant(&dict, "wep_tx_keyidx",
848 DBUS_TYPE_STRING, &key_index);
851 const char *key_mgmt = "NONE";
852 connman_dbus_dict_append_variant(&dict, "key_mgmt",
853 DBUS_TYPE_STRING, &key_mgmt);
856 dbus_message_iter_close_container(&array, &dict);
858 dbus_error_init(&error);
860 reply = dbus_connection_send_with_reply_and_block(connection,
861 message, -1, &error);
863 if (dbus_error_is_set(&error) == TRUE) {
864 connman_error("%s", error.message);
865 dbus_error_free(&error);
867 connman_error("Failed to set network options");
868 dbus_message_unref(message);
872 dbus_message_unref(message);
874 dbus_message_unref(reply);
879 static int initiate_scan(struct supplicant_task *task)
881 DBusMessage *message;
882 DBusPendingCall *call;
884 DBG("task %p", task);
886 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
887 SUPPLICANT_INTF ".Interface", "scan");
891 if (dbus_connection_send_with_reply(connection, message,
892 &call, TIMEOUT) == FALSE) {
893 connman_error("Failed to initiate scan");
894 dbus_message_unref(message);
898 dbus_message_unref(message);
907 { "<hidden>", "hidden" },
908 { "default", "linksys" },
916 { "comcomcom", "3com" },
918 { "Symbol", "symbol" },
919 { "Motorola", "motorola" },
920 { "Wireless" , "wireless" },
925 static char *build_group(const char *addr, const char *name,
926 const unsigned char *ssid, unsigned int ssid_len,
927 const char *mode, const char *security)
935 str = g_string_sized_new((ssid_len * 2) + 24);
939 for (i = 0; special_ssid[i].name; i++) {
940 if (g_strcmp0(special_ssid[i].name, name) == 0) {
941 if (special_ssid[i].value == NULL)
942 g_string_append_printf(str, "%s_%s",
945 g_string_append_printf(str, "%s_%s",
946 special_ssid[i].value, addr);
951 if (ssid_len > 0 && ssid[0] != '\0') {
952 for (i = 0; i < ssid_len; i++)
953 g_string_append_printf(str, "%02x", ssid[i]);
955 g_string_append_printf(str, "hidden_%s", addr);
958 g_string_append_printf(str, "_%s_%s", mode, security);
960 return g_string_free(str, FALSE);
963 static void extract_addr(DBusMessageIter *value,
964 struct supplicant_result *result)
966 DBusMessageIter array;
967 struct ether_addr *eth;
971 dbus_message_iter_recurse(value, &array);
972 dbus_message_iter_get_fixed_array(&array, &addr, &addr_len);
977 result->addr = g_try_malloc(addr_len);
978 if (result->addr == NULL)
981 memcpy(result->addr, addr, addr_len);
982 result->addr_len = addr_len;
984 result->path = g_try_malloc0(13);
985 if (result->path == NULL)
990 snprintf(result->path, 13, "%02x%02x%02x%02x%02x%02x",
991 eth->ether_addr_octet[0],
992 eth->ether_addr_octet[1],
993 eth->ether_addr_octet[2],
994 eth->ether_addr_octet[3],
995 eth->ether_addr_octet[4],
996 eth->ether_addr_octet[5]);
999 static void extract_ssid(DBusMessageIter *value,
1000 struct supplicant_result *result)
1002 DBusMessageIter array;
1003 unsigned char *ssid;
1006 dbus_message_iter_recurse(value, &array);
1007 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
1012 result->ssid = g_try_malloc(ssid_len);
1013 if (result->ssid == NULL)
1016 memcpy(result->ssid, ssid, ssid_len);
1017 result->ssid_len = ssid_len;
1019 result->name = g_try_malloc0(ssid_len + 1);
1020 if (result->name == NULL)
1023 for (i = 0; i < ssid_len; i++) {
1024 if (g_ascii_isprint(ssid[i]))
1025 result->name[i] = ssid[i];
1027 result->name[i] = ' ';
1031 static void extract_wpaie(DBusMessageIter *value,
1032 struct supplicant_result *result)
1034 DBusMessageIter array;
1038 dbus_message_iter_recurse(value, &array);
1039 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1042 result->has_wpa = TRUE;
1045 static void extract_rsnie(DBusMessageIter *value,
1046 struct supplicant_result *result)
1048 DBusMessageIter array;
1052 dbus_message_iter_recurse(value, &array);
1053 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1056 result->has_rsn = TRUE;
1059 static void extract_wpsie(DBusMessageIter *value,
1060 struct supplicant_result *result)
1062 DBusMessageIter array;
1066 dbus_message_iter_recurse(value, &array);
1067 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
1070 result->has_wps = TRUE;
1073 static void extract_capabilites(DBusMessageIter *value,
1074 struct supplicant_result *result)
1076 dbus_message_iter_get_basic(value, &result->capabilities);
1078 if (result->capabilities & IEEE80211_CAP_ESS)
1079 result->adhoc = FALSE;
1080 else if (result->capabilities & IEEE80211_CAP_IBSS)
1081 result->adhoc = TRUE;
1083 if (result->capabilities & IEEE80211_CAP_PRIVACY)
1084 result->has_wep = TRUE;
1087 static unsigned char calculate_strength(struct supplicant_task *task,
1088 struct supplicant_result *result)
1090 if (task->range->max_qual.qual == 0) {
1091 unsigned char strength;
1093 if (result->level > 0)
1094 strength = 100 - result->level;
1096 strength = 120 + result->level;
1104 return (result->quality * 100) / task->range->max_qual.qual;
1107 static unsigned short calculate_channel(struct supplicant_result *result)
1109 if (result->frequency < 0)
1112 return (result->frequency - 2407) / 5;
1115 static void get_properties(struct supplicant_task *task);
1117 static void properties_reply(DBusPendingCall *call, void *user_data)
1119 struct supplicant_task *task = user_data;
1120 struct supplicant_result result;
1121 struct connman_network *network;
1123 DBusMessageIter array, dict;
1124 unsigned char strength;
1125 unsigned short channel, frequency;
1126 const char *mode, *security;
1128 unsigned int ssid_len;
1130 DBG("task %p", task);
1132 reply = dbus_pending_call_steal_reply(call);
1133 if (reply == NULL) {
1134 get_properties(task);
1138 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1139 dbus_message_unref(reply);
1140 get_properties(task);
1144 memset(&result, 0, sizeof(result));
1145 result.frequency = -1;
1146 result.quality = -1;
1150 dbus_message_iter_init(reply, &array);
1152 dbus_message_iter_recurse(&array, &dict);
1154 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
1155 DBusMessageIter entry, value;
1158 dbus_message_iter_recurse(&dict, &entry);
1159 dbus_message_iter_get_basic(&entry, &key);
1161 dbus_message_iter_next(&entry);
1163 dbus_message_iter_recurse(&entry, &value);
1165 //type = dbus_message_iter_get_arg_type(&value);
1166 //dbus_message_iter_get_basic(&value, &val);
1174 * frequency : i (105)
1175 * capabilities : q (113)
1182 if (g_str_equal(key, "bssid") == TRUE)
1183 extract_addr(&value, &result);
1184 else if (g_str_equal(key, "ssid") == TRUE)
1185 extract_ssid(&value, &result);
1186 else if (g_str_equal(key, "wpaie") == TRUE)
1187 extract_wpaie(&value, &result);
1188 else if (g_str_equal(key, "rsnie") == TRUE)
1189 extract_rsnie(&value, &result);
1190 else if (g_str_equal(key, "wpsie") == TRUE)
1191 extract_wpsie(&value, &result);
1192 else if (g_str_equal(key, "capabilities") == TRUE)
1193 extract_capabilites(&value, &result);
1194 else if (g_str_equal(key, "frequency") == TRUE)
1195 dbus_message_iter_get_basic(&value, &result.frequency);
1196 else if (g_str_equal(key, "quality") == TRUE)
1197 dbus_message_iter_get_basic(&value, &result.quality);
1198 else if (g_str_equal(key, "noise") == TRUE)
1199 dbus_message_iter_get_basic(&value, &result.noise);
1200 else if (g_str_equal(key, "level") == TRUE)
1201 dbus_message_iter_get_basic(&value, &result.level);
1202 else if (g_str_equal(key, "maxrate") == TRUE)
1203 dbus_message_iter_get_basic(&value, &result.maxrate);
1205 dbus_message_iter_next(&dict);
1208 if (result.path == NULL)
1211 if (result.path[0] == '\0')
1214 if (result.frequency > 0 && result.frequency < 14)
1215 result.frequency = 2407 + (5 * result.frequency);
1216 else if (result.frequency == 14)
1217 result.frequency = 2484;
1219 strength = calculate_strength(task, &result);
1220 channel = calculate_channel(&result);
1222 frequency = (result.frequency < 0) ? 0 : result.frequency;
1224 if (result.has_rsn == TRUE)
1226 else if (result.has_wpa == TRUE)
1228 else if (result.has_wep == TRUE)
1233 mode = (result.adhoc == TRUE) ? "adhoc" : "managed";
1235 group = build_group(result.path, result.name,
1236 result.ssid, result.ssid_len,
1239 network = connman_device_get_network(task->device, result.path);
1240 if (network == NULL) {
1243 network = connman_network_create(result.path,
1244 CONNMAN_NETWORK_TYPE_WIFI);
1245 if (network == NULL)
1248 index = connman_device_get_index(task->device);
1249 connman_network_set_index(network, index);
1251 connman_network_set_protocol(network,
1252 CONNMAN_NETWORK_PROTOCOL_IP);
1254 connman_network_set_address(network, result.addr,
1257 if (connman_device_add_network(task->device, network) < 0) {
1258 connman_network_unref(network);
1263 if (result.name != NULL && result.name[0] != '\0')
1264 connman_network_set_name(network, result.name);
1266 if (connman_network_get_blob(network, "WiFi.SSID", &ssid_len) == NULL) {
1267 connman_network_set_blob(network, "WiFi.SSID",
1268 result.ssid, result.ssid_len);
1271 connman_network_set_string(network, "WiFi.Mode", mode);
1273 DBG("%s (%s %s) strength %d (%s)",
1274 result.name, mode, security, strength,
1275 (result.has_wps == TRUE) ? "WPS" : "no WPS");
1277 connman_network_set_available(network, TRUE);
1278 connman_network_set_strength(network, strength);
1280 connman_network_set_uint16(network, "Frequency", frequency);
1281 connman_network_set_uint16(network, "WiFi.Channel", channel);
1282 connman_network_set_string(network, "WiFi.Security", security);
1284 connman_network_set_group(network, group);
1289 g_free(result.path);
1290 g_free(result.addr);
1291 g_free(result.name);
1292 g_free(result.ssid);
1294 dbus_message_unref(reply);
1296 get_properties(task);
1299 static void get_properties(struct supplicant_task *task)
1301 DBusMessage *message;
1302 DBusPendingCall *call;
1305 path = g_slist_nth_data(task->scan_results, 0);
1309 message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
1310 SUPPLICANT_INTF ".BSSID",
1313 task->scan_results = g_slist_remove(task->scan_results, path);
1316 if (message == NULL)
1319 if (dbus_connection_send_with_reply(connection, message,
1320 &call, TIMEOUT) == FALSE) {
1321 connman_error("Failed to get network properties");
1322 dbus_message_unref(message);
1327 connman_error("D-Bus connection not available");
1328 dbus_message_unref(message);
1332 dbus_pending_call_set_notify(call, properties_reply, task, NULL);
1334 dbus_message_unref(message);
1339 if (task->noscan == FALSE)
1340 connman_device_set_scanning(task->device, FALSE);
1343 static void scan_results_reply(DBusPendingCall *call, void *user_data)
1345 struct supplicant_task *task = user_data;
1351 DBG("task %p", task);
1353 reply = dbus_pending_call_steal_reply(call);
1357 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
1360 dbus_error_init(&error);
1362 if (dbus_message_get_args(reply, &error,
1363 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
1364 &results, &num_results,
1365 DBUS_TYPE_INVALID) == FALSE) {
1366 if (dbus_error_is_set(&error) == TRUE) {
1367 connman_error("%s", error.message);
1368 dbus_error_free(&error);
1370 connman_error("Wrong arguments for scan result");
1374 if (num_results == 0)
1377 for (i = 0; i < num_results; i++) {
1378 char *path = g_strdup(results[i]);
1382 task->scan_results = g_slist_append(task->scan_results, path);
1385 g_strfreev(results);
1387 dbus_message_unref(reply);
1389 get_properties(task);
1394 dbus_message_unref(reply);
1397 if (task->noscan == FALSE)
1398 connman_device_set_scanning(task->device, FALSE);
1401 static void scan_results_available(struct supplicant_task *task)
1403 DBusMessage *message;
1404 DBusPendingCall *call;
1406 DBG("task %p", task);
1408 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
1409 SUPPLICANT_INTF ".Interface",
1411 if (message == NULL)
1414 if (dbus_connection_send_with_reply(connection, message,
1415 &call, TIMEOUT) == FALSE) {
1416 connman_error("Failed to request scan result");
1420 if (task->noscan == FALSE)
1421 connman_device_set_scanning(task->device, TRUE);
1424 connman_error("D-Bus connection not available");
1428 dbus_pending_call_set_notify(call, scan_results_reply, task, NULL);
1431 dbus_message_unref(message);
1434 static enum supplicant_state string2state(const char *state)
1436 if (g_str_equal(state, "INACTIVE") == TRUE)
1437 return WPA_INACTIVE;
1438 else if (g_str_equal(state, "SCANNING") == TRUE)
1439 return WPA_SCANNING;
1440 else if (g_str_equal(state, "ASSOCIATING") == TRUE)
1441 return WPA_ASSOCIATING;
1442 else if (g_str_equal(state, "ASSOCIATED") == TRUE)
1443 return WPA_ASSOCIATED;
1444 else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
1445 return WPA_GROUP_HANDSHAKE;
1446 else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
1447 return WPA_4WAY_HANDSHAKE;
1448 else if (g_str_equal(state, "COMPLETED") == TRUE)
1449 return WPA_COMPLETED;
1450 else if (g_str_equal(state, "DISCONNECTED") == TRUE)
1451 return WPA_DISCONNECTED;
1456 static int task_connect(struct supplicant_task *task)
1458 const char *address, *security, *passphrase;
1460 unsigned int ssid_len;
1462 address = connman_network_get_string(task->network, "Address");
1463 security = connman_network_get_string(task->network, "WiFi.Security");
1464 passphrase = connman_network_get_string(task->network, "WiFi.Passphrase");
1466 ssid = connman_network_get_blob(task->network, "WiFi.SSID", &ssid_len);
1468 DBG("address %s security %s passphrase %s",
1469 address, security, passphrase);
1471 if (security == NULL && passphrase == NULL)
1474 if (g_str_equal(security, "none") == FALSE && passphrase == NULL)
1479 select_network(task);
1480 disable_network(task);
1482 set_network(task, ssid, ssid_len, address, security, passphrase);
1484 enable_network(task);
1489 static void state_change(struct supplicant_task *task, DBusMessage *msg)
1492 const char *newstate, *oldstate;
1493 enum supplicant_state state;
1495 dbus_error_init(&error);
1497 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &newstate,
1498 DBUS_TYPE_STRING, &oldstate,
1499 DBUS_TYPE_INVALID) == FALSE) {
1500 if (dbus_error_is_set(&error) == TRUE) {
1501 connman_error("%s", error.message);
1502 dbus_error_free(&error);
1504 connman_error("Wrong arguments for state change");
1508 DBG("state %s ==> %s", oldstate, newstate);
1510 state = string2state(newstate);
1511 if (state == WPA_INVALID)
1514 task->state = state;
1516 switch (task->state) {
1518 task->noscan = TRUE;
1519 connman_device_set_scanning(task->device, TRUE);
1521 case WPA_ASSOCIATING:
1522 case WPA_ASSOCIATED:
1523 case WPA_4WAY_HANDSHAKE:
1524 case WPA_GROUP_HANDSHAKE:
1525 task->noscan = TRUE;
1528 case WPA_DISCONNECTED:
1529 task->noscan = FALSE;
1532 task->noscan = FALSE;
1533 connman_device_set_scanning(task->device, FALSE);
1539 if (task->network == NULL)
1542 switch (task->state) {
1544 if (connman_network_get_group(task->network) == NULL) {
1545 const char *name, *mode, *security;
1546 char *group, *bssid;
1549 * This is a hidden network, we need to set its
1550 * group based on the BSSID we just joined.
1552 bssid = get_bssid(task->device);
1554 name = connman_network_get_string(task->network,
1556 mode = connman_network_get_string(task->network,
1558 security = connman_network_get_string(task->network,
1561 if (bssid && name && mode && security) {
1562 group = build_group(bssid, name, NULL, 0,
1564 connman_network_set_group(task->network, group);
1572 connman_network_set_connected(task->network, TRUE);
1573 connman_device_set_scanning(task->device, FALSE);
1576 case WPA_DISCONNECTED:
1577 if (task->disconnecting == TRUE) {
1578 connman_network_set_connected(task->network, FALSE);
1579 connman_network_unref(task->network);
1580 task->disconnecting = FALSE;
1582 if (task->pending_network != NULL) {
1583 task->network = task->pending_network;
1584 task->pending_network = NULL;
1589 connman_network_set_connected(task->network, FALSE);
1590 connman_device_set_scanning(task->device, FALSE);
1594 case WPA_ASSOCIATING:
1595 connman_network_set_associating(task->network, TRUE);
1599 connman_network_set_associating(task->network, FALSE);
1604 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
1605 DBusMessage *msg, void *data)
1607 struct supplicant_task *task;
1608 const char *member, *path;
1610 if (dbus_message_has_interface(msg,
1611 SUPPLICANT_INTF ".Interface") == FALSE)
1612 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1614 member = dbus_message_get_member(msg);
1616 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1618 path = dbus_message_get_path(msg);
1620 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1622 task = find_task_by_path(path);
1624 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1626 DBG("task %p member %s", task, member);
1628 if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
1629 scan_results_available(task);
1630 else if (g_str_equal(member, "StateChange") == TRUE)
1631 state_change(task, msg);
1633 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1636 int supplicant_start(struct connman_device *device)
1638 struct supplicant_task *task;
1641 DBG("device %p", device);
1643 task = g_try_new0(struct supplicant_task, 1);
1647 task->ifindex = connman_device_get_index(device);
1648 task->ifname = connman_inet_ifname(task->ifindex);
1650 if (task->ifname == NULL) {
1655 task->range = g_try_malloc0(sizeof(struct iw_range));
1656 if (task->range == NULL) {
1661 err = get_range(task);
1665 task->device = connman_device_ref(device);
1667 task->created = FALSE;
1668 task->noscan = FALSE;
1669 task->state = WPA_INVALID;
1670 task->disconnecting = FALSE;
1671 task->pending_network = NULL;
1673 task_list = g_slist_append(task_list, task);
1675 return create_interface(task);
1678 g_free(task->range);
1679 g_free(task->ifname);
1685 int supplicant_stop(struct connman_device *device)
1687 int index = connman_device_get_index(device);
1688 struct supplicant_task *task;
1690 DBG("device %p", device);
1692 task = find_task_by_index(index);
1696 g_free(task->range);
1698 task_list = g_slist_remove(task_list, task);
1700 disable_network(task);
1702 remove_network(task);
1704 return remove_interface(task);
1707 int supplicant_scan(struct connman_device *device)
1709 int index = connman_device_get_index(device);
1710 struct supplicant_task *task;
1713 DBG("device %p", device);
1715 task = find_task_by_index(index);
1719 switch (task->state) {
1722 case WPA_ASSOCIATING:
1723 case WPA_ASSOCIATED:
1724 case WPA_4WAY_HANDSHAKE:
1725 case WPA_GROUP_HANDSHAKE:
1731 err = initiate_scan(task);
1736 int supplicant_connect(struct connman_network *network)
1738 struct supplicant_task *task;
1741 DBG("network %p", network);
1743 index = connman_network_get_index(network);
1745 task = find_task_by_index(index);
1749 if (task->disconnecting == TRUE)
1750 task->pending_network = connman_network_ref(network);
1752 task->network = connman_network_ref(network);
1753 return task_connect(task);
1759 int supplicant_disconnect(struct connman_network *network)
1761 struct supplicant_task *task;
1764 DBG("network %p", network);
1766 index = connman_network_get_index(network);
1768 task = find_task_by_index(index);
1772 if (task->disconnecting == TRUE)
1773 return -EINPROGRESS;
1775 disable_network(task);
1777 remove_network(task);
1779 task->disconnecting = TRUE;
1784 static void supplicant_activate(DBusConnection *conn)
1786 DBusMessage *message;
1788 DBG("conn %p", conn);
1790 message = dbus_message_new_method_call(SUPPLICANT_NAME, "/",
1791 DBUS_INTERFACE_INTROSPECTABLE, "Introspect");
1792 if (message == NULL)
1795 dbus_message_set_no_reply(message, TRUE);
1797 dbus_connection_send(conn, message, NULL);
1799 dbus_message_unref(message);
1802 static GSList *driver_list = NULL;
1804 static void supplicant_probe(DBusConnection *conn, void *user_data)
1808 DBG("conn %p", conn);
1810 for (list = driver_list; list; list = list->next) {
1811 struct supplicant_driver *driver = list->data;
1813 DBG("driver %p name %s", driver, driver->name);
1820 static void supplicant_remove(DBusConnection *conn, void *user_data)
1824 DBG("conn %p", conn);
1826 for (list = driver_list; list; list = list->next) {
1827 struct supplicant_driver *driver = list->data;
1829 DBG("driver %p name %s", driver, driver->name);
1836 static const char *supplicant_rule = "type=signal,"
1837 "interface=" SUPPLICANT_INTF ".Interface";
1840 static int supplicant_create(void)
1842 if (g_slist_length(driver_list) > 0)
1845 connection = connman_dbus_get_connection();
1846 if (connection == NULL)
1849 DBG("connection %p", connection);
1851 if (dbus_connection_add_filter(connection,
1852 supplicant_filter, NULL, NULL) == FALSE) {
1853 connection = connman_dbus_get_connection();
1857 dbus_bus_add_match(connection, supplicant_rule, NULL);
1858 dbus_connection_flush(connection);
1860 watch = g_dbus_add_service_watch(connection, SUPPLICANT_NAME,
1861 supplicant_probe, supplicant_remove, NULL, NULL);
1866 static void supplicant_destroy(void)
1868 if (g_slist_length(driver_list) > 0)
1871 DBG("connection %p", connection);
1874 g_dbus_remove_watch(connection, watch);
1876 dbus_bus_remove_match(connection, supplicant_rule, NULL);
1877 dbus_connection_flush(connection);
1879 dbus_connection_remove_filter(connection, supplicant_filter, NULL);
1881 dbus_connection_unref(connection);
1885 int supplicant_register(struct supplicant_driver *driver)
1889 DBG("driver %p name %s", driver, driver->name);
1891 err = supplicant_create();
1895 driver_list = g_slist_append(driver_list, driver);
1897 if (g_dbus_check_service(connection, SUPPLICANT_NAME) == TRUE)
1898 supplicant_probe(connection, NULL);
1900 supplicant_activate(connection);
1905 void supplicant_unregister(struct supplicant_driver *driver)
1907 DBG("driver %p name %s", driver, driver->name);
1909 supplicant_remove(connection, NULL);
1911 driver_list = g_slist_remove(driver_list, driver);
1913 supplicant_destroy();