Commit 2475b1cc authored by Max Stepanov's avatar Max Stepanov Committed by Johannes Berg
Browse files

mac80211: add generic cipher scheme support



This adds generic cipher scheme support to mac80211, such schemes
are fully under control by the driver. On hw registration drivers
may specify additional HW ciphers with a scheme how these ciphers
have to be handled by mac80211 TX/RR. A cipher scheme specifies a
cipher suite value, a size of the security header to be added to
or stripped from frames and how the PN is to be verified on RX.
Signed-off-by: default avatarMax Stepanov <Max.Stepanov@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 6bc54fbc
...@@ -1228,6 +1228,36 @@ struct ieee80211_key_conf { ...@@ -1228,6 +1228,36 @@ struct ieee80211_key_conf {
u8 key[0]; u8 key[0];
}; };
/**
* struct ieee80211_cipher_scheme - cipher scheme
*
* This structure contains a cipher scheme information defining
* the secure packet crypto handling.
*
* @cipher: a cipher suite selector
* @iftype: a cipher iftype bit mask indicating an allowed cipher usage
* @hdr_len: a length of a security header used the cipher
* @pn_len: a length of a packet number in the security header
* @pn_off: an offset of pn from the beginning of the security header
* @key_idx_off: an offset of key index byte in the security header
* @key_idx_mask: a bit mask of key_idx bits
* @key_idx_shift: a bit shift needed to get key_idx
* key_idx value calculation:
* (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift
* @mic_len: a mic length in bytes
*/
struct ieee80211_cipher_scheme {
u32 cipher;
u16 iftype;
u8 hdr_len;
u8 pn_len;
u8 pn_off;
u8 key_idx_off;
u8 key_idx_mask;
u8 key_idx_shift;
u8 mic_len;
};
/** /**
* enum set_key_cmd - key command * enum set_key_cmd - key command
* *
...@@ -1636,6 +1666,10 @@ enum ieee80211_hw_flags { ...@@ -1636,6 +1666,10 @@ enum ieee80211_hw_flags {
* @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may
* deliver to a WMM STA during any Service Period triggered by the WMM STA. * deliver to a WMM STA during any Service Period triggered by the WMM STA.
* Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values. * Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
*
* @n_cipher_schemes: a size of an array of cipher schemes definitions.
* @cipher_schemes: a pointer to an array of cipher scheme definitions
* supported by HW.
*/ */
struct ieee80211_hw { struct ieee80211_hw {
struct ieee80211_conf conf; struct ieee80211_conf conf;
...@@ -1663,6 +1697,8 @@ struct ieee80211_hw { ...@@ -1663,6 +1697,8 @@ struct ieee80211_hw {
netdev_features_t netdev_features; netdev_features_t netdev_features;
u8 uapsd_queues; u8 uapsd_queues;
u8 uapsd_max_sp_len; u8 uapsd_max_sp_len;
u8 n_cipher_schemes;
const struct ieee80211_cipher_scheme *cipher_schemes;
}; };
/** /**
......
...@@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
struct key_params *params) struct key_params *params)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta = NULL; struct sta_info *sta = NULL;
const struct ieee80211_cipher_scheme *cs = NULL;
struct ieee80211_key *key; struct ieee80211_key *key;
int err; int err;
...@@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_WEP104:
if (IS_ERR(sdata->local->wep_tx_tfm)) if (IS_ERR(local->wep_tx_tfm))
return -EINVAL; return -EINVAL;
break; break;
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_GCMP:
break;
default: default:
cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type);
break; break;
} }
key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len, key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
params->key, params->seq_len, params->seq); params->key, params->seq_len, params->seq,
cs);
if (IS_ERR(key)) if (IS_ERR(key))
return PTR_ERR(key); return PTR_ERR(key);
if (pairwise) if (pairwise)
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
mutex_lock(&sdata->local->sta_mtx); mutex_lock(&local->sta_mtx);
if (mac_addr) { if (mac_addr) {
if (ieee80211_vif_is_mesh(&sdata->vif)) if (ieee80211_vif_is_mesh(&sdata->vif))
...@@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
break; break;
} }
if (sta)
sta->cipher_scheme = cs;
err = ieee80211_key_link(key, sdata, sta); err = ieee80211_key_link(key, sdata, sta);
out_unlock: out_unlock:
mutex_unlock(&sdata->local->sta_mtx); mutex_unlock(&local->sta_mtx);
return err; return err;
} }
...@@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
goto out_unlock; goto out_unlock;
if (pairwise) if (pairwise)
key = key_mtx_dereference(local, sta->ptk); key = key_mtx_dereference(local, sta->ptk[key_idx]);
else else
key = key_mtx_dereference(local, sta->gtk[key_idx]); key = key_mtx_dereference(local, sta->gtk[key_idx]);
} else } else
...@@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
goto out; goto out;
if (pairwise) if (pairwise)
key = rcu_dereference(sta->ptk); key = rcu_dereference(sta->ptk[key_idx]);
else if (key_idx < NUM_DEFAULT_KEYS) else if (key_idx < NUM_DEFAULT_KEYS)
key = rcu_dereference(sta->gtk[key_idx]); key = rcu_dereference(sta->gtk[key_idx]);
} else } else
...@@ -968,11 +979,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -968,11 +979,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
*/ */
sdata->control_port_protocol = params->crypto.control_port_ethertype; sdata->control_port_protocol = params->crypto.control_port_ethertype;
sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
&params->crypto,
sdata->vif.type);
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
vlan->control_port_protocol = vlan->control_port_protocol =
params->crypto.control_port_ethertype; params->crypto.control_port_ethertype;
vlan->control_port_no_encrypt = vlan->control_port_no_encrypt =
params->crypto.control_port_no_encrypt; params->crypto.control_port_no_encrypt;
vlan->encrypt_headroom =
ieee80211_cs_headroom(sdata->local,
&params->crypto,
vlan->vif.type);
} }
sdata->vif.bss_conf.beacon_int = params->beacon_interval; sdata->vif.bss_conf.beacon_int = params->beacon_interval;
......
...@@ -728,6 +728,7 @@ struct ieee80211_sub_if_data { ...@@ -728,6 +728,7 @@ struct ieee80211_sub_if_data {
u16 sequence_number; u16 sequence_number;
__be16 control_port_protocol; __be16 control_port_protocol;
bool control_port_no_encrypt; bool control_port_no_encrypt;
int encrypt_headroom;
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
...@@ -1749,6 +1750,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work); ...@@ -1749,6 +1750,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work);
int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata, int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *csa_settings); struct cfg80211_csa_settings *csa_settings);
bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs);
bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n);
const struct ieee80211_cipher_scheme *
ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
enum nl80211_iftype iftype);
int ieee80211_cs_headroom(struct ieee80211_local *local,
struct cfg80211_crypto_settings *crypto,
enum nl80211_iftype iftype);
#ifdef CONFIG_MAC80211_NOINLINE #ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline #define debug_noinline noinline
#else #else
......
...@@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) ...@@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
snprintf(sdata->name, IFNAMSIZ, "%s-monitor", snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
wiphy_name(local->hw.wiphy)); wiphy_name(local->hw.wiphy));
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
ieee80211_set_default_queues(sdata); ieee80211_set_default_queues(sdata);
ret = drv_add_interface(local, sdata); ret = drv_add_interface(local, sdata);
...@@ -1273,6 +1275,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, ...@@ -1273,6 +1275,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE); sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
sdata->control_port_no_encrypt = false; sdata->control_port_no_encrypt = false;
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
sdata->noack_map = 0; sdata->noack_map = 0;
...@@ -1689,6 +1692,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ...@@ -1689,6 +1692,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
sdata->user_power_level = local->user_power_level; sdata->user_power_level = local->user_power_level;
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
/* setup type-dependent data */ /* setup type-dependent data */
ieee80211_setup_sdata(sdata, type); ieee80211_setup_sdata(sdata, type);
......
...@@ -267,22 +267,22 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ...@@ -267,22 +267,22 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (new) if (new)
list_add_tail(&new->list, &sdata->key_list); list_add_tail(&new->list, &sdata->key_list);
if (sta && pairwise) { WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
rcu_assign_pointer(sta->ptk, new);
} else if (sta) {
if (old)
idx = old->conf.keyidx;
else
idx = new->conf.keyidx;
rcu_assign_pointer(sta->gtk[idx], new);
} else {
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
if (old) if (old)
idx = old->conf.keyidx; idx = old->conf.keyidx;
else else
idx = new->conf.keyidx; idx = new->conf.keyidx;
if (sta) {
if (pairwise) {
rcu_assign_pointer(sta->ptk[idx], new);
sta->ptk_idx = idx;
} else {
rcu_assign_pointer(sta->gtk[idx], new);
sta->gtk_idx = idx;
}
} else {
defunikey = old && defunikey = old &&
old == key_mtx_dereference(sdata->local, old == key_mtx_dereference(sdata->local,
sdata->default_unicast_key); sdata->default_unicast_key);
...@@ -316,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ...@@ -316,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
list_del(&old->list); list_del(&old->list);
} }
struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, struct ieee80211_key *
const u8 *key_data, ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
size_t seq_len, const u8 *seq) const u8 *key_data,
size_t seq_len, const u8 *seq,
const struct ieee80211_cipher_scheme *cs)
{ {
struct ieee80211_key *key; struct ieee80211_key *key;
int i, j, err; int i, j, err;
...@@ -397,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, ...@@ -397,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
return ERR_PTR(err); return ERR_PTR(err);
} }
break; break;
default:
if (cs) {
size_t len = (seq_len > MAX_PN_LEN) ?
MAX_PN_LEN : seq_len;
key->conf.iv_len = cs->hdr_len;
key->conf.icv_len = cs->mic_len;
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
for (j = 0; j < len; j++)
key->u.gen.rx_pn[i][j] =
seq[len - j - 1];
}
} }
memcpy(key->conf.key, key_data, key_len); memcpy(key->conf.key, key_data, key_len);
INIT_LIST_HEAD(&key->list); INIT_LIST_HEAD(&key->list);
...@@ -479,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key, ...@@ -479,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
mutex_lock(&sdata->local->key_mtx); mutex_lock(&sdata->local->key_mtx);
if (sta && pairwise) if (sta && pairwise)
old_key = key_mtx_dereference(sdata->local, sta->ptk); old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
else if (sta) else if (sta)
old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
else else
...@@ -629,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local, ...@@ -629,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
list_add(&key->list, &keys); list_add(&key->list, &keys);
} }
key = key_mtx_dereference(local, sta->ptk); for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
if (key) { key = key_mtx_dereference(local, sta->ptk[i]);
if (!key)
continue;
ieee80211_key_replace(key->sdata, key->sta, ieee80211_key_replace(key->sdata, key->sta,
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
key, NULL); key, NULL);
...@@ -881,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif, ...@@ -881,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx, key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
keyconf->keylen, keyconf->key, keyconf->keylen, keyconf->key,
0, NULL); 0, NULL, NULL);
if (IS_ERR(key)) if (IS_ERR(key))
return ERR_CAST(key); return ERR_CAST(key);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#define NUM_DEFAULT_KEYS 4 #define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2 #define NUM_DEFAULT_MGMT_KEYS 2
#define MAX_PN_LEN 16
struct ieee80211_local; struct ieee80211_local;
struct ieee80211_sub_if_data; struct ieee80211_sub_if_data;
...@@ -93,6 +94,10 @@ struct ieee80211_key { ...@@ -93,6 +94,10 @@ struct ieee80211_key {
u32 replays; /* dot11RSNAStatsCMACReplays */ u32 replays; /* dot11RSNAStatsCMACReplays */
u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
} aes_cmac; } aes_cmac;
struct {
/* generic cipher scheme */
u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
} gen;
} u; } u;
/* number of times this key has been used */ /* number of times this key has been used */
...@@ -113,9 +118,11 @@ struct ieee80211_key { ...@@ -113,9 +118,11 @@ struct ieee80211_key {
struct ieee80211_key_conf conf; struct ieee80211_key_conf conf;
}; };
struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, struct ieee80211_key *
const u8 *key_data, ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
size_t seq_len, const u8 *seq); const u8 *key_data,
size_t seq_len, const u8 *seq,
const struct ieee80211_cipher_scheme *cs);
/* /*
* Insert a key into data structures (sdata, sta if necessary) * Insert a key into data structures (sdata, sta if necessary)
* to make it used, free old key. On failure, also free the new key. * to make it used, free old key. On failure, also free the new key.
......
...@@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, ...@@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
} }
EXPORT_SYMBOL(ieee80211_alloc_hw); EXPORT_SYMBOL(ieee80211_alloc_hw);
int ieee80211_register_hw(struct ieee80211_hw *hw) static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
{ {
struct ieee80211_local *local = hw_to_local(hw); bool have_wep = !(IS_ERR(local->wep_tx_tfm) ||
int result, i; IS_ERR(local->wep_rx_tfm));
enum ieee80211_band band; bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE;
int channels, max_bitrates; const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes;
bool supp_ht, supp_vht; int n_suites = 0, r = 0, w = 0;
netdev_features_t feature_whitelist; u32 *suites;
struct cfg80211_chan_def dflt_chandef = {};
static const u32 cipher_suites[] = { static const u32 cipher_suites[] = {
/* keep WEP first, it may be removed below */ /* keep WEP first, it may be removed below */
WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP40,
...@@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
WLAN_CIPHER_SUITE_AES_CMAC WLAN_CIPHER_SUITE_AES_CMAC
}; };
/* Driver specifies the ciphers, we have nothing to do... */
if (local->hw.wiphy->cipher_suites && have_wep)
return 0;
/* Set up cipher suites if driver relies on mac80211 cipher defs */
if (!local->hw.wiphy->cipher_suites && !cs) {
local->hw.wiphy->cipher_suites = cipher_suites;
local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
if (!have_mfp)
local->hw.wiphy->n_cipher_suites--;
if (!have_wep) {
local->hw.wiphy->cipher_suites += 2;
local->hw.wiphy->n_cipher_suites -= 2;
}
return 0;
}
if (!local->hw.wiphy->cipher_suites) {
/*
* Driver specifies cipher schemes only
* We start counting ciphers defined by schemes, TKIP and CCMP
*/
n_suites = local->hw.n_cipher_schemes + 2;
/* check if we have WEP40 and WEP104 */
if (have_wep)
n_suites += 2;
/* check if we have AES_CMAC */
if (have_mfp)
n_suites++;
suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL);
if (!suites)
return -ENOMEM;
suites[w++] = WLAN_CIPHER_SUITE_CCMP;
suites[w++] = WLAN_CIPHER_SUITE_TKIP;
if (have_wep) {
suites[w++] = WLAN_CIPHER_SUITE_WEP40;
suites[w++] = WLAN_CIPHER_SUITE_WEP104;
}
if (have_mfp)
suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC;
for (r = 0; r < local->hw.n_cipher_schemes; r++)
suites[w++] = cs[r].cipher;
} else {
/* Driver provides cipher suites, but we need to exclude WEP */
suites = kmemdup(local->hw.wiphy->cipher_suites,
sizeof(u32) * local->hw.wiphy->n_cipher_suites,
GFP_KERNEL);
if (!suites)
return -ENOMEM;
for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
u32 suite = local->hw.wiphy->cipher_suites[r];
if (suite == WLAN_CIPHER_SUITE_WEP40 ||
suite == WLAN_CIPHER_SUITE_WEP104)
continue;
suites[w++] = suite;
}
}
local->hw.wiphy->cipher_suites = suites;
local->hw.wiphy->n_cipher_suites = w;
local->wiphy_ciphers_allocated = true;
return 0;
}
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
int result, i;
enum ieee80211_band band;
int channels, max_bitrates;
bool supp_ht, supp_vht;
netdev_features_t feature_whitelist;
struct cfg80211_chan_def dflt_chandef = {};
if (hw->flags & IEEE80211_HW_QUEUE_CONTROL && if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&
(local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE || (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||
local->hw.offchannel_tx_hw_queue >= local->hw.queues)) local->hw.offchannel_tx_hw_queue >= local->hw.queues))
...@@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (local->hw.wiphy->max_scan_ie_len) if (local->hw.wiphy->max_scan_ie_len)
local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len; local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
/* Set up cipher suites unless driver already did */ WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,
if (!local->hw.wiphy->cipher_suites) { local->hw.n_cipher_schemes));
local->hw.wiphy->cipher_suites = cipher_suites;
local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); result = ieee80211_init_cipher_suites(local);
if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) if (result < 0)
local->hw.wiphy->n_cipher_suites--; goto fail_wiphy_register;
}
if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
if (local->hw.wiphy->cipher_suites == cipher_suites) {
local->hw.wiphy->cipher_suites += 2;
local->hw.wiphy->n_cipher_suites -= 2;
} else {
u32 *suites;
int r, w = 0;
/* Filter out WEP */
suites = kmemdup(