mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-21 11:52:34 +01:00
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.
This commit is contained in:
parent
b93ae37325
commit
31a0e42772
61
src/device.c
61
src/device.c
@ -28,7 +28,12 @@
|
||||
|
||||
#include <ell/ell.h>
|
||||
|
||||
#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,
|
||||
|
196
src/netdev.c
196
src/netdev.c
@ -34,7 +34,12 @@
|
||||
#include <ell/ell.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
143
src/wiphy.c
143
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;
|
||||
|
Loading…
Reference in New Issue
Block a user