5 * Copyright (C) 2007 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>
36 #include <dbus/dbus.h>
39 #include <connman/log.h>
41 #include "supplicant.h"
43 enum supplicant_state {
49 STATE_GROUP_HANDSHAKE,
54 struct supplicant_task {
58 struct connman_iface *iface;
62 enum supplicant_state state;
65 static GSList *tasks = NULL;
67 struct supplicant_ap {
76 #define IEEE80211_CAP_ESS 0x0001
77 #define IEEE80211_CAP_IBSS 0x0002
78 #define IEEE80211_CAP_PRIVACY 0x0010
80 static struct supplicant_task *find_task(int ifindex)
84 for (list = tasks; list; list = list->next) {
85 struct supplicant_task *task = list->data;
87 if (task->ifindex == ifindex)
94 static int get_interface(struct supplicant_task *task)
96 DBusMessage *message, *reply;
100 DBG("task %p", task);
102 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
103 SUPPLICANT_INTF, "getInterface");
107 dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
110 dbus_error_init(&error);
112 reply = dbus_connection_send_with_reply_and_block(task->conn,
113 message, -1, &error);
115 if (dbus_error_is_set(&error) == TRUE) {
116 connman_error("%s", error.message);
117 dbus_error_free(&error);
119 connman_error("Failed to get interface");
120 dbus_message_unref(message);
124 dbus_message_unref(message);
126 dbus_error_init(&error);
128 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
129 DBUS_TYPE_INVALID) == FALSE) {
130 if (dbus_error_is_set(&error) == TRUE) {
131 connman_error("%s", error.message);
132 dbus_error_free(&error);
134 connman_error("Wrong arguments for interface");
135 dbus_message_unref(reply);
139 DBG("path %s", path);
141 task->path = g_strdup(path);
142 task->created = FALSE;
144 dbus_message_unref(reply);
149 static int add_interface(struct supplicant_task *task)
151 DBusMessage *message, *reply;
155 DBG("task %p", task);
157 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
158 SUPPLICANT_INTF, "addInterface");
162 dbus_error_init(&error);
164 dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
167 reply = dbus_connection_send_with_reply_and_block(task->conn,
168 message, -1, &error);
170 if (dbus_error_is_set(&error) == TRUE) {
171 connman_error("%s", error.message);
172 dbus_error_free(&error);
174 connman_error("Failed to add interface");
175 dbus_message_unref(message);
179 dbus_message_unref(message);
181 dbus_error_init(&error);
183 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
184 DBUS_TYPE_INVALID) == FALSE) {
185 if (dbus_error_is_set(&error) == TRUE) {
186 connman_error("%s", error.message);
187 dbus_error_free(&error);
189 connman_error("Wrong arguments for interface");
190 dbus_message_unref(reply);
194 DBG("path %s", path);
196 task->path = g_strdup(path);
197 task->created = TRUE;
199 dbus_message_unref(reply);
204 static int remove_interface(struct supplicant_task *task)
206 DBusMessage *message, *reply;
209 DBG("task %p", task);
211 if (task->created == FALSE)
214 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
215 SUPPLICANT_INTF, "removeInterface");
219 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->path,
222 dbus_error_init(&error);
224 reply = dbus_connection_send_with_reply_and_block(task->conn,
225 message, -1, &error);
227 if (dbus_error_is_set(&error) == TRUE) {
228 connman_error("%s", error.message);
229 dbus_error_free(&error);
231 connman_error("Failed to remove interface");
232 dbus_message_unref(message);
236 dbus_message_unref(message);
238 dbus_message_unref(reply);
243 static int set_ap_scan(struct supplicant_task *task)
245 DBusMessage *message, *reply;
249 DBG("task %p", task);
251 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
252 SUPPLICANT_INTF ".Interface", "setAPScan");
256 dbus_message_append_args(message, DBUS_TYPE_UINT32, &ap_scan,
259 dbus_error_init(&error);
261 reply = dbus_connection_send_with_reply_and_block(task->conn,
262 message, -1, &error);
264 if (dbus_error_is_set(&error) == TRUE) {
265 connman_error("%s", error.message);
266 dbus_error_free(&error);
268 connman_error("Failed to set AP scan");
269 dbus_message_unref(message);
273 dbus_message_unref(message);
275 dbus_message_unref(reply);
280 static int add_network(struct supplicant_task *task)
282 DBusMessage *message, *reply;
286 DBG("task %p", task);
288 if (task->network != NULL)
291 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
292 SUPPLICANT_INTF ".Interface", "addNetwork");
296 dbus_error_init(&error);
298 reply = dbus_connection_send_with_reply_and_block(task->conn,
299 message, -1, &error);
301 if (dbus_error_is_set(&error) == TRUE) {
302 connman_error("%s", error.message);
303 dbus_error_free(&error);
305 connman_error("Failed to add network");
306 dbus_message_unref(message);
310 dbus_message_unref(message);
312 dbus_error_init(&error);
314 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
315 DBUS_TYPE_INVALID) == FALSE) {
316 if (dbus_error_is_set(&error) == TRUE) {
317 connman_error("%s", error.message);
318 dbus_error_free(&error);
320 connman_error("Wrong arguments for network");
321 dbus_message_unref(reply);
325 DBG("path %s", path);
327 task->network = g_strdup(path);
329 dbus_message_unref(reply);
334 static int remove_network(struct supplicant_task *task)
336 DBusMessage *message, *reply;
339 DBG("task %p", task);
341 if (task->network == NULL)
344 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
345 SUPPLICANT_INTF ".Interface", "removeNetwork");
349 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
352 dbus_error_init(&error);
354 reply = dbus_connection_send_with_reply_and_block(task->conn,
355 message, -1, &error);
357 if (dbus_error_is_set(&error) == TRUE) {
358 connman_error("%s", error.message);
359 dbus_error_free(&error);
361 connman_error("Failed to remove network");
362 dbus_message_unref(message);
366 dbus_message_unref(message);
368 dbus_message_unref(reply);
370 g_free(task->network);
371 task->network = NULL;
376 static int select_network(struct supplicant_task *task)
378 DBusMessage *message, *reply;
381 DBG("task %p", task);
383 if (task->network == NULL)
386 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
387 SUPPLICANT_INTF ".Interface", "selectNetwork");
391 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
394 dbus_error_init(&error);
396 reply = dbus_connection_send_with_reply_and_block(task->conn,
397 message, -1, &error);
399 if (dbus_error_is_set(&error) == TRUE) {
400 connman_error("%s", error.message);
401 dbus_error_free(&error);
403 connman_error("Failed to select network");
404 dbus_message_unref(message);
408 dbus_message_unref(message);
410 dbus_message_unref(reply);
415 static int enable_network(struct supplicant_task *task)
417 DBusMessage *message, *reply;
420 DBG("task %p", task);
422 if (task->network == NULL)
425 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
426 SUPPLICANT_INTF ".Network", "enable");
430 dbus_error_init(&error);
432 reply = dbus_connection_send_with_reply_and_block(task->conn,
433 message, -1, &error);
435 if (dbus_error_is_set(&error) == TRUE) {
436 connman_error("%s", error.message);
437 dbus_error_free(&error);
439 connman_error("Failed to enable network");
440 dbus_message_unref(message);
444 dbus_message_unref(message);
446 dbus_message_unref(reply);
451 static int disable_network(struct supplicant_task *task)
453 DBusMessage *message, *reply;
456 DBG("task %p", task);
458 if (task->network == NULL)
461 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
462 SUPPLICANT_INTF ".Network", "disable");
466 dbus_error_init(&error);
468 reply = dbus_connection_send_with_reply_and_block(task->conn,
469 message, -1, &error);
471 if (dbus_error_is_set(&error) == TRUE) {
472 connman_error("%s", error.message);
473 dbus_error_free(&error);
475 connman_error("Failed to disable network");
476 dbus_message_unref(message);
480 dbus_message_unref(message);
482 dbus_message_unref(reply);
487 static void append_entry(DBusMessageIter *dict,
488 const char *key, int type, void *val)
490 DBusMessageIter entry, value;
491 const char *signature;
493 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
496 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
499 case DBUS_TYPE_STRING:
500 signature = DBUS_TYPE_STRING_AS_STRING;
502 case DBUS_TYPE_UINT16:
503 signature = DBUS_TYPE_UINT16_AS_STRING;
506 signature = DBUS_TYPE_VARIANT_AS_STRING;
510 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
512 dbus_message_iter_append_basic(&value, type, val);
513 dbus_message_iter_close_container(&entry, &value);
515 dbus_message_iter_close_container(dict, &entry);
518 static int set_network(struct supplicant_task *task, const char *network,
519 const char *passphrase)
521 DBusMessage *message, *reply;
522 DBusMessageIter array, dict;
525 DBG("task %p", task);
527 if (task->network == NULL)
530 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
531 SUPPLICANT_INTF ".Network", "set");
535 dbus_message_iter_init_append(message, &array);
537 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
538 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
539 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
540 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
542 append_entry(&dict, "ssid", DBUS_TYPE_STRING, &network);
544 if (passphrase && strlen(passphrase) > 0) {
545 const char *key_mgmt = "WPA-PSK";
546 append_entry(&dict, "key_mgmt", DBUS_TYPE_STRING, &key_mgmt);
547 append_entry(&dict, "psk", DBUS_TYPE_STRING, &passphrase);
549 const char *key_mgmt = "NONE";
550 append_entry(&dict, "key_mgmt", DBUS_TYPE_STRING, &key_mgmt);
553 dbus_message_iter_close_container(&array, &dict);
555 dbus_error_init(&error);
557 reply = dbus_connection_send_with_reply_and_block(task->conn,
558 message, -1, &error);
560 if (dbus_error_is_set(&error) == TRUE) {
561 connman_error("%s", error.message);
562 dbus_error_free(&error);
564 connman_error("Failed to set network options");
565 dbus_message_unref(message);
569 dbus_message_unref(message);
571 dbus_message_unref(reply);
576 static int initiate_scan(struct supplicant_task *task)
578 DBusMessage *message, *reply;
581 DBG("task %p", task);
583 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
584 SUPPLICANT_INTF ".Interface", "scan");
588 dbus_error_init(&error);
590 reply = dbus_connection_send_with_reply_and_block(task->conn,
591 message, -1, &error);
593 if (dbus_error_is_set(&error) == TRUE) {
594 connman_error("%s", error.message);
595 dbus_error_free(&error);
597 connman_error("Failed to initiate scan");
598 dbus_message_unref(message);
602 dbus_message_unref(message);
604 dbus_message_unref(reply);
609 static void extract_ssid(struct supplicant_ap *ap, DBusMessageIter *value)
611 DBusMessageIter array;
615 dbus_message_iter_recurse(value, &array);
616 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
618 ap->identifier = g_strdup((char *) ssid);
621 static void extract_wpaie(struct supplicant_ap *ap, DBusMessageIter *value)
623 DBusMessageIter array;
627 dbus_message_iter_recurse(value, &array);
628 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
634 static void extract_rsnie(struct supplicant_ap *ap, DBusMessageIter *value)
636 DBusMessageIter array;
640 dbus_message_iter_recurse(value, &array);
641 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
647 static void extract_capabilites(struct supplicant_ap *ap,
648 DBusMessageIter *value)
652 dbus_message_iter_get_basic(value, &capabilities);
654 ap->capabilities = capabilities;
656 if (capabilities & IEEE80211_CAP_PRIVACY)
660 static int parse_network_properties(struct supplicant_task *task,
661 DBusMessage *message)
663 DBusMessageIter array, dict;
664 struct supplicant_ap *ap;
667 ap = g_try_new0(struct supplicant_ap, 1);
671 dbus_message_iter_init(message, &array);
673 dbus_message_iter_recurse(&array, &dict);
675 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
676 DBusMessageIter entry, value;
679 dbus_message_iter_recurse(&dict, &entry);
680 dbus_message_iter_get_basic(&entry, &key);
682 dbus_message_iter_next(&entry);
684 dbus_message_iter_recurse(&entry, &value);
686 //type = dbus_message_iter_get_arg_type(&value);
687 //dbus_message_iter_get_basic(&value, &val);
689 if (g_str_equal(key, "ssid") == TRUE)
690 extract_ssid(ap, &value);
691 else if (g_str_equal(key, "wpaie") == TRUE)
692 extract_wpaie(ap, &value);
693 else if (g_str_equal(key, "rsnie") == TRUE)
694 extract_rsnie(ap, &value);
695 else if (g_str_equal(key, "capabilities") == TRUE)
696 extract_capabilites(ap, &value);
698 dbus_message_iter_next(&dict);
708 connman_iface_indicate_station(task->iface,
709 ap->identifier, 25, security);
716 static int get_network_properties(struct supplicant_task *task,
719 DBusMessage *message, *reply;
722 message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
723 SUPPLICANT_INTF ".BSSID",
728 dbus_error_init(&error);
730 reply = dbus_connection_send_with_reply_and_block(task->conn,
731 message, -1, &error);
733 if (dbus_error_is_set(&error) == TRUE) {
734 connman_error("%s", error.message);
735 dbus_error_free(&error);
737 connman_error("Failed to get network properties");
738 dbus_message_unref(message);
742 dbus_message_unref(message);
744 parse_network_properties(task, reply);
746 dbus_message_unref(reply);
751 static int scan_results_available(struct supplicant_task *task)
753 DBusMessage *message, *reply;
758 DBG("task %p", task);
760 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
761 SUPPLICANT_INTF ".Interface",
766 dbus_error_init(&error);
768 reply = dbus_connection_send_with_reply_and_block(task->conn,
769 message, -1, &error);
771 if (dbus_error_is_set(&error) == TRUE) {
772 connman_error("%s", error.message);
773 dbus_error_free(&error);
775 connman_error("Failed to request scan result");
776 dbus_message_unref(message);
780 dbus_message_unref(message);
782 dbus_error_init(&error);
784 if (dbus_message_get_args(reply, &error,
785 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
786 &results, &num_results,
787 DBUS_TYPE_INVALID) == FALSE) {
788 if (dbus_error_is_set(&error) == TRUE) {
789 connman_error("%s", error.message);
790 dbus_error_free(&error);
792 connman_error("Wrong arguments for scan result");
793 dbus_message_unref(reply);
797 for (i = 0; i < num_results; i++)
798 get_network_properties(task, results[i]);
802 dbus_message_unref(reply);
807 static void state_change(struct supplicant_task *task, DBusMessage *msg)
810 const char *state, *previous;
812 dbus_error_init(&error);
814 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &state,
815 DBUS_TYPE_STRING, &previous,
816 DBUS_TYPE_INVALID) == FALSE) {
817 if (dbus_error_is_set(&error) == TRUE) {
818 connman_error("%s", error.message);
819 dbus_error_free(&error);
821 connman_error("Wrong arguments for state change");
825 DBG("state %s ==> %s", previous, state);
827 if (g_str_equal(state, "INACTIVE") == TRUE)
828 task->state = STATE_INACTIVE;
829 else if (g_str_equal(state, "SCANNING") == TRUE)
830 task->state = STATE_SCANNING;
831 else if (g_str_equal(state, "ASSOCIATING") == TRUE)
832 task->state = STATE_ASSOCIATING;
833 else if (g_str_equal(state, "ASSOCIATED") == TRUE)
834 task->state = STATE_ASSOCIATED;
835 else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
836 task->state = STATE_4WAY_HANDSHAKE;
837 else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
838 task->state = STATE_4WAY_HANDSHAKE;
839 else if (g_str_equal(state, "COMPLETED") == TRUE)
840 task->state = STATE_COMPLETED;
841 else if (g_str_equal(state, "DISCONNECTED") == TRUE)
842 task->state = STATE_DISCONNECTED;
844 switch (task->state) {
845 case STATE_COMPLETED:
846 connman_iface_indicate_carrier_on(task->iface);
848 case STATE_DISCONNECTED:
849 connman_iface_indicate_carrier_off(task->iface);
856 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
857 DBusMessage *msg, void *data)
859 struct supplicant_task *task = data;
862 if (dbus_message_has_interface(msg,
863 SUPPLICANT_INTF ".Interface") == FALSE)
864 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
866 member = dbus_message_get_member(msg);
868 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
870 DBG("task %p member %s", task, member);
872 if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
873 scan_results_available(task);
874 else if (g_str_equal(member, "StateChange") == TRUE)
875 state_change(task, msg);
877 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
880 static int add_filter(struct supplicant_task *task)
885 if (dbus_connection_add_filter(task->conn,
886 supplicant_filter, task, NULL) == FALSE)
889 filter = g_strdup_printf("type=signal,interface=%s.Interface,path=%s",
890 SUPPLICANT_INTF, task->path);
892 DBG("filter %s", filter);
894 dbus_error_init(&error);
896 dbus_bus_add_match(task->conn, filter, &error);
900 if (dbus_error_is_set(&error) == TRUE) {
901 connman_error("Can't add match: %s", error.message);
902 dbus_error_free(&error);
908 static int remove_filter(struct supplicant_task *task)
913 filter = g_strdup_printf("type=signal,interface=%s.Interface,path=%s",
914 SUPPLICANT_INTF, task->path);
916 DBG("filter %s", filter);
918 dbus_error_init(&error);
920 dbus_bus_add_match(task->conn, filter, &error);
924 if (dbus_error_is_set(&error) == TRUE) {
925 connman_error("Can't add match: %s", error.message);
926 dbus_error_free(&error);
929 dbus_connection_remove_filter(task->conn, supplicant_filter, task);
934 int __supplicant_start(struct connman_iface *iface)
937 struct supplicant_task *task;
940 sk = socket(PF_INET, SOCK_DGRAM, 0);
944 memset(&ifr, 0, sizeof(ifr));
945 ifr.ifr_ifindex = iface->index;
947 err = ioctl(sk, SIOCGIFNAME, &ifr);
954 DBG("interface %s", ifr.ifr_name);
956 task = g_try_new0(struct supplicant_task, 1);
960 task->ifindex = iface->index;
961 task->ifname = g_strdup(ifr.ifr_name);
964 if (task->ifname == NULL) {
969 task->conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
970 if (task->conn == NULL) {
975 task->created = FALSE;
977 err = get_interface(task);
979 err = add_interface(task);
986 task->state = STATE_INACTIVE;
988 tasks = g_slist_append(tasks, task);
997 int __supplicant_stop(struct connman_iface *iface)
999 struct supplicant_task *task;
1001 task = find_task(iface->index);
1005 DBG("interface %s", task->ifname);
1007 tasks = g_slist_remove(tasks, task);
1009 disable_network(task);
1011 remove_network(task);
1013 remove_filter(task);
1015 remove_interface(task);
1017 dbus_connection_unref(task->conn);
1019 g_free(task->ifname);
1026 int __supplicant_scan(struct connman_iface *iface)
1028 struct supplicant_task *task;
1031 task = find_task(iface->index);
1035 DBG("interface %s", task->ifname);
1037 switch (task->state) {
1038 case STATE_SCANNING:
1040 case STATE_ASSOCIATING:
1041 case STATE_ASSOCIATED:
1042 case STATE_4WAY_HANDSHAKE:
1043 case STATE_GROUP_HANDSHAKE:
1049 err = initiate_scan(task);
1054 int __supplicant_connect(struct connman_iface *iface,
1055 const char *network, const char *passphrase)
1057 struct supplicant_task *task;
1059 task = find_task(iface->index);
1063 DBG("interface %s", task->ifname);
1067 select_network(task);
1068 disable_network(task);
1070 set_network(task, network, passphrase);
1072 enable_network(task);
1077 int __supplicant_disconnect(struct connman_iface *iface)
1079 struct supplicant_task *task;
1081 task = find_task(iface->index);
1085 DBG("interface %s", task->ifname);
1087 disable_network(task);
1089 remove_network(task);