Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ffc2a90 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

mac80211: allow vendor specific cipher suites



Allow drivers to specify their own set of cipher
suites to advertise vendor-specific ciphers. The
driver is then required to implement hardware
crypto offload for it.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 7d64b7cc
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -119,9 +119,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
		}
	}

	ieee80211_key_link(key, sdata, sta);
	err = ieee80211_key_link(key, sdata, sta);
	if (err)
		ieee80211_key_free(sdata->local, key);

	err = 0;
 out_unlock:
	mutex_unlock(&sdata->local->sta_mtx);

+2 −0
Original line number Diff line number Diff line
@@ -662,6 +662,8 @@ struct ieee80211_local {
	int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
	unsigned int filter_flags; /* FIF_* */

	bool wiphy_ciphers_allocated;

	/* protects the aggregated multicast list and filter calls */
	spinlock_t filter_lock;

+30 −8
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
	return NULL;
}

static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
{
	struct ieee80211_sub_if_data *sdata;
	struct ieee80211_sta *sta;
@@ -68,8 +68,10 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)

	might_sleep();

	if (!key->local->ops->set_key)
		return;
	if (!key->local->ops->set_key) {
		ret = -EOPNOTSUPP;
		goto out_unsupported;
	}

	assert_key_lock(key->local);

@@ -90,6 +92,24 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
		wiphy_err(key->local->hw.wiphy,
			  "failed to set key (%d, %pM) to hardware (%d)\n",
			  key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);

out_unsupported:
	if (ret) {
		switch (key->conf.cipher) {
		case WLAN_CIPHER_SUITE_WEP40:
		case WLAN_CIPHER_SUITE_WEP104:
		case WLAN_CIPHER_SUITE_TKIP:
		case WLAN_CIPHER_SUITE_CCMP:
		case WLAN_CIPHER_SUITE_AES_CMAC:
			/* all of these we can do in software */
			ret = 0;
			break;
		default:
			ret = -EINVAL;
		}
	}

	return ret;
}

static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
@@ -329,12 +349,12 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
	kfree(key);
}

void ieee80211_key_link(struct ieee80211_key *key,
int ieee80211_key_link(struct ieee80211_key *key,
		       struct ieee80211_sub_if_data *sdata,
		       struct sta_info *sta)
{
	struct ieee80211_key *old_key;
	int idx;
	int idx, ret;

	BUG_ON(!sdata);
	BUG_ON(!key);
@@ -389,9 +409,11 @@ void ieee80211_key_link(struct ieee80211_key *key,

	ieee80211_debugfs_key_add(key);

	ieee80211_key_enable_hw_accel(key);
	ret = ieee80211_key_enable_hw_accel(key);

	mutex_unlock(&sdata->local->key_mtx);

	return ret;
}

static void __ieee80211_key_free(struct ieee80211_key *key)
+3 −3
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
 * Insert a key into data structures (sdata, sta if necessary)
 * to make it used, free old key.
 */
void ieee80211_key_link(struct ieee80211_key *key,
int __must_check ieee80211_key_link(struct ieee80211_key *key,
				    struct ieee80211_sub_if_data *sdata,
				    struct sta_info *sta);
void ieee80211_key_free(struct ieee80211_local *local,
+38 −6
Original line number Diff line number Diff line
@@ -662,13 +662,40 @@ 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)
				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;
		}
	}

	result = wiphy_register(local->hw.wiphy);
@@ -783,6 +810,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 fail_workqueue:
	wiphy_unregister(local->hw.wiphy);
 fail_wiphy_register:
	if (local->wiphy_ciphers_allocated)
		kfree(local->hw.wiphy->cipher_suites);
	kfree(local->int_scan_req);
	return result;
}
@@ -840,6 +869,9 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
	mutex_destroy(&local->iflist_mtx);
	mutex_destroy(&local->mtx);

	if (local->wiphy_ciphers_allocated)
		kfree(local->hw.wiphy->cipher_suites);

	wiphy_free(local->hw.wiphy);
}
EXPORT_SYMBOL(ieee80211_free_hw);
Loading