Skip to content

Commit

Permalink
wifi: mac80211: properly implement MLO key handling
Browse files Browse the repository at this point in the history
Implement key installation and lookup (on TX and RX)
for MLO, so we can use multiple GTKs/IGTKs/BIGTKs.

Co-authored-by: Ilan Peer <[email protected]>
Signed-off-by: Ilan Peer <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
  • Loading branch information
jmberg-intel and ilanpeer2 committed Aug 25, 2022
1 parent e7a7b84 commit ccdde7c
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 104 deletions.
2 changes: 2 additions & 0 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,7 @@ enum ieee80211_key_flags {
* - Temporal Authenticator Rx MIC Key (64 bits)
* @icv_len: The ICV length for this key type
* @iv_len: The IV length for this key type
* @link_id: the link ID for MLO, or -1 for non-MLO or pairwise keys
*/
struct ieee80211_key_conf {
atomic64_t tx_pn;
Expand All @@ -1984,6 +1985,7 @@ struct ieee80211_key_conf {
u8 hw_key_idx;
s8 keyidx;
u16 flags;
s8 link_id;
u8 keylen;
u8 key[];
};
Expand Down
75 changes: 62 additions & 13 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@
#include "wme.h"

static struct ieee80211_link_data *
ieee80211_link_or_deflink(struct ieee80211_sub_if_data *sdata, int link_id)
ieee80211_link_or_deflink(struct ieee80211_sub_if_data *sdata, int link_id,
bool require_valid)
{
struct ieee80211_link_data *link;

if (link_id < 0) {
if (sdata->vif.valid_links)
/*
* For keys, if sdata is not an MLD, we might not use
* the return value at all (if it's not a pairwise key),
* so in that case (require_valid==false) don't error.
*/
if (require_valid && sdata->vif.valid_links)
return ERR_PTR(-EINVAL);

return &sdata->deflink;
Expand Down Expand Up @@ -456,6 +462,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac_addr, struct key_params *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_link_data *link =
ieee80211_link_or_deflink(sdata, link_id, false);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta = NULL;
struct ieee80211_key *key;
Expand All @@ -464,6 +472,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;

if (IS_ERR(link))
return PTR_ERR(link);

if (pairwise && params->mode == NL80211_KEY_SET_TX)
return ieee80211_set_tx(sdata, mac_addr, key_idx);

Expand All @@ -472,6 +483,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_WEP104:
if (link_id >= 0)
return -EINVAL;
if (WARN_ON_ONCE(fips_enabled))
return -EINVAL;
break;
Expand All @@ -484,6 +497,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (IS_ERR(key))
return PTR_ERR(key);

key->conf.link_id = link_id;

if (pairwise)
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;

Expand Down Expand Up @@ -545,7 +560,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
break;
}

err = ieee80211_key_link(key, sdata, sta);
err = ieee80211_key_link(key, link, sta);

out_unlock:
mutex_unlock(&local->sta_mtx);
Expand All @@ -554,18 +569,37 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}

static struct ieee80211_key *
ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata,
ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata, int link_id,
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_link_data *link = &sdata->deflink;
struct ieee80211_key *key;
struct sta_info *sta;

if (link_id >= 0) {
link = rcu_dereference_check(sdata->link[link_id],
lockdep_is_held(&sdata->wdev.mtx));
if (!link)
return NULL;
}

if (mac_addr) {
struct sta_info *sta;
struct link_sta_info *link_sta;

sta = sta_info_get_bss(sdata, mac_addr);
if (!sta)
return NULL;

if (link_id >= 0) {
link_sta = rcu_dereference_check(sta->link[link_id],
lockdep_is_held(&local->sta_mtx));
if (!link_sta)
return NULL;
} else {
link_sta = &sta->deflink;
}

if (pairwise && key_idx < NUM_DEFAULT_KEYS)
return rcu_dereference_check_key_mtx(local,
sta->ptk[key_idx]);
Expand All @@ -575,7 +609,7 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata,
NUM_DEFAULT_MGMT_KEYS +
NUM_DEFAULT_BEACON_KEYS)
return rcu_dereference_check_key_mtx(local,
sta->deflink.gtk[key_idx]);
link_sta->gtk[key_idx]);

return NULL;
}
Expand All @@ -584,7 +618,7 @@ ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata,
return rcu_dereference_check_key_mtx(local,
sdata->keys[key_idx]);

key = rcu_dereference_check_key_mtx(local, sdata->deflink.gtk[key_idx]);
key = rcu_dereference_check_key_mtx(local, link->gtk[key_idx]);
if (key)
return key;

Expand All @@ -607,7 +641,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
mutex_lock(&local->sta_mtx);
mutex_lock(&local->key_mtx);

key = ieee80211_lookup_key(sdata, key_idx, pairwise, mac_addr);
key = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);
if (!key) {
ret = -ENOENT;
goto out_unlock;
Expand Down Expand Up @@ -643,7 +677,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,

rcu_read_lock();

key = ieee80211_lookup_key(sdata, key_idx, pairwise, mac_addr);
key = ieee80211_lookup_key(sdata, link_id, key_idx, pairwise, mac_addr);
if (!key)
goto out;

Expand Down Expand Up @@ -734,8 +768,13 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
bool multi)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_link_data *link =
ieee80211_link_or_deflink(sdata, link_id, false);

ieee80211_set_default_key(sdata, key_idx, uni, multi);
if (IS_ERR(link))
return PTR_ERR(link);

ieee80211_set_default_key(link, key_idx, uni, multi);

return 0;
}
Expand All @@ -745,8 +784,13 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
int link_id, u8 key_idx)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_link_data *link =
ieee80211_link_or_deflink(sdata, link_id, true);

ieee80211_set_default_mgmt_key(sdata, key_idx);
if (IS_ERR(link))
return PTR_ERR(link);

ieee80211_set_default_mgmt_key(link, key_idx);

return 0;
}
Expand All @@ -756,8 +800,13 @@ static int ieee80211_config_default_beacon_key(struct wiphy *wiphy,
int link_id, u8 key_idx)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_link_data *link =
ieee80211_link_or_deflink(sdata, link_id, true);

if (IS_ERR(link))
return PTR_ERR(link);

ieee80211_set_default_beacon_key(sdata, key_idx);
ieee80211_set_default_beacon_key(link, key_idx);

return 0;
}
Expand Down Expand Up @@ -2588,7 +2637,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_link_data *link =
ieee80211_link_or_deflink(sdata, params->link_id);
ieee80211_link_or_deflink(sdata, params->link_id, true);
struct ieee80211_tx_queue_params p;

if (!local->ops->conf_tx)
Expand Down
1 change: 1 addition & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ struct ieee80211_rx_data {
struct ieee80211_sub_if_data *sdata;
struct ieee80211_link_data *link;
struct sta_info *sta;
struct link_sta_info *link_sta;
struct ieee80211_key *key;

unsigned int flags;
Expand Down
9 changes: 9 additions & 0 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,19 @@ struct link_container {
static void ieee80211_free_links(struct ieee80211_sub_if_data *sdata,
struct link_container **links)
{
LIST_HEAD(keys);
unsigned int link_id;

for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
if (!links[link_id])
continue;
ieee80211_remove_link_keys(&links[link_id]->data, &keys);
}

synchronize_rcu();

ieee80211_free_key_list(sdata->local, &keys);

for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) {
if (!links[link_id])
continue;
Expand Down
Loading

0 comments on commit ccdde7c

Please sign in to comment.