Commit 370e5673 authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: fix broken traffic for 802.1x in client mode

When running 802.1x WEP keys must be installed
without pairwise-groupwise swap (which is
necessary for static WEP).
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 5c427f5c
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
static int ath10k_send_key(struct ath10k_vif *arvif, static int ath10k_send_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key, struct ieee80211_key_conf *key,
enum set_key_cmd cmd, enum set_key_cmd cmd,
const u8 *macaddr, bool def_idx) const u8 *macaddr, u32 flags)
{ {
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
struct wmi_vdev_install_key_arg arg = { struct wmi_vdev_install_key_arg arg = {
...@@ -45,16 +45,12 @@ static int ath10k_send_key(struct ath10k_vif *arvif, ...@@ -45,16 +45,12 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
.key_idx = key->keyidx, .key_idx = key->keyidx,
.key_len = key->keylen, .key_len = key->keylen,
.key_data = key->key, .key_data = key->key,
.key_flags = flags,
.macaddr = macaddr, .macaddr = macaddr,
}; };
lockdep_assert_held(&arvif->ar->conf_mutex); lockdep_assert_held(&arvif->ar->conf_mutex);
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
arg.key_flags = WMI_KEY_PAIRWISE;
else
arg.key_flags = WMI_KEY_GROUP;
switch (key->cipher) { switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP:
arg.key_cipher = WMI_CIPHER_AES_CCM; arg.key_cipher = WMI_CIPHER_AES_CCM;
...@@ -68,13 +64,6 @@ static int ath10k_send_key(struct ath10k_vif *arvif, ...@@ -68,13 +64,6 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
arg.key_cipher = WMI_CIPHER_WEP; arg.key_cipher = WMI_CIPHER_WEP;
/* AP/IBSS mode requires self-key to be groupwise
* Otherwise pairwise key must be set */
if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN))
arg.key_flags = WMI_KEY_PAIRWISE;
if (def_idx)
arg.key_flags |= WMI_KEY_TX_USAGE;
break; break;
case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_AES_CMAC:
/* this one needs to be done in software */ /* this one needs to be done in software */
...@@ -95,7 +84,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif, ...@@ -95,7 +84,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
static int ath10k_install_key(struct ath10k_vif *arvif, static int ath10k_install_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key, struct ieee80211_key_conf *key,
enum set_key_cmd cmd, enum set_key_cmd cmd,
const u8 *macaddr, bool def_idx) const u8 *macaddr, u32 flags)
{ {
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
int ret; int ret;
...@@ -104,7 +93,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif, ...@@ -104,7 +93,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif,
reinit_completion(&ar->install_key_done); reinit_completion(&ar->install_key_done);
ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx); ret = ath10k_send_key(arvif, key, cmd, macaddr, flags);
if (ret) if (ret)
return ret; return ret;
...@@ -122,7 +111,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, ...@@ -122,7 +111,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
struct ath10k_peer *peer; struct ath10k_peer *peer;
int ret; int ret;
int i; int i;
bool def_idx; u32 flags;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
...@@ -136,14 +125,16 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, ...@@ -136,14 +125,16 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) { for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
if (arvif->wep_keys[i] == NULL) if (arvif->wep_keys[i] == NULL)
continue; continue;
flags = 0;
flags |= WMI_KEY_PAIRWISE;
/* set TX_USAGE flag for default key id */ /* set TX_USAGE flag for default key id */
if (arvif->def_wep_key_idx == i) if (arvif->def_wep_key_idx == i)
def_idx = true; flags |= WMI_KEY_TX_USAGE;
else
def_idx = false;
ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
addr, def_idx); addr, flags);
if (ret) if (ret)
return ret; return ret;
...@@ -163,6 +154,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, ...@@ -163,6 +154,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
int first_errno = 0; int first_errno = 0;
int ret; int ret;
int i; int i;
u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
...@@ -179,7 +171,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, ...@@ -179,7 +171,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
/* key flags are not required to delete the key */ /* key flags are not required to delete the key */
ret = ath10k_install_key(arvif, peer->keys[i], ret = ath10k_install_key(arvif, peer->keys[i],
DISABLE_KEY, addr, false); DISABLE_KEY, addr, flags);
if (ret && first_errno == 0) if (ret && first_errno == 0)
first_errno = ret; first_errno = ret;
...@@ -229,6 +221,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, ...@@ -229,6 +221,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
int first_errno = 0; int first_errno = 0;
int ret; int ret;
int i; int i;
u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
...@@ -254,7 +247,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, ...@@ -254,7 +247,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
if (i == ARRAY_SIZE(peer->keys)) if (i == ARRAY_SIZE(peer->keys))
break; break;
/* key flags are not required to delete the key */ /* key flags are not required to delete the key */
ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false); ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, flags);
if (ret && first_errno == 0) if (ret && first_errno == 0)
first_errno = ret; first_errno = ret;
...@@ -266,6 +259,44 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, ...@@ -266,6 +259,44 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
return first_errno; return first_errno;
} }
static int ath10k_mac_vif_sta_fix_wep_key(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
enum nl80211_iftype iftype = arvif->vif->type;
struct ieee80211_key_conf *key;
u32 flags = 0;
int num = 0;
int i;
int ret;
lockdep_assert_held(&ar->conf_mutex);
if (iftype != NL80211_IFTYPE_STATION)
return 0;
for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
if (arvif->wep_keys[i]) {
key = arvif->wep_keys[i];
++num;
}
}
if (num != 1)
return 0;
flags |= WMI_KEY_PAIRWISE;
flags |= WMI_KEY_TX_USAGE;
ret = ath10k_install_key(arvif, key, SET_KEY, arvif->bssid, flags);
if (ret) {
ath10k_warn(ar, "failed to install key %i on vdev %i: %d\n",
key->keyidx, arvif->vdev_id, ret);
return ret;
}
return 0;
}
/*********************/ /*********************/
/* General utilities */ /* General utilities */
/*********************/ /*********************/
...@@ -3891,8 +3922,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -3891,8 +3922,8 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *peer_addr; const u8 *peer_addr;
bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 || bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104; key->cipher == WLAN_CIPHER_SUITE_WEP104;
bool def_idx = false;
int ret = 0; int ret = 0;
u32 flags = 0;
if (key->keyidx > WMI_MAX_KEY_INDEX) if (key->keyidx > WMI_MAX_KEY_INDEX)
return -ENOSPC; return -ENOSPC;
...@@ -3935,16 +3966,41 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ...@@ -3935,16 +3966,41 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (cmd == DISABLE_KEY) if (cmd == DISABLE_KEY)
ath10k_clear_vdev_key(arvif, key); ath10k_clear_vdev_key(arvif, key);
/* 802.1x never sets the def_wep_key_idx so each set_key()
* call changes default tx key.
*
* Static WEP sets def_wep_key_idx via .set_default_unicast_key
* after first set_key().
*/
if (cmd == SET_KEY && arvif->def_wep_key_idx == -1)
flags |= WMI_KEY_TX_USAGE;
} }
/* set TX_USAGE flag for all the keys incase of dot1x-WEP. For if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
* static WEP, do not set this flag for the keys whose key id flags |= WMI_KEY_PAIRWISE;
* is greater than default key id. else
flags |= WMI_KEY_GROUP;
/* mac80211 uploads static WEP keys as groupwise while fw/hw requires
* pairwise keys for non-self peers, i.e. BSSID in STA mode and
* associated stations in AP/IBSS.
*
* Static WEP keys for peer_addr=vif->addr and 802.1X WEP keys work
* fine when mapped directly from mac80211.
*
* Note: When installing first static WEP groupwise key (which should
* be pairwise) def_wep_key_idx isn't known yet (it's equal to -1).
* Since .set_default_unicast_key is called only for static WEP it's
* used to re-upload the key as pairwise.
*/ */
if (arvif->def_wep_key_idx == -1) if (arvif->def_wep_key_idx >= 0 &&
def_idx = true; memcmp(peer_addr, arvif->vif->addr, ETH_ALEN)) {
flags &= ~WMI_KEY_GROUP;
flags |= WMI_KEY_PAIRWISE;
}
ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx); ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
arvif->vdev_id, peer_addr, ret); arvif->vdev_id, peer_addr, ret);
...@@ -3998,6 +4054,14 @@ static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw, ...@@ -3998,6 +4054,14 @@ static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw,
} }
arvif->def_wep_key_idx = keyidx; arvif->def_wep_key_idx = keyidx;
ret = ath10k_mac_vif_sta_fix_wep_key(arvif);
if (ret) {
ath10k_warn(ar, "failed to fix sta wep key on vdev %i: %d\n",
arvif->vdev_id, ret);
goto unlock;
}
unlock: unlock:
mutex_unlock(&arvif->ar->conf_mutex); mutex_unlock(&arvif->ar->conf_mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment