mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-22 21:22:37 +01:00
netdev: Scan & Retry CMD_AUTHENTICATE
Handle situations where the BSS we're trying to connect to is no longer in the kernel scan result cache. Normally, the kernel will re-scan the target frequency if this happens on the CMD_CONNECT path, and retry the connection. Unfortunately, CMD_AUTHENTICATE path used for WPA3, OWE and FILS does not have this scanning behavior. CMD_AUTHENTICATE simply fails with a -ENOENT error. Work around this by trying a limited scan of the target frequency and re-trying CMD_AUTHENTICATE once.
This commit is contained in:
parent
a8768e354d
commit
fb217479d2
112
src/netdev.c
112
src/netdev.c
@ -143,6 +143,7 @@ struct netdev {
|
|||||||
struct l_io *pae_io; /* for drivers without EAPoL over NL80211 */
|
struct l_io *pae_io; /* for drivers without EAPoL over NL80211 */
|
||||||
|
|
||||||
struct l_genl_msg *connect_cmd;
|
struct l_genl_msg *connect_cmd;
|
||||||
|
struct l_genl_msg *auth_cmd;
|
||||||
struct wiphy_radio_work_item work;
|
struct wiphy_radio_work_item work;
|
||||||
|
|
||||||
bool connected : 1;
|
bool connected : 1;
|
||||||
@ -157,6 +158,7 @@ struct netdev {
|
|||||||
bool expect_connect_failure : 1;
|
bool expect_connect_failure : 1;
|
||||||
bool aborting : 1;
|
bool aborting : 1;
|
||||||
bool events_ready : 1;
|
bool events_ready : 1;
|
||||||
|
bool retry_auth : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netdev_preauth_state {
|
struct netdev_preauth_state {
|
||||||
@ -2335,18 +2337,73 @@ static struct l_genl_msg *netdev_build_cmd_authenticate(struct netdev *netdev,
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netdev_auth_cb(struct l_genl_msg *msg, void *user_data)
|
static void netdev_scan_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
{
|
{
|
||||||
struct netdev *netdev = user_data;
|
struct netdev *netdev = user_data;
|
||||||
|
|
||||||
if (l_genl_msg_get_error(msg) < 0) {
|
if (l_genl_msg_get_error(msg) < 0) {
|
||||||
l_error("Error sending CMD_AUTHENTICATE");
|
|
||||||
|
|
||||||
netdev_connect_failed(netdev,
|
netdev_connect_failed(netdev,
|
||||||
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
||||||
MMPDU_STATUS_CODE_UNSPECIFIED);
|
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev->retry_auth = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netdev_auth_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
|
{
|
||||||
|
struct netdev *netdev = user_data;
|
||||||
|
struct handshake_state *hs = netdev->handshake;
|
||||||
|
int err = l_genl_msg_get_error(msg);
|
||||||
|
struct l_genl_msg *scan_msg;
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
l_genl_msg_unref(netdev->auth_cmd);
|
||||||
|
netdev->auth_cmd = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l_debug("Error during auth: %d", err);
|
||||||
|
|
||||||
|
if (!netdev->auth_cmd || err != -ENOENT) {
|
||||||
|
netdev_connect_failed(netdev,
|
||||||
|
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
||||||
|
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kernel can't find the BSS in its cache, scan and retry */
|
||||||
|
scan_msg = scan_build_trigger_scan_bss(netdev->index, netdev->wiphy,
|
||||||
|
netdev->frequency,
|
||||||
|
hs->ssid, hs->ssid_len);
|
||||||
|
|
||||||
|
if (!l_genl_family_send(nl80211, scan_msg,
|
||||||
|
netdev_scan_cb, netdev, NULL)) {
|
||||||
|
l_genl_msg_unref(scan_msg);
|
||||||
|
netdev_connect_failed(netdev,
|
||||||
|
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
||||||
|
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netdev_new_scan_results_event(struct l_genl_msg *msg,
|
||||||
|
struct netdev *netdev)
|
||||||
|
{
|
||||||
|
if (!netdev->retry_auth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
l_debug("");
|
||||||
|
|
||||||
|
if (!l_genl_family_send(nl80211, netdev->auth_cmd,
|
||||||
|
netdev_auth_cb, netdev, NULL)) {
|
||||||
|
netdev_connect_failed(netdev,
|
||||||
|
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
||||||
|
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
netdev->auth_cmd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netdev_assoc_cb(struct l_genl_msg *msg, void *user_data)
|
static void netdev_assoc_cb(struct l_genl_msg *msg, void *user_data)
|
||||||
@ -2368,7 +2425,6 @@ static void netdev_sae_tx_authenticate(const uint8_t *body,
|
|||||||
struct l_genl_msg *msg;
|
struct l_genl_msg *msg;
|
||||||
|
|
||||||
msg = netdev_build_cmd_authenticate(netdev, NL80211_AUTHTYPE_SAE);
|
msg = netdev_build_cmd_authenticate(netdev, NL80211_AUTHTYPE_SAE);
|
||||||
|
|
||||||
l_genl_msg_append_attr(msg, NL80211_ATTR_AUTH_DATA, body_len, body);
|
l_genl_msg_append_attr(msg, NL80211_ATTR_AUTH_DATA, body_len, body);
|
||||||
|
|
||||||
if (!l_genl_family_send(nl80211, msg, netdev_auth_cb, netdev, NULL)) {
|
if (!l_genl_family_send(nl80211, msg, netdev_auth_cb, netdev, NULL)) {
|
||||||
@ -2376,7 +2432,10 @@ static void netdev_sae_tx_authenticate(const uint8_t *body,
|
|||||||
netdev_connect_failed(netdev,
|
netdev_connect_failed(netdev,
|
||||||
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
||||||
MMPDU_STATUS_CODE_UNSPECIFIED);
|
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev->auth_cmd = l_genl_msg_ref(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netdev_sae_tx_associate(void *user_data)
|
static void netdev_sae_tx_associate(void *user_data)
|
||||||
@ -2421,7 +2480,10 @@ static void netdev_owe_tx_authenticate(void *user_data)
|
|||||||
netdev_connect_failed(netdev,
|
netdev_connect_failed(netdev,
|
||||||
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
||||||
MMPDU_STATUS_CODE_UNSPECIFIED);
|
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev->auth_cmd = l_genl_msg_ref(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netdev_owe_tx_associate(struct iovec *ie_iov, size_t iov_len,
|
static void netdev_owe_tx_associate(struct iovec *ie_iov, size_t iov_len,
|
||||||
@ -2459,7 +2521,10 @@ static void netdev_fils_tx_authenticate(const uint8_t *body,
|
|||||||
netdev_connect_failed(netdev,
|
netdev_connect_failed(netdev,
|
||||||
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
NETDEV_RESULT_AUTHENTICATION_FAILED,
|
||||||
MMPDU_STATUS_CODE_UNSPECIFIED);
|
MMPDU_STATUS_CODE_UNSPECIFIED);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev->auth_cmd = l_genl_msg_ref(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netdev_fils_tx_associate(struct iovec *iov, size_t iov_len,
|
static void netdev_fils_tx_associate(struct iovec *iov, size_t iov_len,
|
||||||
@ -2821,6 +2886,8 @@ static bool netdev_connection_work_ready(struct wiphy_radio_work_item *item)
|
|||||||
{
|
{
|
||||||
struct netdev *netdev = l_container_of(item, struct netdev, work);
|
struct netdev *netdev = l_container_of(item, struct netdev, work);
|
||||||
|
|
||||||
|
netdev->retry_auth = false;
|
||||||
|
|
||||||
if (mac_per_ssid) {
|
if (mac_per_ssid) {
|
||||||
int ret = netdev_start_powered_mac_change(netdev);
|
int ret = netdev_start_powered_mac_change(netdev);
|
||||||
|
|
||||||
@ -2842,8 +2909,21 @@ failed:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void netdev_connection_work_destroy(struct wiphy_radio_work_item *item)
|
||||||
|
{
|
||||||
|
struct netdev *netdev = l_container_of(item, struct netdev, work);
|
||||||
|
|
||||||
|
if (netdev->auth_cmd) {
|
||||||
|
l_genl_msg_unref(netdev->auth_cmd);
|
||||||
|
netdev->auth_cmd = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
netdev->retry_auth = false;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct wiphy_radio_work_item_ops connect_work_ops = {
|
static const struct wiphy_radio_work_item_ops connect_work_ops = {
|
||||||
.do_work = netdev_connection_work_ready,
|
.do_work = netdev_connection_work_ready,
|
||||||
|
.destroy = netdev_connection_work_destroy,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int netdev_connect_common(struct netdev *netdev,
|
static int netdev_connect_common(struct netdev *netdev,
|
||||||
@ -3805,6 +3885,26 @@ static void netdev_station_event(struct l_genl_msg *msg,
|
|||||||
netdev_station_watch_func_t, netdev, mac, added);
|
netdev_station_watch_func_t, netdev, mac, added);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void netdev_scan_notify(struct l_genl_msg *msg, void *user_data)
|
||||||
|
{
|
||||||
|
struct netdev *netdev = NULL;
|
||||||
|
uint32_t ifindex;
|
||||||
|
|
||||||
|
if (nl80211_parse_attrs(msg, NL80211_ATTR_IFINDEX, &ifindex,
|
||||||
|
NL80211_ATTR_UNSPEC) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
netdev = netdev_find(ifindex);
|
||||||
|
if (!netdev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (l_genl_msg_get_command(msg)) {
|
||||||
|
case NL80211_CMD_NEW_SCAN_RESULTS:
|
||||||
|
netdev_new_scan_results_event(msg, netdev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
|
static void netdev_mlme_notify(struct l_genl_msg *msg, void *user_data)
|
||||||
{
|
{
|
||||||
struct netdev *netdev = NULL;
|
struct netdev *netdev = NULL;
|
||||||
@ -5106,6 +5206,10 @@ static int netdev_init(void)
|
|||||||
NULL, NULL))
|
NULL, NULL))
|
||||||
l_error("Registering for MLME notification failed");
|
l_error("Registering for MLME notification failed");
|
||||||
|
|
||||||
|
if (!l_genl_family_register(nl80211, "scan", netdev_scan_notify,
|
||||||
|
NULL, NULL))
|
||||||
|
l_error("Registering for scan notifications failed");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_netlink:
|
fail_netlink:
|
||||||
|
29
src/scan.c
29
src/scan.c
@ -436,6 +436,35 @@ done:
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct l_genl_msg *scan_build_trigger_scan_bss(uint32_t ifindex,
|
||||||
|
struct wiphy *wiphy,
|
||||||
|
uint32_t frequency,
|
||||||
|
const uint8_t *ssid,
|
||||||
|
uint32_t ssid_len)
|
||||||
|
{
|
||||||
|
struct l_genl_msg *msg = l_genl_msg_new(NL80211_CMD_TRIGGER_SCAN);
|
||||||
|
uint32_t flags = 0;
|
||||||
|
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &ifindex);
|
||||||
|
|
||||||
|
l_genl_msg_enter_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES);
|
||||||
|
l_genl_msg_append_attr(msg, 0, 4, &frequency);
|
||||||
|
l_genl_msg_leave_nested(msg);
|
||||||
|
|
||||||
|
if (wiphy_has_ext_feature(wiphy, NL80211_EXT_FEATURE_SCAN_RANDOM_SN))
|
||||||
|
flags |= NL80211_SCAN_FLAG_RANDOM_SN;
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
l_genl_msg_append_attr(msg, NL80211_ATTR_SCAN_FLAGS, 4, &flags);
|
||||||
|
|
||||||
|
/* direct probe request scan */
|
||||||
|
l_genl_msg_enter_nested(msg, NL80211_ATTR_SCAN_SSIDS);
|
||||||
|
l_genl_msg_append_attr(msg, 0, ssid_len, ssid);
|
||||||
|
l_genl_msg_leave_nested(msg);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
struct scan_cmds_add_data {
|
struct scan_cmds_add_data {
|
||||||
struct scan_context *sc;
|
struct scan_context *sc;
|
||||||
const struct scan_parameters *params;
|
const struct scan_parameters *params;
|
||||||
|
@ -26,6 +26,7 @@ struct p2p_probe_resp;
|
|||||||
struct p2p_probe_req;
|
struct p2p_probe_req;
|
||||||
struct p2p_beacon;
|
struct p2p_beacon;
|
||||||
struct mmpdu_header;
|
struct mmpdu_header;
|
||||||
|
struct wiphy;
|
||||||
|
|
||||||
enum scan_band {
|
enum scan_band {
|
||||||
SCAN_BAND_2_4_GHZ = 0x1,
|
SCAN_BAND_2_4_GHZ = 0x1,
|
||||||
@ -120,6 +121,12 @@ static inline bool scan_bss_addr_eq(const struct scan_bss *a1,
|
|||||||
return !memcmp(a1->addr, a2->addr, sizeof(a1->addr));
|
return !memcmp(a1->addr, a2->addr, sizeof(a1->addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct l_genl_msg *scan_build_trigger_scan_bss(uint32_t ifindex,
|
||||||
|
struct wiphy *wiphy,
|
||||||
|
uint32_t frequency,
|
||||||
|
const uint8_t *ssid,
|
||||||
|
uint32_t ssid_len);
|
||||||
|
|
||||||
uint32_t scan_passive(uint64_t wdev_id, struct scan_freq_set *freqs,
|
uint32_t scan_passive(uint64_t wdev_id, struct scan_freq_set *freqs,
|
||||||
scan_trigger_func_t trigger, scan_notify_func_t notify,
|
scan_trigger_func_t trigger, scan_notify_func_t notify,
|
||||||
void *userdata, scan_destroy_func_t destroy);
|
void *userdata, scan_destroy_func_t destroy);
|
||||||
|
Loading…
Reference in New Issue
Block a user