mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-11-26 18:59:22 +01:00
device: In roam, preauthenticate to target BSS if supported
If FT is not possible and we're using 8021x try to preauthenticate to target BSS before reassociation to it.
This commit is contained in:
parent
08e863cb7e
commit
a620a02d35
133
src/device.c
133
src/device.c
@ -76,6 +76,7 @@ struct device {
|
|||||||
struct timespec roam_min_time;
|
struct timespec roam_min_time;
|
||||||
struct l_timeout *roam_trigger_timeout;
|
struct l_timeout *roam_trigger_timeout;
|
||||||
uint32_t roam_scan_id;
|
uint32_t roam_scan_id;
|
||||||
|
uint8_t preauth_bssid[ETH_ALEN];
|
||||||
|
|
||||||
struct wiphy *wiphy;
|
struct wiphy *wiphy;
|
||||||
struct netdev *netdev;
|
struct netdev *netdev;
|
||||||
@ -802,11 +803,102 @@ static void device_fast_transition_cb(struct netdev *netdev,
|
|||||||
device_roam_failed(device);
|
device_roam_failed(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void device_transition_reassociate(struct device *device,
|
||||||
|
struct scan_bss *bss,
|
||||||
|
struct handshake_state *new_hs)
|
||||||
|
{
|
||||||
|
if (netdev_reassociate(device->netdev, bss, new_hs,
|
||||||
|
device_reassociate_cb) < 0) {
|
||||||
|
handshake_state_free(new_hs);
|
||||||
|
|
||||||
|
device_roam_failed(device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->connected_bss = bss;
|
||||||
|
device->preparing_roam = false;
|
||||||
|
device_enter_state(device, DEVICE_STATE_ROAMING);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bss_match_bssid(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct scan_bss *bss = a;
|
||||||
|
const uint8_t *bssid = b;
|
||||||
|
|
||||||
|
return !memcmp(bss->addr, bssid, sizeof(bss->addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void device_preauthenticate_cb(struct netdev *netdev,
|
||||||
|
enum netdev_result result,
|
||||||
|
const uint8_t *pmk, void *user_data)
|
||||||
|
{
|
||||||
|
struct device *device = user_data;
|
||||||
|
struct scan_bss *bss;
|
||||||
|
struct handshake_state *new_hs;
|
||||||
|
|
||||||
|
l_debug("%d, result: %d", device->index, result);
|
||||||
|
|
||||||
|
if (!device->preparing_roam || result == NETDEV_RESULT_ABORTED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bss = l_queue_find(device->bss_list, bss_match_bssid,
|
||||||
|
device->preauth_bssid);
|
||||||
|
if (!bss) {
|
||||||
|
l_error("Roam target BSS not found");
|
||||||
|
|
||||||
|
device_roam_failed(device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_hs = device_handshake_setup(device, device->connected_network, bss);
|
||||||
|
if (!new_hs) {
|
||||||
|
l_error("device_handshake_setup failed");
|
||||||
|
|
||||||
|
device_roam_failed(device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == NETDEV_RESULT_OK) {
|
||||||
|
uint8_t pmkid[16];
|
||||||
|
uint8_t rsne_buf[300];
|
||||||
|
struct ie_rsn_info rsn_info;
|
||||||
|
|
||||||
|
handshake_state_set_pmk(new_hs, pmk);
|
||||||
|
handshake_state_set_authenticator_address(new_hs,
|
||||||
|
device->preauth_bssid);
|
||||||
|
handshake_state_set_supplicant_address(new_hs,
|
||||||
|
netdev_get_address(device->netdev));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rebuild the RSNE to include the negotiated PMKID. Note
|
||||||
|
* own_ie can't be a WPA IE here, including because the
|
||||||
|
* WPA IE doesn't have a capabilities field and
|
||||||
|
* target_rsne->preauthentication would have been false in
|
||||||
|
* device_transition_start.
|
||||||
|
*/
|
||||||
|
ie_parse_rsne_from_data(new_hs->own_ie, new_hs->own_ie[1] + 2,
|
||||||
|
&rsn_info);
|
||||||
|
|
||||||
|
handshake_state_get_pmkid(new_hs, pmkid);
|
||||||
|
|
||||||
|
rsn_info.num_pmkids = 1;
|
||||||
|
rsn_info.pmkids = pmkid;
|
||||||
|
|
||||||
|
ie_build_rsne(&rsn_info, rsne_buf);
|
||||||
|
handshake_state_set_own_rsn(new_hs, rsne_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_transition_reassociate(device, bss, new_hs);
|
||||||
|
}
|
||||||
|
|
||||||
static void device_transition_start(struct device *device, struct scan_bss *bss)
|
static void device_transition_start(struct device *device, struct scan_bss *bss)
|
||||||
{
|
{
|
||||||
struct handshake_state *hs = netdev_get_handshake(device->netdev);
|
struct handshake_state *hs = netdev_get_handshake(device->netdev);
|
||||||
uint16_t mdid;
|
uint16_t mdid;
|
||||||
struct handshake_state *new_hs;
|
struct handshake_state *new_hs;
|
||||||
|
struct ie_rsn_info cur_rsne, target_rsne;
|
||||||
|
enum security security =
|
||||||
|
network_get_security(device->connected_network);
|
||||||
|
|
||||||
l_debug("%d, target %s", device->index,
|
l_debug("%d, target %s", device->index,
|
||||||
util_address_to_string(bss->addr));
|
util_address_to_string(bss->addr));
|
||||||
@ -842,6 +934,35 @@ static void device_transition_start(struct device *device, struct scan_bss *bss)
|
|||||||
|
|
||||||
/* Non-FT transition */
|
/* Non-FT transition */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FT not available, we can try preauthentication if available.
|
||||||
|
* 802.11-2012 section 11.5.9.2:
|
||||||
|
* "A STA shall not use preauthentication within the same mobility
|
||||||
|
* domain if AKM suite type 00-0F-AC:3 or 00-0F-AC:4 is used in
|
||||||
|
* the current association."
|
||||||
|
*/
|
||||||
|
if (security == SECURITY_8021X &&
|
||||||
|
scan_bss_get_rsn_info(device->connected_bss,
|
||||||
|
&cur_rsne) >= 0 &&
|
||||||
|
scan_bss_get_rsn_info(bss, &target_rsne) >= 0 &&
|
||||||
|
cur_rsne.preauthentication &&
|
||||||
|
target_rsne.preauthentication) {
|
||||||
|
/*
|
||||||
|
* Both the current and the target AP support
|
||||||
|
* pre-authentication and we're using 8021x authentication so
|
||||||
|
* attempt to pre-authenticate and reassociate afterwards.
|
||||||
|
* If the pre-authentication fails or times out we simply
|
||||||
|
* won't supply any PMKID when reassociating.
|
||||||
|
* Remain in the preparing_roam state.
|
||||||
|
*/
|
||||||
|
memcpy(device->preauth_bssid, bss->addr, ETH_ALEN);
|
||||||
|
|
||||||
|
if (netdev_preauthenticate(device->netdev, bss,
|
||||||
|
device_preauthenticate_cb,
|
||||||
|
device) >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
new_hs = device_handshake_setup(device, device->connected_network, bss);
|
new_hs = device_handshake_setup(device, device->connected_network, bss);
|
||||||
if (!new_hs) {
|
if (!new_hs) {
|
||||||
l_error("device_handshake_setup failed in reassociation");
|
l_error("device_handshake_setup failed in reassociation");
|
||||||
@ -850,17 +971,7 @@ static void device_transition_start(struct device *device, struct scan_bss *bss)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (netdev_reassociate(device->netdev, bss, new_hs,
|
device_transition_reassociate(device, bss, new_hs);
|
||||||
device_reassociate_cb) < 0) {
|
|
||||||
handshake_state_free(new_hs);
|
|
||||||
|
|
||||||
device_roam_failed(device);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
device->connected_bss = bss;
|
|
||||||
device->preparing_roam = false;
|
|
||||||
device_enter_state(device, DEVICE_STATE_ROAMING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_roam_scan_triggered(int err, void *user_data)
|
static void device_roam_scan_triggered(int err, void *user_data)
|
||||||
|
Loading…
Reference in New Issue
Block a user