From 31a0e4277297f57097d69bc9f09ce7393b58b78a Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 15 Jun 2016 10:54:13 -0500 Subject: [PATCH] wiphy: Move association logic out of wiphy.c The eapol state machine parameters are now built inside device.c when the network connection is attempted. The reason is that the device object knows about network settings, wiphy constraints and should contain the main 'management' logic. netdev now manages the actual low-level process of building association messages, detecting authentication events, etc. --- src/device.c | 61 +++++++++++++++- src/netdev.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/wiphy.c | 143 ------------------------------------- 3 files changed, 255 insertions(+), 145 deletions(-) diff --git a/src/device.c b/src/device.c index cc2c9ab6..9d431318 100644 --- a/src/device.c +++ b/src/device.c @@ -28,7 +28,12 @@ #include +#include "src/iwd.h" #include "src/common.h" +#include "src/ie.h" +#include "src/eapol.h" +#include "src/wiphy.h" +#include "src/scan.h" #include "src/netdev.h" #include "src/dbus.h" #include "src/network.h" @@ -217,11 +222,65 @@ void device_connect_network(struct device *device, struct network *network, struct scan_bss *bss, struct l_dbus_message *message) { + enum security security = network_get_security(network); + struct wiphy *wiphy = device->wiphy; struct l_dbus *dbus = dbus_get_bus(); + struct eapol_sm *sm = NULL; + + if (security == SECURITY_PSK || security == SECURITY_8021X) { + uint16_t pairwise_ciphers, group_ciphers; + uint8_t rsne_buf[256]; + struct ie_rsn_info info; + + sm = eapol_sm_new(); + + eapol_sm_set_authenticator_address(sm, bss->addr); + eapol_sm_set_supplicant_address(sm, + netdev_get_address(device->netdev)); + + memset(&info, 0, sizeof(info)); + + if (security == SECURITY_PSK) + info.akm_suites = + bss->sha256 ? IE_RSN_AKM_SUITE_PSK_SHA256 : + IE_RSN_AKM_SUITE_PSK; + else + info.akm_suites = + bss->sha256 ? IE_RSN_AKM_SUITE_8021X_SHA256 : + IE_RSN_AKM_SUITE_8021X; + + bss_get_supported_ciphers(bss, + &pairwise_ciphers, &group_ciphers); + + info.pairwise_ciphers = wiphy_select_cipher(wiphy, + pairwise_ciphers); + info.group_cipher = wiphy_select_cipher(wiphy, group_ciphers); + + /* RSN takes priority */ + if (bss->rsne) { + ie_build_rsne(&info, rsne_buf); + eapol_sm_set_ap_rsn(sm, bss->rsne, bss->rsne[1] + 2); + eapol_sm_set_own_rsn(sm, rsne_buf, rsne_buf[1] + 2); + } else { + ie_build_wpa(&info, rsne_buf); + eapol_sm_set_ap_wpa(sm, bss->wpa, bss->wpa[1] + 2); + eapol_sm_set_own_wpa(sm, rsne_buf, rsne_buf[1] + 2); + } + + if (security == SECURITY_PSK) + eapol_sm_set_pmk(sm, network_get_psk(network)); + else + eapol_sm_set_8021x_config(sm, + network_get_settings(network)); + + eapol_sm_set_user_data(sm, device); + eapol_sm_set_tx_user_data(sm, + L_INT_TO_PTR(l_io_get_fd(device->eapol_io))); + } device->connect_pending = l_dbus_message_ref(message); - if (netdev_connect(device->netdev, bss, NULL, + if (netdev_connect(device->netdev, bss, sm, device_netdev_event, device_connect_cb, device) < 0) { dbus_pending_reply(&device->connect_pending, diff --git a/src/netdev.c b/src/netdev.c index b77b20c1..81b773db 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -34,7 +34,12 @@ #include #include "linux/nl80211.h" + +#include "src/iwd.h" #include "src/wiphy.h" +#include "src/ie.h" +#include "src/eapol.h" +#include "src/crypto.h" #include "src/device.h" #include "src/scan.h" #include "src/netdev.h" @@ -48,6 +53,8 @@ struct netdev { netdev_event_func_t event_filter; netdev_connect_cb_t connect_cb; void *user_data; + struct l_genl_msg *associate_msg; + struct eapol_sm *sm; }; static struct l_netlink *rtnl = NULL; @@ -151,6 +158,17 @@ static void netdev_free(void *data) struct netdev *netdev = data; l_debug("Freeing netdev %s[%d]", netdev->name, netdev->index); + + if (netdev->sm) { + eapol_sm_free(netdev->sm); + netdev->sm = NULL; + } + + if (netdev->associate_msg) { + l_genl_msg_unref(netdev->associate_msg); + netdev->associate_msg = NULL; + } + l_free(netdev); } @@ -167,6 +185,126 @@ struct netdev *netdev_find(int ifindex) return l_queue_find(netdev_list, netdev_match, L_UINT_TO_PTR(ifindex)); } +static void netdev_cmd_associate_cb(struct l_genl_msg *msg, void *user_data) +{ + struct netdev *netdev = user_data; + + /* Wait for associate event */ + if (l_genl_msg_get_error(msg) >= 0) { + if (netdev->event_filter) + netdev->event_filter(netdev, + NETDEV_EVENT_ASSOCIATING, + netdev->user_data); + + if (netdev->sm) { + eapol_start(netdev->index, netdev->sm); + netdev->sm = NULL; + } + + return; + } + + if (netdev->connect_cb) + netdev->connect_cb(netdev, NETDEV_RESULT_ASSOCIATION_FAILED, + netdev->user_data); +} + +static struct l_genl_msg *netdev_build_cmd_associate(struct netdev *netdev, + struct scan_bss *bss, + struct eapol_sm *sm) +{ + struct l_genl_msg *msg; + + msg = l_genl_msg_new_sized(NL80211_CMD_ASSOCIATE, 512); + l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index); + l_genl_msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, + 4, &bss->frequency); + l_genl_msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, bss->addr); + l_genl_msg_append_attr(msg, NL80211_ATTR_SSID, + bss->ssid_len, bss->ssid); + + if (sm) { + uint32_t cipher; + uint32_t nl_cipher; + size_t ie_len; + const uint8_t *ie; + + cipher = eapol_sm_get_pairwise_cipher(sm); + if (cipher == IE_RSN_CIPHER_SUITE_CCMP) + nl_cipher = CRYPTO_CIPHER_CCMP; + else + nl_cipher = CRYPTO_CIPHER_TKIP; + + l_genl_msg_append_attr(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, + 4, &nl_cipher); + + cipher = eapol_sm_get_group_cipher(sm); + if (cipher == IE_RSN_CIPHER_SUITE_CCMP) + nl_cipher = CRYPTO_CIPHER_CCMP; + else + nl_cipher = CRYPTO_CIPHER_TKIP; + + l_genl_msg_append_attr(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, + 4, &nl_cipher); + + l_genl_msg_append_attr(msg, NL80211_ATTR_CONTROL_PORT, 0, NULL); + + ie = eapol_sm_get_own_ie(sm, &ie_len); + if (ie) + l_genl_msg_append_attr(msg, NL80211_ATTR_IE, + ie_len, ie); + } + + return msg; +} + +static void netdev_authenticate_event(struct l_genl_msg *msg, + struct netdev *netdev) +{ + struct l_genl_attr attr; + uint16_t type, len; + const void *data; + int err; + + l_debug(""); + + err = l_genl_msg_get_error(msg); + if (err < 0) { + l_error("authentication failed %s (%d)", strerror(-err), err); + goto error; + } + + if (!l_genl_attr_init(&attr, msg)) { + l_debug("attr init failed"); + goto error; + } + + while (l_genl_attr_next(&attr, &type, &len, &data)) { + switch (type) { + case NL80211_ATTR_TIMED_OUT: + l_warn("authentication timed out"); + goto error; + } + } + + if (!netdev->associate_msg) + return; + + if (l_genl_family_send(nl80211, netdev->associate_msg, + netdev_cmd_associate_cb, netdev, NULL) > 0) { + netdev->associate_msg = NULL; + return; + } + + l_genl_msg_unref(netdev->associate_msg); + netdev->associate_msg = NULL; + +error: + if (netdev->connect_cb) + netdev->connect_cb(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED, + netdev->user_data); +} + static void netdev_cmd_authenticate_cb(struct l_genl_msg *msg, void *user_data) { struct netdev *netdev = user_data; @@ -209,18 +347,30 @@ int netdev_connect(struct netdev *netdev, struct scan_bss *bss, netdev_connect_cb_t cb, void *user_data) { struct l_genl_msg *authenticate; + struct l_genl_msg *associate; authenticate = netdev_build_cmd_authenticate(netdev, bss); if (!authenticate) return -EINVAL; + associate = netdev_build_cmd_associate(netdev, bss, sm); + if (!associate) { + l_genl_msg_unref(authenticate); + return -EINVAL; + } + if (!l_genl_family_send(nl80211, authenticate, - netdev_cmd_authenticate_cb, netdev, NULL)) + netdev_cmd_authenticate_cb, netdev, NULL)) { + l_genl_msg_unref(associate); + l_genl_msg_unref(authenticate); return -EIO; + } netdev->event_filter = event_filter; netdev->connect_cb = cb; netdev->user_data = user_data; + netdev->sm = sm; + netdev->associate_msg = associate; return 0; } @@ -231,6 +381,46 @@ int netdev_disconnect(struct netdev *netdev, return 0; } +static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data) +{ + struct netdev *netdev = NULL; + struct l_genl_attr attr; + uint16_t type, len; + const void *data; + uint8_t cmd; + + cmd = l_genl_msg_get_command(msg); + + l_debug("MLME notification %u", cmd); + + if (!l_genl_attr_init(&attr, msg)) + return; + + while (l_genl_attr_next(&attr, &type, &len, &data)) { + switch (type) { + case NL80211_ATTR_IFINDEX: + if (len != sizeof(uint32_t)) { + l_warn("Invalid interface index attribute"); + return; + } + + netdev = netdev_find(*((uint32_t *) data)); + break; + } + } + + if (!netdev) { + l_warn("MLME notification is missing ifindex attribute"); + return; + } + + switch (cmd) { + case NL80211_CMD_AUTHENTICATE: + netdev_authenticate_event(msg, netdev); + break; + } +} + static void netdev_get_interface_callback(struct l_genl_msg *msg, void *user_data) { @@ -411,6 +601,10 @@ bool netdev_init(struct l_genl_family *in) NULL, NULL)) l_error("Getting all interface information failed"); + if (!l_genl_family_register(nl80211, "mlme", netdev_mlme_notify, + NULL, NULL)) + l_error("Registering for MLME notification failed"); + return true; } diff --git a/src/wiphy.c b/src/wiphy.c index 1262cf6d..b098216d 100644 --- a/src/wiphy.c +++ b/src/wiphy.c @@ -836,146 +836,6 @@ static void mlme_associate_event(struct l_genl_msg *msg, struct device *device) operstate_cb, device); } -static void genl_associate_cb(struct l_genl_msg *msg, void *user_data) -{ - struct device *device = user_data; - - if (l_genl_msg_get_error(msg) < 0 && device->connect_pending) - dbus_pending_reply(&device->connect_pending, - dbus_error_failed(device->connect_pending)); -} - -static void mlme_associate_cmd(struct device *device) -{ - struct l_genl_msg *msg; - struct scan_bss *bss = device->connected_bss; - struct network *network = device->connected_network; - struct wiphy *wiphy = device->wiphy; - const char *ssid = network_get_ssid(network); - enum security security = network_get_security(network); - - l_debug(""); - - msg = l_genl_msg_new_sized(NL80211_CMD_ASSOCIATE, 512); - msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &device->index); - msg_append_attr(msg, NL80211_ATTR_WIPHY_FREQ, 4, &bss->frequency); - msg_append_attr(msg, NL80211_ATTR_MAC, ETH_ALEN, bss->addr); - msg_append_attr(msg, NL80211_ATTR_SSID, strlen(ssid), ssid); - - if (security == SECURITY_PSK || security == SECURITY_8021X) { - uint16_t pairwise_ciphers, group_ciphers; - uint32_t pairwise_cipher_attr; - uint32_t group_cipher_attr; - uint8_t rsne_buf[256]; - struct ie_rsn_info info; - struct eapol_sm *sm = eapol_sm_new(); - - memset(&info, 0, sizeof(info)); - - if (security == SECURITY_PSK) - info.akm_suites = - bss->sha256 ? IE_RSN_AKM_SUITE_PSK_SHA256 : - IE_RSN_AKM_SUITE_PSK; - else - info.akm_suites = - bss->sha256 ? IE_RSN_AKM_SUITE_8021X_SHA256 : - IE_RSN_AKM_SUITE_8021X; - - bss_get_supported_ciphers(bss, &pairwise_ciphers, - &group_ciphers); - - info.pairwise_ciphers = wiphy_select_cipher(wiphy, - pairwise_ciphers); - if (info.pairwise_ciphers == IE_RSN_CIPHER_SUITE_CCMP) - pairwise_cipher_attr = CRYPTO_CIPHER_CCMP; - else - pairwise_cipher_attr = CRYPTO_CIPHER_TKIP; - - info.group_cipher = wiphy_select_cipher(wiphy, group_ciphers); - if (info.group_cipher == IE_RSN_CIPHER_SUITE_CCMP) - group_cipher_attr = CRYPTO_CIPHER_CCMP; - else - group_cipher_attr = CRYPTO_CIPHER_TKIP; - - /* RSN takes priority */ - if (bss->rsne) { - ie_build_rsne(&info, rsne_buf); - eapol_sm_set_ap_rsn(sm, bss->rsne, bss->rsne[1] + 2); - eapol_sm_set_own_rsn(sm, rsne_buf, rsne_buf[1] + 2); - } else { - ie_build_wpa(&info, rsne_buf); - eapol_sm_set_ap_wpa(sm, bss->wpa, bss->wpa[1] + 2); - eapol_sm_set_own_wpa(sm, rsne_buf, rsne_buf[1] + 2); - } - - if (security == SECURITY_PSK) - eapol_sm_set_pmk(sm, network_get_psk(network)); - else - eapol_sm_set_8021x_config(sm, - network_get_settings(network)); - - eapol_sm_set_authenticator_address(sm, bss->addr); - eapol_sm_set_supplicant_address(sm, - netdev_get_address(device->netdev)); - eapol_sm_set_user_data(sm, device); - eapol_sm_set_tx_user_data(sm, - L_INT_TO_PTR(l_io_get_fd(device->eapol_io))); - eapol_start(device->index, sm); - - msg_append_attr(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, - 4, &pairwise_cipher_attr); - msg_append_attr(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, - 4, &group_cipher_attr); - - msg_append_attr(msg, NL80211_ATTR_CONTROL_PORT, 0, NULL); - msg_append_attr(msg, NL80211_ATTR_IE, - rsne_buf[1] + 2, rsne_buf); - } - - l_genl_family_send(nl80211, msg, genl_associate_cb, device, NULL); -} - -static void mlme_authenticate_event(struct l_genl_msg *msg, - struct device *device) -{ - struct l_genl_attr attr; - uint16_t type, len; - const void *data; - int err; - - l_debug(""); - - err = l_genl_msg_get_error(msg); - if (err < 0) { - l_error("authentication failed %s (%d)", strerror(-err), err); - goto error; - } - - if (!l_genl_attr_init(&attr, msg)) { - l_debug("attr init failed"); - goto error; - } - - while (l_genl_attr_next(&attr, &type, &len, &data)) { - switch (type) { - case NL80211_ATTR_TIMED_OUT: - l_warn("authentication timed out"); - goto error; - } - } - - l_info("Authentication completed"); - mlme_associate_cmd(device); - return; - -error: - if (device->connect_pending) - dbus_pending_reply(&device->connect_pending, - dbus_error_failed(device->connect_pending)); - - device_disassociated(device); -} - static void mlme_deauthenticate_event(struct l_genl_msg *msg, struct device *device) { @@ -1670,9 +1530,6 @@ static void wiphy_mlme_notify(struct l_genl_msg *msg, void *user_data) switch (cmd) { - case NL80211_CMD_AUTHENTICATE: - mlme_authenticate_event(msg, device); - break; case NL80211_CMD_ASSOCIATE: mlme_associate_event(msg, device); break;