forked from mirrors/linux
		
	nl80211/cfg80211: Extended Key ID support
Add support for IEEE 802.11-2016 "Extended Key ID for Individually Addressed Frames". Extend cfg80211 and nl80211 to allow pairwise keys to be installed for Rx only, enable Tx separately and allow Key ID 1 for pairwise keys. Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de> [use NLA_POLICY_RANGE() for NL80211_KEY_MODE] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
		
							parent
							
								
									092c4098f2
								
							
						
					
					
						commit
						6cdd3979a2
					
				
					 6 changed files with 102 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -485,6 +485,7 @@ struct vif_params {
 | 
			
		|||
 *	with the get_key() callback, must be in little endian,
 | 
			
		||||
 *	length given by @seq_len.
 | 
			
		||||
 * @seq_len: length of @seq.
 | 
			
		||||
 * @mode: key install mode (RX_TX, NO_TX or SET_TX)
 | 
			
		||||
 */
 | 
			
		||||
struct key_params {
 | 
			
		||||
	const u8 *key;
 | 
			
		||||
| 
						 | 
				
			
			@ -492,6 +493,7 @@ struct key_params {
 | 
			
		|||
	int key_len;
 | 
			
		||||
	int seq_len;
 | 
			
		||||
	u32 cipher;
 | 
			
		||||
	enum nl80211_key_mode mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4152,6 +4152,27 @@ enum nl80211_channel_type {
 | 
			
		|||
	NL80211_CHAN_HT40PLUS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum nl80211_key_mode - Key mode
 | 
			
		||||
 *
 | 
			
		||||
 * @NL80211_KEY_RX_TX: (Default)
 | 
			
		||||
 *	Key can be used for Rx and Tx immediately
 | 
			
		||||
 *
 | 
			
		||||
 * The following modes can only be selected for unicast keys and when the
 | 
			
		||||
 * driver supports @NL80211_EXT_FEATURE_EXT_KEY_ID:
 | 
			
		||||
 *
 | 
			
		||||
 * @NL80211_KEY_NO_TX: Only allowed in combination with @NL80211_CMD_NEW_KEY:
 | 
			
		||||
 *	Unicast key can only be used for Rx, Tx not allowed, yet
 | 
			
		||||
 * @NL80211_KEY_SET_TX: Only allowed in combination with @NL80211_CMD_SET_KEY:
 | 
			
		||||
 *	The unicast key identified by idx and mac is cleared for Tx and becomes
 | 
			
		||||
 *	the preferred Tx key for the station.
 | 
			
		||||
 */
 | 
			
		||||
enum nl80211_key_mode {
 | 
			
		||||
	NL80211_KEY_RX_TX,
 | 
			
		||||
	NL80211_KEY_NO_TX,
 | 
			
		||||
	NL80211_KEY_SET_TX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum nl80211_chan_width - channel width definitions
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -4395,6 +4416,9 @@ enum nl80211_key_default_types {
 | 
			
		|||
 * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
 | 
			
		||||
 *	attributes, specifying what a key should be set as default as.
 | 
			
		||||
 *	See &enum nl80211_key_default_types.
 | 
			
		||||
 * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
 | 
			
		||||
 *	Defaults to @NL80211_KEY_RX_TX.
 | 
			
		||||
 *
 | 
			
		||||
 * @__NL80211_KEY_AFTER_LAST: internal
 | 
			
		||||
 * @NL80211_KEY_MAX: highest key attribute
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -4408,6 +4432,7 @@ enum nl80211_key_attributes {
 | 
			
		|||
	NL80211_KEY_DEFAULT_MGMT,
 | 
			
		||||
	NL80211_KEY_TYPE,
 | 
			
		||||
	NL80211_KEY_DEFAULT_TYPES,
 | 
			
		||||
	NL80211_KEY_MODE,
 | 
			
		||||
 | 
			
		||||
	/* keep last */
 | 
			
		||||
	__NL80211_KEY_AFTER_LAST,
 | 
			
		||||
| 
						 | 
				
			
			@ -5353,6 +5378,8 @@ enum nl80211_feature_flags {
 | 
			
		|||
 *      able to rekey an in-use key correctly. Userspace must not rekey PTK keys
 | 
			
		||||
 *      if this flag is not set. Ignoring this can leak clear text packets and/or
 | 
			
		||||
 *      freeze the connection.
 | 
			
		||||
 * @NL80211_EXT_FEATURE_EXT_KEY_ID: Driver supports "Extended Key ID for
 | 
			
		||||
 *      Individually Addressed Frames" from IEEE802.11-2016.
 | 
			
		||||
 *
 | 
			
		||||
 * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
 | 
			
		||||
 *	fairness for transmitted packets and has enabled airtime fairness
 | 
			
		||||
| 
						 | 
				
			
			@ -5406,6 +5433,7 @@ enum nl80211_ext_feature_index {
 | 
			
		|||
	NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
 | 
			
		||||
	NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
 | 
			
		||||
	NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
 | 
			
		||||
	NL80211_EXT_FEATURE_EXT_KEY_ID,
 | 
			
		||||
 | 
			
		||||
	/* add new features before the definition below */
 | 
			
		||||
	NUM_NL80211_EXT_FEATURES,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -553,6 +553,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
 | 
			
		|||
	[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
 | 
			
		||||
	[NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
 | 
			
		||||
	[NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
 | 
			
		||||
	[NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* policy for the key default flags */
 | 
			
		||||
| 
						 | 
				
			
			@ -967,6 +968,9 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
 | 
			
		|||
		k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (tb[NL80211_KEY_MODE])
 | 
			
		||||
		k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3643,8 +3647,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 | 
			
		|||
	if (key.idx < 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	/* only support setting default key */
 | 
			
		||||
	if (!key.def && !key.defmgmt)
 | 
			
		||||
	/* Only support setting default key and
 | 
			
		||||
	 * Extended Key ID action NL80211_KEY_SET_TX.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!key.def && !key.defmgmt &&
 | 
			
		||||
	    !(key.p.mode == NL80211_KEY_SET_TX))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	wdev_lock(dev->ieee80211_ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -3668,7 +3675,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 | 
			
		|||
#ifdef CONFIG_CFG80211_WEXT
 | 
			
		||||
		dev->ieee80211_ptr->wext.default_key = key.idx;
 | 
			
		||||
#endif
 | 
			
		||||
	} else {
 | 
			
		||||
	} else if (key.defmgmt) {
 | 
			
		||||
		if (key.def_uni || !key.def_multi) {
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -3690,8 +3697,25 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 | 
			
		|||
#ifdef CONFIG_CFG80211_WEXT
 | 
			
		||||
		dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
 | 
			
		||||
#endif
 | 
			
		||||
	} else if (key.p.mode == NL80211_KEY_SET_TX &&
 | 
			
		||||
		   wiphy_ext_feature_isset(&rdev->wiphy,
 | 
			
		||||
					   NL80211_EXT_FEATURE_EXT_KEY_ID)) {
 | 
			
		||||
		u8 *mac_addr = NULL;
 | 
			
		||||
 | 
			
		||||
		if (info->attrs[NL80211_ATTR_MAC])
 | 
			
		||||
			mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 | 
			
		||||
 | 
			
		||||
		if (!mac_addr || key.idx < 0 || key.idx > 1) {
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = rdev_add_key(rdev, dev, key.idx,
 | 
			
		||||
				   NL80211_KEYTYPE_PAIRWISE,
 | 
			
		||||
				   mac_addr, &key.p);
 | 
			
		||||
	} else {
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 out:
 | 
			
		||||
	wdev_unlock(dev->ieee80211_ptr);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,7 +77,8 @@ static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
 | 
			
		|||
			       struct key_params *params)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
 | 
			
		||||
	trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise,
 | 
			
		||||
			   mac_addr, params->mode);
 | 
			
		||||
	ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise,
 | 
			
		||||
				  mac_addr, params);
 | 
			
		||||
	trace_rdev_return_int(&rdev->wiphy, ret);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -430,12 +430,6 @@ DECLARE_EVENT_CLASS(key_handle,
 | 
			
		|||
		  BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr))
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
DEFINE_EVENT(key_handle, rdev_add_key,
 | 
			
		||||
	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
 | 
			
		||||
		 bool pairwise, const u8 *mac_addr),
 | 
			
		||||
	TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
DEFINE_EVENT(key_handle, rdev_get_key,
 | 
			
		||||
	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
 | 
			
		||||
		 bool pairwise, const u8 *mac_addr),
 | 
			
		||||
| 
						 | 
				
			
			@ -448,6 +442,33 @@ DEFINE_EVENT(key_handle, rdev_del_key,
 | 
			
		|||
	TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
TRACE_EVENT(rdev_add_key,
 | 
			
		||||
	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
 | 
			
		||||
		 bool pairwise, const u8 *mac_addr, u8 mode),
 | 
			
		||||
	TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr, mode),
 | 
			
		||||
	TP_STRUCT__entry(
 | 
			
		||||
		WIPHY_ENTRY
 | 
			
		||||
		NETDEV_ENTRY
 | 
			
		||||
		MAC_ENTRY(mac_addr)
 | 
			
		||||
		__field(u8, key_index)
 | 
			
		||||
		__field(bool, pairwise)
 | 
			
		||||
		__field(u8, mode)
 | 
			
		||||
	),
 | 
			
		||||
	TP_fast_assign(
 | 
			
		||||
		WIPHY_ASSIGN;
 | 
			
		||||
		NETDEV_ASSIGN;
 | 
			
		||||
		MAC_ASSIGN(mac_addr, mac_addr);
 | 
			
		||||
		__entry->key_index = key_index;
 | 
			
		||||
		__entry->pairwise = pairwise;
 | 
			
		||||
		__entry->mode = mode;
 | 
			
		||||
	),
 | 
			
		||||
	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, "
 | 
			
		||||
		  "mode: %u, pairwise: %s, mac addr: " MAC_PR_FMT,
 | 
			
		||||
		  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
 | 
			
		||||
		  __entry->mode, BOOL_TO_STR(__entry->pairwise),
 | 
			
		||||
		  MAC_PR_ARG(mac_addr))
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
TRACE_EVENT(rdev_set_default_key,
 | 
			
		||||
	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
 | 
			
		||||
		 bool unicast, bool multicast),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -237,14 +237,23 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 | 
			
		|||
	case WLAN_CIPHER_SUITE_CCMP_256:
 | 
			
		||||
	case WLAN_CIPHER_SUITE_GCMP:
 | 
			
		||||
	case WLAN_CIPHER_SUITE_GCMP_256:
 | 
			
		||||
		/* Disallow pairwise keys with non-zero index unless it's WEP
 | 
			
		||||
		 * or a vendor specific cipher (because current deployments use
 | 
			
		||||
		 * pairwise WEP keys with non-zero indices and for vendor
 | 
			
		||||
		 * specific ciphers this should be validated in the driver or
 | 
			
		||||
		 * hardware level - but 802.11i clearly specifies to use zero)
 | 
			
		||||
		/* IEEE802.11-2016 allows only 0 and - when using Extended Key
 | 
			
		||||
		 * ID - 1 as index for pairwise keys.
 | 
			
		||||
		 * @NL80211_KEY_NO_TX is only allowed for pairwise keys when
 | 
			
		||||
		 * the driver supports Extended Key ID.
 | 
			
		||||
		 * @NL80211_KEY_SET_TX can't be set when installing and
 | 
			
		||||
		 * validating a key.
 | 
			
		||||
		 */
 | 
			
		||||
		if (pairwise && key_idx)
 | 
			
		||||
		if (params->mode == NL80211_KEY_NO_TX) {
 | 
			
		||||
			if (!wiphy_ext_feature_isset(&rdev->wiphy,
 | 
			
		||||
						     NL80211_EXT_FEATURE_EXT_KEY_ID))
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
			else if (!pairwise || key_idx < 0 || key_idx > 1)
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
		} else if ((pairwise && key_idx) ||
 | 
			
		||||
			   params->mode == NL80211_KEY_SET_TX) {
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case WLAN_CIPHER_SUITE_AES_CMAC:
 | 
			
		||||
	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue