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 // COMPLETED ==> ASSOCIATING
55 // ASSOCIATED ==> DISCONNECTED
56 // DISCONNECTED ==> INACTIVE
58 // DISCONNECTED ==> SCANNING
59 // SCANNING ==> ASSOCIATED
61 // ASSOCIATING ==> ASSOCIATED
62 // ASSOCIATED ==> 4WAY_HANDSHAKE
63 // 4WAY_HANDSHAKE ==> GROUP_HANDSHAKE
64 // GROUP_HANDSHAKE ==> COMPLETED
66 struct supplicant_task {
70 struct connman_iface *iface;
74 enum supplicant_state state;
77 static GSList *tasks = NULL;
79 struct supplicant_ap {
88 #define IEEE80211_CAP_ESS 0x0001
89 #define IEEE80211_CAP_IBSS 0x0002
90 #define IEEE80211_CAP_PRIVACY 0x0010
92 static struct supplicant_task *find_task(int ifindex)
96 for (list = tasks; list; list = list->next) {
97 struct supplicant_task *task = list->data;
99 if (task->ifindex == ifindex)
106 static int get_interface(struct supplicant_task *task)
108 DBusMessage *message, *reply;
112 DBG("task %p", task);
114 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
115 SUPPLICANT_INTF, "getInterface");
119 dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
122 dbus_error_init(&error);
124 reply = dbus_connection_send_with_reply_and_block(task->conn,
125 message, -1, &error);
127 if (dbus_error_is_set(&error) == TRUE) {
128 connman_error("%s", error.message);
129 dbus_error_free(&error);
131 connman_error("Failed to get interface");
132 dbus_message_unref(message);
136 dbus_message_unref(message);
138 dbus_error_init(&error);
140 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
141 DBUS_TYPE_INVALID) == FALSE) {
142 if (dbus_error_is_set(&error) == TRUE) {
143 connman_error("%s", error.message);
144 dbus_error_free(&error);
146 connman_error("Wrong arguments for interface");
147 dbus_message_unref(reply);
151 DBG("path %s", path);
153 task->path = g_strdup(path);
154 task->created = FALSE;
156 dbus_message_unref(reply);
161 static int add_interface(struct supplicant_task *task)
163 DBusMessage *message, *reply;
167 DBG("task %p", task);
169 message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
170 SUPPLICANT_INTF, "addInterface");
174 dbus_error_init(&error);
176 dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
179 reply = dbus_connection_send_with_reply_and_block(task->conn,
180 message, -1, &error);
182 if (dbus_error_is_set(&error) == TRUE) {
183 connman_error("%s", error.message);
184 dbus_error_free(&error);
186 connman_error("Failed to add interface");
187 dbus_message_unref(message);
191 dbus_message_unref(message);
193 dbus_error_init(&error);
195 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
196 DBUS_TYPE_INVALID) == FALSE) {
197 if (dbus_error_is_set(&error) == TRUE) {
198 connman_error("%s", error.message);
199 dbus_error_free(&error);
201 connman_error("Wrong arguments for interface");
202 dbus_message_unref(reply);
206 DBG("path %s", path);
208 task->path = g_strdup(path);
209 task->created = TRUE;
211 dbus_message_unref(reply);
216 static int add_network(struct supplicant_task *task)
218 DBusMessage *message, *reply;
222 DBG("task %p", task);
224 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
225 SUPPLICANT_INTF ".Interface", "addNetwork");
229 dbus_error_init(&error);
231 reply = dbus_connection_send_with_reply_and_block(task->conn,
232 message, -1, &error);
234 if (dbus_error_is_set(&error) == TRUE) {
235 connman_error("%s", error.message);
236 dbus_error_free(&error);
238 connman_error("Failed to add network");
239 dbus_message_unref(message);
243 dbus_message_unref(message);
245 dbus_error_init(&error);
247 if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
248 DBUS_TYPE_INVALID) == FALSE) {
249 if (dbus_error_is_set(&error) == TRUE) {
250 connman_error("%s", error.message);
251 dbus_error_free(&error);
253 connman_error("Wrong arguments for network");
254 dbus_message_unref(reply);
258 DBG("path %s", path);
260 task->network = g_strdup(path);
262 dbus_message_unref(reply);
267 static int remove_network(struct supplicant_task *task)
269 DBusMessage *message, *reply;
272 DBG("task %p", task);
274 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
275 SUPPLICANT_INTF ".Interface", "removeNetwork");
279 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
282 dbus_error_init(&error);
284 reply = dbus_connection_send_with_reply_and_block(task->conn,
285 message, -1, &error);
287 if (dbus_error_is_set(&error) == TRUE) {
288 connman_error("%s", error.message);
289 dbus_error_free(&error);
291 connman_error("Failed to remove network");
292 dbus_message_unref(message);
296 dbus_message_unref(message);
298 dbus_message_unref(reply);
303 static int select_network(struct supplicant_task *task)
305 DBusMessage *message, *reply;
308 DBG("task %p", task);
310 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
311 SUPPLICANT_INTF ".Interface", "selectNetwork");
315 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
318 dbus_error_init(&error);
320 reply = dbus_connection_send_with_reply_and_block(task->conn,
321 message, -1, &error);
323 if (dbus_error_is_set(&error) == TRUE) {
324 connman_error("%s", error.message);
325 dbus_error_free(&error);
327 connman_error("Failed to select network");
328 dbus_message_unref(message);
332 dbus_message_unref(message);
334 dbus_message_unref(reply);
339 static int enable_network(struct supplicant_task *task)
341 DBusMessage *message, *reply;
344 DBG("task %p", task);
346 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
347 SUPPLICANT_INTF ".Network", "enable");
351 dbus_error_init(&error);
353 reply = dbus_connection_send_with_reply_and_block(task->conn,
354 message, -1, &error);
356 if (dbus_error_is_set(&error) == TRUE) {
357 connman_error("%s", error.message);
358 dbus_error_free(&error);
360 connman_error("Failed to enable network");
361 dbus_message_unref(message);
365 dbus_message_unref(message);
367 dbus_message_unref(reply);
372 static int disable_network(struct supplicant_task *task)
374 DBusMessage *message, *reply;
377 DBG("task %p", task);
379 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
380 SUPPLICANT_INTF ".Network", "disable");
384 dbus_error_init(&error);
386 reply = dbus_connection_send_with_reply_and_block(task->conn,
387 message, -1, &error);
389 if (dbus_error_is_set(&error) == TRUE) {
390 connman_error("%s", error.message);
391 dbus_error_free(&error);
393 connman_error("Failed to disable network");
394 dbus_message_unref(message);
398 dbus_message_unref(message);
400 dbus_message_unref(reply);
405 static void append_entry(DBusMessageIter *dict,
406 const char *key, int type, void *val)
408 DBusMessageIter entry, value;
409 const char *signature;
411 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
414 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
417 case DBUS_TYPE_STRING:
418 signature = DBUS_TYPE_STRING_AS_STRING;
420 case DBUS_TYPE_UINT16:
421 signature = DBUS_TYPE_UINT16_AS_STRING;
424 signature = DBUS_TYPE_VARIANT_AS_STRING;
428 dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
430 dbus_message_iter_append_basic(&value, type, val);
431 dbus_message_iter_close_container(&entry, &value);
433 dbus_message_iter_close_container(dict, &entry);
436 static int set_network(struct supplicant_task *task, const char *network,
437 const char *passphrase)
439 DBusMessage *message, *reply;
440 DBusMessageIter array, dict;
443 DBG("task %p", task);
445 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
446 SUPPLICANT_INTF ".Network", "set");
450 dbus_message_iter_init_append(message, &array);
452 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
453 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
454 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
455 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
457 append_entry(&dict, "ssid", DBUS_TYPE_STRING, &network);
459 if (passphrase && strlen(passphrase) > 0) {
460 //exec_cmd(task, "SET_NETWORK 0 proto RSN WPA");
461 //exec_cmd(task, "SET_NETWORK 0 key_mgmt WPA-PSK");
463 append_entry(&dict, "psk", DBUS_TYPE_STRING, &passphrase);
465 //exec_cmd(task, "SET_NETWORK 0 proto RSN WPA");
466 //exec_cmd(task, "SET_NETWORK 0 key_mgmt NONE");
469 dbus_message_iter_close_container(&array, &dict);
471 dbus_error_init(&error);
473 reply = dbus_connection_send_with_reply_and_block(task->conn,
474 message, -1, &error);
476 if (dbus_error_is_set(&error) == TRUE) {
477 connman_error("%s", error.message);
478 dbus_error_free(&error);
480 connman_error("Failed to set network options");
481 dbus_message_unref(message);
485 dbus_message_unref(message);
487 dbus_message_unref(reply);
492 static int initiate_scan(struct supplicant_task *task)
494 DBusMessage *message, *reply;
497 DBG("task %p", task);
499 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
500 SUPPLICANT_INTF ".Interface", "scan");
504 dbus_error_init(&error);
506 reply = dbus_connection_send_with_reply_and_block(task->conn,
507 message, -1, &error);
509 if (dbus_error_is_set(&error) == TRUE) {
510 connman_error("%s", error.message);
511 dbus_error_free(&error);
513 connman_error("Failed to initiate scan");
514 dbus_message_unref(message);
518 dbus_message_unref(message);
520 dbus_message_unref(reply);
525 static void extract_ssid(struct supplicant_ap *ap, DBusMessageIter *value)
527 DBusMessageIter array;
531 dbus_message_iter_recurse(value, &array);
532 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
534 ap->identifier = g_strdup((char *) ssid);
537 static void extract_wpaie(struct supplicant_ap *ap, DBusMessageIter *value)
539 DBusMessageIter array;
543 dbus_message_iter_recurse(value, &array);
544 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
550 static void extract_rsnie(struct supplicant_ap *ap, DBusMessageIter *value)
552 DBusMessageIter array;
556 dbus_message_iter_recurse(value, &array);
557 dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
563 static void extract_capabilites(struct supplicant_ap *ap,
564 DBusMessageIter *value)
568 dbus_message_iter_get_basic(value, &capabilities);
570 ap->capabilities = capabilities;
572 if (capabilities & IEEE80211_CAP_PRIVACY)
576 static int parse_network_properties(struct supplicant_task *task,
577 DBusMessage *message)
579 DBusMessageIter array, dict;
580 struct supplicant_ap *ap;
583 DBG("task %p", task);
585 ap = g_try_new0(struct supplicant_ap, 1);
589 dbus_message_iter_init(message, &array);
591 dbus_message_iter_recurse(&array, &dict);
593 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
594 DBusMessageIter entry, value;
597 dbus_message_iter_recurse(&dict, &entry);
598 dbus_message_iter_get_basic(&entry, &key);
600 dbus_message_iter_next(&entry);
602 dbus_message_iter_recurse(&entry, &value);
604 //type = dbus_message_iter_get_arg_type(&value);
605 //dbus_message_iter_get_basic(&value, &val);
607 if (g_str_equal(key, "ssid") == TRUE)
608 extract_ssid(ap, &value);
609 else if (g_str_equal(key, "wpaie") == TRUE)
610 extract_wpaie(ap, &value);
611 else if (g_str_equal(key, "rsnie") == TRUE)
612 extract_rsnie(ap, &value);
613 else if (g_str_equal(key, "capabilities") == TRUE)
614 extract_capabilites(ap, &value);
616 dbus_message_iter_next(&dict);
619 DBG("SSID %s", ap->identifier);
628 connman_iface_indicate_station(task->iface,
629 ap->identifier, 25, security);
636 static int get_network_properties(struct supplicant_task *task,
639 DBusMessage *message, *reply;
642 DBG("task %p", task);
644 message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
645 SUPPLICANT_INTF ".BSSID",
650 dbus_error_init(&error);
652 reply = dbus_connection_send_with_reply_and_block(task->conn,
653 message, -1, &error);
655 if (dbus_error_is_set(&error) == TRUE) {
656 connman_error("%s", error.message);
657 dbus_error_free(&error);
659 connman_error("Failed to get network properties");
660 dbus_message_unref(message);
664 dbus_message_unref(message);
666 parse_network_properties(task, reply);
668 dbus_message_unref(reply);
673 static int scan_results_available(struct supplicant_task *task)
675 DBusMessage *message, *reply;
680 DBG("task %p", task);
682 message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
683 SUPPLICANT_INTF ".Interface",
688 dbus_error_init(&error);
690 reply = dbus_connection_send_with_reply_and_block(task->conn,
691 message, -1, &error);
693 if (dbus_error_is_set(&error) == TRUE) {
694 connman_error("%s", error.message);
695 dbus_error_free(&error);
697 connman_error("Failed to request scan result");
698 dbus_message_unref(message);
702 dbus_message_unref(message);
704 dbus_error_init(&error);
706 if (dbus_message_get_args(reply, &error,
707 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
708 &results, &num_results,
709 DBUS_TYPE_INVALID) == FALSE) {
710 if (dbus_error_is_set(&error) == TRUE) {
711 connman_error("%s", error.message);
712 dbus_error_free(&error);
714 connman_error("Wrong arguments for scan result");
715 dbus_message_unref(reply);
719 for (i = 0; i < num_results; i++)
720 get_network_properties(task, results[i]);
724 dbus_message_unref(reply);
729 static void state_change(struct supplicant_task *task, DBusMessage *msg)
732 const char *state, *previous;
734 dbus_error_init(&error);
736 if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &state,
737 DBUS_TYPE_STRING, &previous,
738 DBUS_TYPE_INVALID) == FALSE) {
739 if (dbus_error_is_set(&error) == TRUE) {
740 connman_error("%s", error.message);
741 dbus_error_free(&error);
743 connman_error("Wrong arguments for state change");
747 DBG("state %s ==> %s", previous, state);
749 if (g_str_equal(state, "INACTIVE") == TRUE)
750 task->state = STATE_INACTIVE;
751 else if (g_str_equal(state, "SCANNING") == TRUE)
752 task->state = STATE_SCANNING;
753 else if (g_str_equal(state, "ASSOCIATING") == TRUE)
754 task->state = STATE_ASSOCIATING;
755 else if (g_str_equal(state, "ASSOCIATED") == TRUE)
756 task->state = STATE_ASSOCIATED;
757 else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
758 task->state = STATE_4WAY_HANDSHAKE;
759 else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
760 task->state = STATE_4WAY_HANDSHAKE;
761 else if (g_str_equal(state, "COMPLETED") == TRUE)
762 task->state = STATE_COMPLETED;
763 else if (g_str_equal(state, "DISCONNECTED") == TRUE)
764 task->state = STATE_DISCONNECTED;
767 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
768 DBusMessage *msg, void *data)
770 struct supplicant_task *task = data;
773 if (dbus_message_has_interface(msg,
774 SUPPLICANT_INTF ".Interface") == FALSE)
775 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
777 member = dbus_message_get_member(msg);
779 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
781 DBG("task %p member %s", task, member);
783 if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
784 scan_results_available(task);
785 else if (g_str_equal(member, "StateChange") == TRUE)
786 state_change(task, msg);
788 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
791 static int add_filter(struct supplicant_task *task)
796 if (dbus_connection_add_filter(task->conn,
797 supplicant_filter, task, NULL) == FALSE)
800 filter = g_strdup_printf("type=signal,interface=%s.Interface,path=%s",
801 SUPPLICANT_INTF, task->path);
803 DBG("filter %s", filter);
805 dbus_error_init(&error);
807 dbus_bus_add_match(task->conn, filter, &error);
811 if (dbus_error_is_set(&error) == TRUE) {
812 connman_error("Can't add match: %s", error.message);
813 dbus_error_free(&error);
819 int __supplicant_start(struct connman_iface *iface)
822 struct supplicant_task *task;
825 sk = socket(PF_INET, SOCK_DGRAM, 0);
829 memset(&ifr, 0, sizeof(ifr));
830 ifr.ifr_ifindex = iface->index;
832 err = ioctl(sk, SIOCGIFNAME, &ifr);
839 DBG("interface %s", ifr.ifr_name);
841 task = g_try_new0(struct supplicant_task, 1);
845 task->ifindex = iface->index;
846 task->ifname = g_strdup(ifr.ifr_name);
849 if (task->ifname == NULL) {
854 task->conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
855 if (task->conn == NULL) {
860 task->created = FALSE;
862 err = get_interface(task);
864 err = add_interface(task);
871 task->state = STATE_INACTIVE;
873 tasks = g_slist_append(tasks, task);
879 select_network(task);
880 disable_network(task);
885 int __supplicant_stop(struct connman_iface *iface)
887 struct supplicant_task *task;
889 task = find_task(iface->index);
893 DBG("interface %s", task->ifname);
895 tasks = g_slist_remove(tasks, task);
897 remove_network(task);
899 dbus_connection_unref(task->conn);
901 g_free(task->ifname);
902 g_free(task->network);
909 int __supplicant_scan(struct connman_iface *iface)
911 struct supplicant_task *task;
914 task = find_task(iface->index);
918 DBG("interface %s", task->ifname);
920 switch (task->state) {
923 case STATE_ASSOCIATING:
924 case STATE_ASSOCIATED:
925 case STATE_4WAY_HANDSHAKE:
926 case STATE_GROUP_HANDSHAKE:
932 err = initiate_scan(task);
937 int __supplicant_connect(struct connman_iface *iface,
938 const char *network, const char *passphrase)
940 struct supplicant_task *task;
942 task = find_task(iface->index);
946 DBG("interface %s", task->ifname);
948 set_network(task, network, passphrase);
950 enable_network(task);
955 int __supplicant_disconnect(struct connman_iface *iface)
957 struct supplicant_task *task;
959 task = find_task(iface->index);
963 DBG("interface %s", task->ifname);
965 disable_network(task);