|
@@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|
|
}
|
|
|
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);
|
|
|
- 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 = {};
|
|
|
+ bool have_wep = !(IS_ERR(local->wep_tx_tfm) ||
|
|
|
+ IS_ERR(local->wep_rx_tfm));
|
|
|
+ bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE;
|
|
|
+ const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes;
|
|
|
+ int n_suites = 0, r = 0, w = 0;
|
|
|
+ u32 *suites;
|
|
|
static const u32 cipher_suites[] = {
|
|
|
/* keep WEP first, it may be removed below */
|
|
|
WLAN_CIPHER_SUITE_WEP40,
|
|
@@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|
|
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 &&
|
|
|
(local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||
|
|
|
local->hw.offchannel_tx_hw_queue >= local->hw.queues))
|
|
@@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|
|
if (local->hw.wiphy->max_scan_ie_len)
|
|
|
local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
|
|
|
|
|
|
- /* Set up cipher suites unless driver already did */
|
|
|
- if (!local->hw.wiphy->cipher_suites) {
|
|
|
- local->hw.wiphy->cipher_suites = cipher_suites;
|
|
|
- local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
|
|
- if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
|
|
|
- local->hw.wiphy->n_cipher_suites--;
|
|
|
- }
|
|
|
- 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(
|
|
|
- local->hw.wiphy->cipher_suites,
|
|
|
- sizeof(u32) * local->hw.wiphy->n_cipher_suites,
|
|
|
- GFP_KERNEL);
|
|
|
- if (!suites) {
|
|
|
- result = -ENOMEM;
|
|
|
- goto fail_wiphy_register;
|
|
|
- }
|
|
|
- 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;
|
|
|
- }
|
|
|
- }
|
|
|
+ WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,
|
|
|
+ local->hw.n_cipher_schemes));
|
|
|
+
|
|
|
+ result = ieee80211_init_cipher_suites(local);
|
|
|
+ if (result < 0)
|
|
|
+ goto fail_wiphy_register;
|
|
|
|
|
|
if (!local->ops->remain_on_channel)
|
|
|
local->hw.wiphy->max_remain_on_channel_duration = 5000;
|