static int ath10k_send_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr, bool def_idx)
+ const u8 *macaddr, u32 flags)
{
struct ath10k *ar = arvif->ar;
struct wmi_vdev_install_key_arg arg = {
.key_idx = key->keyidx,
.key_len = key->keylen,
.key_data = key->key,
+ .key_flags = flags,
.macaddr = macaddr,
};
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) {
case WLAN_CIPHER_SUITE_CCMP:
arg.key_cipher = WMI_CIPHER_AES_CCM;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
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;
case WLAN_CIPHER_SUITE_AES_CMAC:
/* this one needs to be done in software */
static int ath10k_install_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr, bool def_idx)
+ const u8 *macaddr, u32 flags)
{
struct ath10k *ar = arvif->ar;
int ret;
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)
return ret;
struct ath10k_peer *peer;
int ret;
int i;
- bool def_idx;
+ u32 flags;
lockdep_assert_held(&ar->conf_mutex);
for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
if (arvif->wep_keys[i] == NULL)
continue;
+
+ flags = 0;
+ flags |= WMI_KEY_PAIRWISE;
+
/* set TX_USAGE flag for default key id */
if (arvif->def_wep_key_idx == i)
- def_idx = true;
- else
- def_idx = false;
+ flags |= WMI_KEY_TX_USAGE;
ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
- addr, def_idx);
+ addr, flags);
if (ret)
return ret;
int first_errno = 0;
int ret;
int i;
+ u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex);
/* key flags are not required to delete the key */
ret = ath10k_install_key(arvif, peer->keys[i],
- DISABLE_KEY, addr, false);
+ DISABLE_KEY, addr, flags);
if (ret && first_errno == 0)
first_errno = ret;
int first_errno = 0;
int ret;
int i;
+ u32 flags = 0;
lockdep_assert_held(&ar->conf_mutex);
if (i == ARRAY_SIZE(peer->keys))
break;
/* 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)
first_errno = ret;
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 */
/*********************/
const u8 *peer_addr;
bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104;
- bool def_idx = false;
int ret = 0;
+ u32 flags = 0;
if (key->keyidx > WMI_MAX_KEY_INDEX)
return -ENOSPC;
if (cmd == DISABLE_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
- * static WEP, do not set this flag for the keys whose key id
- * is greater than default key id.
+ if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+ flags |= WMI_KEY_PAIRWISE;
+ 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)
- def_idx = true;
+ if (arvif->def_wep_key_idx >= 0 &&
+ 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) {
ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
arvif->vdev_id, peer_addr, ret);
}
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:
mutex_unlock(&arvif->ar->conf_mutex);
}