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

Commit e8cbb4cb authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller
Browse files

mac80211: support adding/removing keys via cfg80211



This adds the necessary hooks to mac80211 to allow userspace
to edit keys with cfg80211 (through nl80211.)

Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 41ade00f
Loading
Loading
Loading
Loading
+91 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 * This file is GPLv2 as found in COPYING.
 */

#include <linux/ieee80211.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <net/net_namespace.h>
@@ -99,8 +100,98 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
	return 0;
}

static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
			     u8 key_idx, u8 *mac_addr,
			     struct key_params *params)
{
	struct ieee80211_sub_if_data *sdata;
	struct sta_info *sta = NULL;
	enum ieee80211_key_alg alg;
	int ret;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	switch (params->cipher) {
	case WLAN_CIPHER_SUITE_WEP40:
	case WLAN_CIPHER_SUITE_WEP104:
		alg = ALG_WEP;
		break;
	case WLAN_CIPHER_SUITE_TKIP:
		alg = ALG_TKIP;
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		alg = ALG_CCMP;
		break;
	default:
		return -EINVAL;
	}

	if (mac_addr) {
		sta = sta_info_get(sdata->local, mac_addr);
		if (!sta)
			return -ENOENT;
	}

	ret = 0;
	if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
				 params->key_len, params->key))
		ret = -ENOMEM;

	if (sta)
		sta_info_put(sta);

	return ret;
}

static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
			     u8 key_idx, u8 *mac_addr)
{
	struct ieee80211_sub_if_data *sdata;
	struct sta_info *sta;
	int ret;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	if (mac_addr) {
		sta = sta_info_get(sdata->local, mac_addr);
		if (!sta)
			return -ENOENT;

		ret = 0;
		if (sta->key)
			ieee80211_key_free(sta->key);
		else
			ret = -ENOENT;

		sta_info_put(sta);
		return ret;
	}

	if (!sdata->keys[key_idx])
		return -ENOENT;

	ieee80211_key_free(sdata->keys[key_idx]);

	return 0;
}

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

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	ieee80211_set_default_key(sdata, key_idx);

	return 0;
}

struct cfg80211_ops mac80211_config_ops = {
	.add_virtual_intf = ieee80211_add_iface,
	.del_virtual_intf = ieee80211_del_iface,
	.change_virtual_intf = ieee80211_change_iface,
	.add_key = ieee80211_add_key,
	.del_key = ieee80211_del_key,
	.set_default_key = ieee80211_config_default_key,
};