netdev: Add netdev_reassociate

netdev_reassociate transitions to another BSS without FT.  Similar to
netdev_connect but uses reassociation instead of association and
requires and an existing connection.
This commit is contained in:
Andrew Zaborowski 2017-03-31 14:43:01 +02:00 committed by Denis Kenzior
parent bb350a3b8e
commit c8b251a475
2 changed files with 68 additions and 3 deletions

View File

@ -1857,7 +1857,8 @@ static void netdev_cmd_connect_cb(struct l_genl_msg *msg, void *user_data)
static struct l_genl_msg *netdev_build_cmd_connect(struct netdev *netdev,
struct scan_bss *bss,
struct handshake_state *hs)
struct handshake_state *hs,
const uint8_t *prev_bssid)
{
uint32_t auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
struct l_genl_msg *msg;
@ -1874,6 +1875,10 @@ static struct l_genl_msg *netdev_build_cmd_connect(struct netdev *netdev,
bss->ssid_len, bss->ssid);
l_genl_msg_append_attr(msg, NL80211_ATTR_AUTH_TYPE, 4, &auth_type);
if (prev_bssid)
l_genl_msg_append_attr(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
prev_bssid);
if (bss->capability & IE_BSS_CAP_PRIVACY)
l_genl_msg_append_attr(msg, NL80211_ATTR_PRIVACY, 0, NULL);
@ -1979,7 +1984,7 @@ int netdev_connect(struct netdev *netdev, struct scan_bss *bss,
if (netdev->connected)
return -EISCONN;
cmd_connect = netdev_build_cmd_connect(netdev, bss, hs);
cmd_connect = netdev_build_cmd_connect(netdev, bss, hs, NULL);
if (!cmd_connect)
return -EINVAL;
@ -2008,7 +2013,7 @@ int netdev_connect_wsc(struct netdev *netdev, struct scan_bss *bss,
if (netdev->connected)
return -EISCONN;
cmd_connect = netdev_build_cmd_connect(netdev, bss, hs);
cmd_connect = netdev_build_cmd_connect(netdev, bss, hs, NULL);
if (!cmd_connect)
return -EINVAL;
@ -2077,6 +2082,63 @@ int netdev_disconnect(struct netdev *netdev,
return 0;
}
int netdev_reassociate(struct netdev *netdev, struct scan_bss *target_bss,
struct handshake_state *hs, netdev_connect_cb_t cb)
{
struct l_genl_msg *cmd_connect;
struct handshake_state *old_hs;
struct eapol_sm *sm = NULL, *old_sm;
bool is_rsn = hs->own_ie != NULL;
int err;
if (!netdev->operational)
return -ENOTCONN;
cmd_connect = netdev_build_cmd_connect(netdev, target_bss, hs,
netdev->handshake->aa);
if (!cmd_connect)
return -EINVAL;
if (is_rsn)
sm = eapol_sm_new(hs);
old_sm = netdev->sm;
old_hs = netdev->handshake;
err = netdev_connect_common(netdev, cmd_connect, target_bss, hs, sm,
netdev->event_filter, cb,
netdev->user_data);
if (err < 0)
return err;
memcpy(netdev->prev_bssid, old_hs->aa, ETH_ALEN);
netdev->operational = false;
/*
* Cancel commands that could be running because of EAPoL activity
* like re-keying, this way the callbacks for those commands don't
* have to check if failures resulted from the transition.
*/
if (netdev->group_new_key_cmd_id) {
l_genl_family_cancel(nl80211, netdev->group_new_key_cmd_id);
netdev->group_new_key_cmd_id = 0;
}
if (netdev->group_management_new_key_cmd_id) {
l_genl_family_cancel(nl80211,
netdev->group_management_new_key_cmd_id);
netdev->group_management_new_key_cmd_id = 0;
}
if (old_sm)
eapol_sm_free(old_sm);
handshake_state_free(old_hs);
return err;
}
/*
* Build an FT Authentication Request frame according to 12.5.2 / 12.5.4:
* RSN or non-RSN Over-the-air FT Protocol, with the IE contents

View File

@ -96,6 +96,9 @@ int netdev_connect_wsc(struct netdev *netdev, struct scan_bss *bss,
void *user_data);
int netdev_disconnect(struct netdev *netdev,
netdev_disconnect_cb_t cb, void *user_data);
int netdev_reassociate(struct netdev *netdev, struct scan_bss *target_bss,
struct handshake_state *hs,
netdev_connect_cb_t cb);
int netdev_fast_transition(struct netdev *netdev, struct scan_bss *target_bss,
netdev_connect_cb_t cb);