This adds connection/FT attempts to the radio work queue. This
will ensure that connections aren't delayed or done concurrently
with scanning.
---
src/netdev.c | 86 ++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 66 insertions(+), 20 deletions(-)
diff --git a/src/netdev.c b/src/netdev.c
index e469fb1c..a7f92ff8 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -136,6 +136,9 @@ struct netdev {
struct l_io *pae_io; /* for drivers without EAPoL over NL80211 */
+ struct l_genl_msg *connect_cmd;
+ struct wiphy_radio_work_item work;
+
bool connected : 1;
bool operational : 1;
bool rekey_offload_support : 1;
@@ -485,6 +488,9 @@ static void netdev_preauth_destroy(void *data)
static void netdev_connect_free(struct netdev *netdev)
{
+ if (netdev->work.id)
+ wiphy_radio_work_done(netdev->wiphy, netdev->work.id);
+
if (netdev->sm) {
eapol_sm_free(netdev->sm);
netdev->sm = NULL;
@@ -529,6 +535,7 @@ static void netdev_connect_free(struct netdev *netdev)
netdev->in_ft = false;
netdev->ignore_connect_event = false;
netdev->expect_connect_failure = false;
+ netdev->connect_cmd = NULL;
netdev_rssi_polling_update(netdev);
@@ -625,12 +632,12 @@ static void netdev_free(void *data)
netdev->mac_change_cmd_id = 0;
}
+ scan_wdev_remove(netdev->wdev_id);
+
if (netdev->events_ready)
WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
netdev, NETDEV_WATCH_EVENT_DEL);
- scan_wdev_remove(netdev->wdev_id);
-
watchlist_destroy(&netdev->station_watches);
l_io_destroy(netdev->pae_io);
@@ -1019,6 +1026,9 @@ static void netdev_connect_ok(struct netdev *netdev)
}
netdev_rssi_polling_update(netdev);
+
+ if (netdev->work.id)
+ wiphy_radio_work_done(netdev->wiphy, netdev->work.id);
}
static void netdev_setting_keys_failed(struct netdev_handshake_state *nhs,
@@ -1487,6 +1497,9 @@ void netdev_handshake_failed(struct handshake_state *hs, uint16_t
reason_code)
if (!l_genl_family_send(nl80211, msg, NULL, NULL, NULL))
l_error("error sending DEL_STATION");
}
+
+ if (netdev->work.id)
+ wiphy_radio_work_done(netdev->wiphy, netdev->work.id);
}
static void hardware_rekey_cb(struct l_genl_msg *msg, void *data)
@@ -2426,25 +2439,60 @@ struct rtnl_data {
int ref;
};
-static int netdev_begin_connection(struct netdev *netdev,
- struct l_genl_msg *cmd_connect)
+static bool netdev_connection_ready(struct wiphy_radio_work_item *item)
{
- if (cmd_connect) {
+ struct netdev *netdev = l_container_of(item, struct netdev, work);
+
+ if (netdev->connect_cmd) {
netdev->connect_cmd_id = l_genl_family_send(nl80211,
- cmd_connect, netdev_cmd_connect_cb,
- netdev, NULL);
+ netdev->connect_cmd,
+ netdev_cmd_connect_cb, netdev, NULL);
if (!netdev->connect_cmd_id) {
- l_genl_msg_unref(cmd_connect);
- return -EIO;
+ l_genl_msg_unref(netdev->connect_cmd);
+ netdev->connect_cmd = NULL;
+
+ netdev_connect_failed(netdev, NETDEV_RESULT_ABORTED,
+ MMPDU_STATUS_CODE_UNSPECIFIED);
+ return true;
}
+
+ netdev->connect_cmd = NULL;
}
- handshake_state_set_supplicant_address(netdev->handshake, netdev->addr);
+ if (netdev->ap) {
+ if (!auth_proto_start(netdev->ap)) {
+ /* Restore original nonce if this was an FT attempt */
+ if (netdev->in_ft)
+ memcpy(netdev->handshake->snonce,
+ netdev->prev_snonce, 32);
+
+ netdev_connect_failed(netdev, NETDEV_RESULT_ABORTED,
+ MMPDU_STATUS_CODE_UNSPECIFIED);
+ return true;
+ }
+ /*
+ * set connected since the auth protocols cannot do
+ * so internally
+ */
- /* set connected since the auth protocols cannot do so internally */
- if (netdev->ap && auth_proto_start(netdev->ap))
netdev->connected = true;
+ }
+
+ return false;
+}
+
+static const struct wiphy_radio_work_item_ops connect_work_ops = {
+ .do_work = netdev_connection_ready,
+};
+
+static int netdev_begin_connection(struct netdev *netdev,
+ struct l_genl_msg *cmd_connect)
+{
+ netdev->connect_cmd = cmd_connect;
+
+ wiphy_radio_work_insert(netdev->wiphy, &netdev->work, 1,
+ &connect_work_ops);
return 0;
}
@@ -2514,6 +2562,8 @@ static void netdev_mac_power_up_cb(int error, uint16_t type,
return;
}
+ handshake_state_set_supplicant_address(netdev->handshake, netdev->addr);
+
/*
* Pick up where we left off in netdev_connect_commmon.
*/
@@ -2649,6 +2699,8 @@ static int netdev_connect_common(struct netdev *netdev,
return ret;
}
+ handshake_state_set_supplicant_address(netdev->handshake, netdev->addr);
+
return netdev_begin_connection(netdev, cmd_connect);
}
@@ -3092,7 +3144,6 @@ static int fast_transition(struct netdev *netdev, struct scan_bss
*target_bss,
netdev_connect_cb_t cb)
{
struct netdev_handshake_state *nhs;
- int err = -EINVAL;
if (!netdev->operational)
return -ENOTCONN;
@@ -3173,15 +3224,10 @@ static int fast_transition(struct netdev *netdev, struct scan_bss
*target_bss,
netdev_ft_over_ds_tx_authenticate,
netdev_ft_tx_associate, netdev);
- if (!auth_proto_start(netdev->ap))
- goto restore_snonce;
+ wiphy_radio_work_insert(netdev->wiphy, &netdev->work, 1,
+ &connect_work_ops);
return 0;
-
-restore_snonce:
- memcpy(netdev->handshake->snonce, netdev->prev_snonce, 32);
-
- return err;
}
int netdev_fast_transition(struct netdev *netdev, struct scan_bss *target_bss,
--
2.21.1