Commit e5473e80 authored by Jouni Malinen's avatar Jouni Malinen Committed by Johannes Berg
Browse files

mac80211: Support BIGTK configuration for Beacon protection



Extend mac80211 key configuration to support the new BIGTK with key
index values 6 and 7. Support for actually protecting Beacon frames
(adding the MME in AP mode and checking it in STA mode) is covered in
separate commits.

Signed-off-by: default avatarJouni Malinen <jouni@codeaurora.org>
Link: https://lore.kernel.org/r/20200222132548.20835-3-jouni@codeaurora.org


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 56be393f
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -568,7 +568,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
		if (pairwise && key_idx < NUM_DEFAULT_KEYS)
			key = rcu_dereference(sta->ptk[key_idx]);
		else if (!pairwise &&
			 key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
			 key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
			 NUM_DEFAULT_BEACON_KEYS)
			key = rcu_dereference(sta->gtk[key_idx]);
	} else
		key = rcu_dereference(sdata->keys[key_idx]);
@@ -680,6 +681,17 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
	return 0;
}

static int ieee80211_config_default_beacon_key(struct wiphy *wiphy,
					       struct net_device *dev,
					       u8 key_idx)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	ieee80211_set_default_beacon_key(sdata, key_idx);

	return 0;
}

void sta_set_rate_info_tx(struct sta_info *sta,
			  const struct ieee80211_tx_rate *rate,
			  struct rate_info *rinfo)
@@ -3885,6 +3897,7 @@ const struct cfg80211_ops mac80211_config_ops = {
	.get_key = ieee80211_get_key,
	.set_default_key = ieee80211_config_default_key,
	.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
	.set_default_beacon_key = ieee80211_config_default_beacon_key,
	.start_ap = ieee80211_start_ap,
	.change_beacon = ieee80211_change_beacon,
	.stop_ap = ieee80211_stop_ap,
+31 −0
Original line number Diff line number Diff line
@@ -433,6 +433,37 @@ void ieee80211_debugfs_key_remove_mgmt_default(struct ieee80211_sub_if_data *sda
	sdata->debugfs.default_mgmt_key = NULL;
}

void
ieee80211_debugfs_key_add_beacon_default(struct ieee80211_sub_if_data *sdata)
{
	char buf[50];
	struct ieee80211_key *key;

	if (!sdata->vif.debugfs_dir)
		return;

	key = key_mtx_dereference(sdata->local,
				  sdata->default_beacon_key);
	if (key) {
		sprintf(buf, "../keys/%d", key->debugfs.cnt);
		sdata->debugfs.default_beacon_key =
			debugfs_create_symlink("default_beacon_key",
					       sdata->vif.debugfs_dir, buf);
	} else {
		ieee80211_debugfs_key_remove_beacon_default(sdata);
	}
}

void
ieee80211_debugfs_key_remove_beacon_default(struct ieee80211_sub_if_data *sdata)
{
	if (!sdata)
		return;

	debugfs_remove(sdata->debugfs.default_beacon_key);
	sdata->debugfs.default_beacon_key = NULL;
}

void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
				   struct sta_info *sta)
{
+10 −0
Original line number Diff line number Diff line
@@ -10,6 +10,10 @@ void ieee80211_debugfs_key_add_mgmt_default(
	struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_remove_mgmt_default(
	struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_add_beacon_default(
	struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_remove_beacon_default(
	struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
				   struct sta_info *sta);
#else
@@ -26,6 +30,12 @@ static inline void ieee80211_debugfs_key_add_mgmt_default(
static inline void ieee80211_debugfs_key_remove_mgmt_default(
	struct ieee80211_sub_if_data *sdata)
{}
static inline void ieee80211_debugfs_key_add_beacon_default(
	struct ieee80211_sub_if_data *sdata)
{}
static inline void ieee80211_debugfs_key_remove_beacon_default(
	struct ieee80211_sub_if_data *sdata)
{}
static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
						 struct sta_info *sta)
{}
+5 −1
Original line number Diff line number Diff line
@@ -901,10 +901,13 @@ struct ieee80211_sub_if_data {
	/* bit field of ACM bits (BIT(802.1D tag)) */
	u8 wmm_acm;

	struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
	struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS +
					 NUM_DEFAULT_MGMT_KEYS +
					 NUM_DEFAULT_BEACON_KEYS];
	struct ieee80211_key __rcu *default_unicast_key;
	struct ieee80211_key __rcu *default_multicast_key;
	struct ieee80211_key __rcu *default_mgmt_key;
	struct ieee80211_key __rcu *default_beacon_key;

	u16 sequence_number;
	__be16 control_port_protocol;
@@ -978,6 +981,7 @@ struct ieee80211_sub_if_data {
		struct dentry *default_unicast_key;
		struct dentry *default_multicast_key;
		struct dentry *default_mgmt_key;
		struct dentry *default_beacon_key;
	} debugfs;
#endif

+38 −2
Original line number Diff line number Diff line
@@ -407,6 +407,31 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
	mutex_unlock(&sdata->local->key_mtx);
}

static void
__ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata, int idx)
{
	struct ieee80211_key *key = NULL;

	assert_key_lock(sdata->local);

	if (idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS &&
	    idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
	    NUM_DEFAULT_BEACON_KEYS)
		key = key_mtx_dereference(sdata->local, sdata->keys[idx]);

	rcu_assign_pointer(sdata->default_beacon_key, key);

	ieee80211_debugfs_key_update_default(sdata);
}

void ieee80211_set_default_beacon_key(struct ieee80211_sub_if_data *sdata,
				      int idx)
{
	mutex_lock(&sdata->local->key_mtx);
	__ieee80211_set_default_beacon_key(sdata, idx);
	mutex_unlock(&sdata->local->key_mtx);
}

static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
				  struct sta_info *sta,
				  bool pairwise,
@@ -415,7 +440,7 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
{
	int idx;
	int ret = 0;
	bool defunikey, defmultikey, defmgmtkey;
	bool defunikey, defmultikey, defmgmtkey, defbeaconkey;

	/* caller must provide at least one old/new */
	if (WARN_ON(!new && !old))
@@ -480,6 +505,9 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
		defmgmtkey = old &&
			old == key_mtx_dereference(sdata->local,
						sdata->default_mgmt_key);
		defbeaconkey = old &&
			old == key_mtx_dereference(sdata->local,
						   sdata->default_beacon_key);

		if (defunikey && !new)
			__ieee80211_set_default_key(sdata, -1, true, false);
@@ -487,6 +515,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
			__ieee80211_set_default_key(sdata, -1, false, true);
		if (defmgmtkey && !new)
			__ieee80211_set_default_mgmt_key(sdata, -1);
		if (defbeaconkey && !new)
			__ieee80211_set_default_beacon_key(sdata, -1);

		rcu_assign_pointer(sdata->keys[idx], new);
		if (defunikey && new)
@@ -498,6 +528,9 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
		if (defmgmtkey && new)
			__ieee80211_set_default_mgmt_key(sdata,
							 new->conf.keyidx);
		if (defbeaconkey && new)
			__ieee80211_set_default_beacon_key(sdata,
							   new->conf.keyidx);
	}

	if (old)
@@ -515,7 +548,9 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
	struct ieee80211_key *key;
	int i, j, err;

	if (WARN_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS))
	if (WARN_ON(idx < 0 ||
		    idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
		    NUM_DEFAULT_BEACON_KEYS))
		return ERR_PTR(-EINVAL);

	key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
@@ -978,6 +1013,7 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
	sdata->crypto_tx_tailroom_pending_dec = 0;

	ieee80211_debugfs_key_remove_mgmt_default(sdata);
	ieee80211_debugfs_key_remove_beacon_default(sdata);

	list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
		ieee80211_key_replace(key->sdata, key->sta,
Loading