mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	cfg80211/mac80211: allow per-station GTKs
This adds API to allow adding per-station GTKs, updates mac80211 to support it, and also allows drivers to remove a key from hwaccel again when this may be necessary due to multiple GTKs. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
		
							parent
							
								
									53f73c09d6
								
							
						
					
					
						commit
						e31b82136d
					
				
					 20 changed files with 293 additions and 109 deletions
				
			
		| 
						 | 
					@ -161,7 +161,7 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
					static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
				
			||||||
				u8 key_index, const u8 *mac_addr,
 | 
									u8 key_index, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
				struct key_params *params)
 | 
									struct key_params *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct iwm_priv *iwm = ndev_to_iwm(ndev);
 | 
						struct iwm_priv *iwm = ndev_to_iwm(ndev);
 | 
				
			||||||
| 
						 | 
					@ -181,7 +181,8 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
					static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
				
			||||||
				u8 key_index, const u8 *mac_addr, void *cookie,
 | 
									u8 key_index, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
 | 
									void *cookie,
 | 
				
			||||||
				void (*callback)(void *cookie,
 | 
									void (*callback)(void *cookie,
 | 
				
			||||||
						 struct key_params*))
 | 
											 struct key_params*))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -206,7 +207,7 @@ static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
					static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
 | 
				
			||||||
				u8 key_index, const u8 *mac_addr)
 | 
									u8 key_index, bool pairwise, const u8 *mac_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct iwm_priv *iwm = ndev_to_iwm(ndev);
 | 
						struct iwm_priv *iwm = ndev_to_iwm(ndev);
 | 
				
			||||||
	struct iwm_key *key = &iwm->keys[key_index];
 | 
						struct iwm_key *key = &iwm->keys[key_index];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1438,7 +1438,7 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
					static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
			   u8 idx, const u8 *mac_addr,
 | 
								   u8 idx, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
			   struct key_params *params)
 | 
								   struct key_params *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct lbs_private *priv = wiphy_priv(wiphy);
 | 
						struct lbs_private *priv = wiphy_priv(wiphy);
 | 
				
			||||||
| 
						 | 
					@ -1498,7 +1498,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
					static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
			   u8 key_index, const u8 *mac_addr)
 | 
								   u8 key_index, bool pairwise, const u8 *mac_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lbs_deb_enter(LBS_DEB_CFG80211);
 | 
						lbs_deb_enter(LBS_DEB_CFG80211);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -540,11 +540,11 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
	struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
 | 
						struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
					static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
					u8 key_index, const u8 *mac_addr,
 | 
								 u8 key_index, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
					struct key_params *params);
 | 
								 struct key_params *params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
					static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
					u8 key_index, const u8 *mac_addr);
 | 
								 u8 key_index, bool pairwise, const u8 *mac_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
					static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
								u8 key_index);
 | 
													u8 key_index);
 | 
				
			||||||
| 
						 | 
					@ -2308,8 +2308,8 @@ static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
					static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
					u8 key_index, const u8 *mac_addr,
 | 
								 u8 key_index, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
					struct key_params *params)
 | 
								 struct key_params *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rndis_wlan_private *priv = wiphy_priv(wiphy);
 | 
						struct rndis_wlan_private *priv = wiphy_priv(wiphy);
 | 
				
			||||||
	struct usbnet *usbdev = priv->usbdev;
 | 
						struct usbnet *usbdev = priv->usbdev;
 | 
				
			||||||
| 
						 | 
					@ -2344,7 +2344,7 @@ static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
					static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
					u8 key_index, const u8 *mac_addr)
 | 
								 u8 key_index, bool pairwise, const u8 *mac_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rndis_wlan_private *priv = wiphy_priv(wiphy);
 | 
						struct rndis_wlan_private *priv = wiphy_priv(wiphy);
 | 
				
			||||||
	struct usbnet *usbdev = priv->usbdev;
 | 
						struct usbnet *usbdev = priv->usbdev;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -801,6 +801,9 @@ enum nl80211_commands {
 | 
				
			||||||
 *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
 | 
					 *      This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
 | 
				
			||||||
 *      for non-automatic settings.
 | 
					 *      for non-automatic settings.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
 | 
				
			||||||
 | 
					 *	means support for per-station GTKs.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @NL80211_ATTR_MAX: highest attribute number currently defined
 | 
					 * @NL80211_ATTR_MAX: highest attribute number currently defined
 | 
				
			||||||
 * @__NL80211_ATTR_AFTER_LAST: internal use
 | 
					 * @__NL80211_ATTR_AFTER_LAST: internal use
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -968,6 +971,8 @@ enum nl80211_attrs {
 | 
				
			||||||
	NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
 | 
						NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
 | 
				
			||||||
	NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
 | 
						NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NL80211_ATTR_SUPPORT_IBSS_RSN,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* add attributes here, update the policy in nl80211.c */
 | 
						/* add attributes here, update the policy in nl80211.c */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__NL80211_ATTR_AFTER_LAST,
 | 
						__NL80211_ATTR_AFTER_LAST,
 | 
				
			||||||
| 
						 | 
					@ -1659,11 +1664,14 @@ enum nl80211_auth_type {
 | 
				
			||||||
 * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
 | 
					 * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
 | 
				
			||||||
 * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
 | 
					 * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
 | 
				
			||||||
 * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
 | 
					 * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
 | 
				
			||||||
 | 
					 * @NUM_NL80211_KEYTYPES: number of defined key types
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum nl80211_key_type {
 | 
					enum nl80211_key_type {
 | 
				
			||||||
	NL80211_KEYTYPE_GROUP,
 | 
						NL80211_KEYTYPE_GROUP,
 | 
				
			||||||
	NL80211_KEYTYPE_PAIRWISE,
 | 
						NL80211_KEYTYPE_PAIRWISE,
 | 
				
			||||||
	NL80211_KEYTYPE_PEERKEY,
 | 
						NL80211_KEYTYPE_PEERKEY,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NUM_NL80211_KEYTYPES
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -1694,6 +1702,9 @@ enum nl80211_wpa_versions {
 | 
				
			||||||
 *	CCMP keys, each six bytes in little endian
 | 
					 *	CCMP keys, each six bytes in little endian
 | 
				
			||||||
 * @NL80211_KEY_DEFAULT: flag indicating default key
 | 
					 * @NL80211_KEY_DEFAULT: flag indicating default key
 | 
				
			||||||
 * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
 | 
					 * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
 | 
				
			||||||
 | 
					 * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
 | 
				
			||||||
 | 
					 *	specified the default depends on whether a MAC address was
 | 
				
			||||||
 | 
					 *	given with the command using the key or not (u32)
 | 
				
			||||||
 * @__NL80211_KEY_AFTER_LAST: internal
 | 
					 * @__NL80211_KEY_AFTER_LAST: internal
 | 
				
			||||||
 * @NL80211_KEY_MAX: highest key attribute
 | 
					 * @NL80211_KEY_MAX: highest key attribute
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -1705,6 +1716,7 @@ enum nl80211_key_attributes {
 | 
				
			||||||
	NL80211_KEY_SEQ,
 | 
						NL80211_KEY_SEQ,
 | 
				
			||||||
	NL80211_KEY_DEFAULT,
 | 
						NL80211_KEY_DEFAULT,
 | 
				
			||||||
	NL80211_KEY_DEFAULT_MGMT,
 | 
						NL80211_KEY_DEFAULT_MGMT,
 | 
				
			||||||
 | 
						NL80211_KEY_TYPE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* keep last */
 | 
						/* keep last */
 | 
				
			||||||
	__NL80211_KEY_AFTER_LAST,
 | 
						__NL80211_KEY_AFTER_LAST,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1130,13 +1130,14 @@ struct cfg80211_ops {
 | 
				
			||||||
				       struct vif_params *params);
 | 
									       struct vif_params *params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int	(*add_key)(struct wiphy *wiphy, struct net_device *netdev,
 | 
						int	(*add_key)(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
			   u8 key_index, const u8 *mac_addr,
 | 
								   u8 key_index, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
			   struct key_params *params);
 | 
								   struct key_params *params);
 | 
				
			||||||
	int	(*get_key)(struct wiphy *wiphy, struct net_device *netdev,
 | 
						int	(*get_key)(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
			   u8 key_index, const u8 *mac_addr, void *cookie,
 | 
								   u8 key_index, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
 | 
								   void *cookie,
 | 
				
			||||||
			   void (*callback)(void *cookie, struct key_params*));
 | 
								   void (*callback)(void *cookie, struct key_params*));
 | 
				
			||||||
	int	(*del_key)(struct wiphy *wiphy, struct net_device *netdev,
 | 
						int	(*del_key)(struct wiphy *wiphy, struct net_device *netdev,
 | 
				
			||||||
			   u8 key_index, const u8 *mac_addr);
 | 
								   u8 key_index, bool pairwise, const u8 *mac_addr);
 | 
				
			||||||
	int	(*set_default_key)(struct wiphy *wiphy,
 | 
						int	(*set_default_key)(struct wiphy *wiphy,
 | 
				
			||||||
				   struct net_device *netdev,
 | 
									   struct net_device *netdev,
 | 
				
			||||||
				   u8 key_index);
 | 
									   u8 key_index);
 | 
				
			||||||
| 
						 | 
					@ -1304,6 +1305,7 @@ struct cfg80211_ops {
 | 
				
			||||||
 * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
 | 
					 * @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
 | 
				
			||||||
 *	control port protocol ethertype. The device also honours the
 | 
					 *	control port protocol ethertype. The device also honours the
 | 
				
			||||||
 *	control_port_no_encrypt flag.
 | 
					 *	control_port_no_encrypt flag.
 | 
				
			||||||
 | 
					 * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum wiphy_flags {
 | 
					enum wiphy_flags {
 | 
				
			||||||
	WIPHY_FLAG_CUSTOM_REGULATORY		= BIT(0),
 | 
						WIPHY_FLAG_CUSTOM_REGULATORY		= BIT(0),
 | 
				
			||||||
| 
						 | 
					@ -1314,6 +1316,7 @@ enum wiphy_flags {
 | 
				
			||||||
	WIPHY_FLAG_4ADDR_AP			= BIT(5),
 | 
						WIPHY_FLAG_4ADDR_AP			= BIT(5),
 | 
				
			||||||
	WIPHY_FLAG_4ADDR_STATION		= BIT(6),
 | 
						WIPHY_FLAG_4ADDR_STATION		= BIT(6),
 | 
				
			||||||
	WIPHY_FLAG_CONTROL_PORT_PROTOCOL	= BIT(7),
 | 
						WIPHY_FLAG_CONTROL_PORT_PROTOCOL	= BIT(7),
 | 
				
			||||||
 | 
						WIPHY_FLAG_IBSS_RSN			= BIT(7),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mac_address {
 | 
					struct mac_address {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1041,6 +1041,13 @@ enum ieee80211_tkip_key_type {
 | 
				
			||||||
 * @IEEE80211_HW_NEED_DTIM_PERIOD:
 | 
					 * @IEEE80211_HW_NEED_DTIM_PERIOD:
 | 
				
			||||||
 *	This device needs to know the DTIM period for the BSS before
 | 
					 *	This device needs to know the DTIM period for the BSS before
 | 
				
			||||||
 *	associating.
 | 
					 *	associating.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports
 | 
				
			||||||
 | 
					 *	per-station GTKs as used by IBSS RSN or during fast transition. If
 | 
				
			||||||
 | 
					 *	the device doesn't support per-station GTKs, but can be asked not
 | 
				
			||||||
 | 
					 *	to decrypt group addressed frames, then IBSS RSN support is still
 | 
				
			||||||
 | 
					 *	possible but software crypto will be used. Advertise the wiphy flag
 | 
				
			||||||
 | 
					 *	only in that case.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
enum ieee80211_hw_flags {
 | 
					enum ieee80211_hw_flags {
 | 
				
			||||||
	IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
 | 
						IEEE80211_HW_HAS_RATE_CONTROL			= 1<<0,
 | 
				
			||||||
| 
						 | 
					@ -1064,6 +1071,7 @@ enum ieee80211_hw_flags {
 | 
				
			||||||
	IEEE80211_HW_REPORTS_TX_ACK_STATUS		= 1<<18,
 | 
						IEEE80211_HW_REPORTS_TX_ACK_STATUS		= 1<<18,
 | 
				
			||||||
	IEEE80211_HW_CONNECTION_MONITOR			= 1<<19,
 | 
						IEEE80211_HW_CONNECTION_MONITOR			= 1<<19,
 | 
				
			||||||
	IEEE80211_HW_SUPPORTS_CQM_RSSI			= 1<<20,
 | 
						IEEE80211_HW_SUPPORTS_CQM_RSSI			= 1<<20,
 | 
				
			||||||
 | 
						IEEE80211_HW_SUPPORTS_PER_STA_GTK		= 1<<21,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -2582,6 +2590,22 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
 | 
				
			||||||
void ieee80211_request_smps(struct ieee80211_vif *vif,
 | 
					void ieee80211_request_smps(struct ieee80211_vif *vif,
 | 
				
			||||||
			    enum ieee80211_smps_mode smps_mode);
 | 
								    enum ieee80211_smps_mode smps_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ieee80211_key_removed - disable hw acceleration for key
 | 
				
			||||||
 | 
					 * @key_conf: The key hw acceleration should be disabled for
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This allows drivers to indicate that the given key has been
 | 
				
			||||||
 | 
					 * removed from hardware acceleration, due to a new key that
 | 
				
			||||||
 | 
					 * was added. Don't use this if the key can continue to be used
 | 
				
			||||||
 | 
					 * for TX, if the key restriction is on RX only it is permitted
 | 
				
			||||||
 | 
					 * to keep the key for TX only and not call this function.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Due to locking constraints, it may only be called during
 | 
				
			||||||
 | 
					 * @set_key. This function must be allowed to sleep, and the
 | 
				
			||||||
 | 
					 * key it tries to disable may still be used until it returns.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Rate control API */
 | 
					/* Rate control API */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,7 +103,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 | 
					static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
			     u8 key_idx, const u8 *mac_addr,
 | 
								     u8 key_idx, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
			     struct key_params *params)
 | 
								     struct key_params *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | 
						struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | 
				
			||||||
| 
						 | 
					@ -131,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
	if (IS_ERR(key))
 | 
						if (IS_ERR(key))
 | 
				
			||||||
		return PTR_ERR(key);
 | 
							return PTR_ERR(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pairwise)
 | 
				
			||||||
 | 
							key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&sdata->local->sta_mtx);
 | 
						mutex_lock(&sdata->local->sta_mtx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mac_addr) {
 | 
						if (mac_addr) {
 | 
				
			||||||
| 
						 | 
					@ -153,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 | 
					static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
			     u8 key_idx, const u8 *mac_addr)
 | 
								     u8 key_idx, bool pairwise, const u8 *mac_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ieee80211_sub_if_data *sdata;
 | 
						struct ieee80211_sub_if_data *sdata;
 | 
				
			||||||
	struct sta_info *sta;
 | 
						struct sta_info *sta;
 | 
				
			||||||
| 
						 | 
					@ -170,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
		if (!sta)
 | 
							if (!sta)
 | 
				
			||||||
			goto out_unlock;
 | 
								goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sta->key) {
 | 
							if (pairwise) {
 | 
				
			||||||
			ieee80211_key_free(sdata->local, sta->key);
 | 
								if (sta->ptk) {
 | 
				
			||||||
			WARN_ON(sta->key);
 | 
									ieee80211_key_free(sdata->local, sta->ptk);
 | 
				
			||||||
			ret = 0;
 | 
									ret = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (sta->gtk[key_idx]) {
 | 
				
			||||||
 | 
									ieee80211_key_free(sdata->local,
 | 
				
			||||||
 | 
											   sta->gtk[key_idx]);
 | 
				
			||||||
 | 
									ret = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		goto out_unlock;
 | 
							goto out_unlock;
 | 
				
			||||||
| 
						 | 
					@ -195,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 | 
					static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
			     u8 key_idx, const u8 *mac_addr, void *cookie,
 | 
								     u8 key_idx, bool pairwise, const u8 *mac_addr,
 | 
				
			||||||
 | 
								     void *cookie,
 | 
				
			||||||
			     void (*callback)(void *cookie,
 | 
								     void (*callback)(void *cookie,
 | 
				
			||||||
					      struct key_params *params))
 | 
										      struct key_params *params))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -203,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
	struct sta_info *sta = NULL;
 | 
						struct sta_info *sta = NULL;
 | 
				
			||||||
	u8 seq[6] = {0};
 | 
						u8 seq[6] = {0};
 | 
				
			||||||
	struct key_params params;
 | 
						struct key_params params;
 | 
				
			||||||
	struct ieee80211_key *key;
 | 
						struct ieee80211_key *key = NULL;
 | 
				
			||||||
	u32 iv32;
 | 
						u32 iv32;
 | 
				
			||||||
	u16 iv16;
 | 
						u16 iv16;
 | 
				
			||||||
	int err = -ENOENT;
 | 
						int err = -ENOENT;
 | 
				
			||||||
| 
						 | 
					@ -217,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 | 
				
			||||||
		if (!sta)
 | 
							if (!sta)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		key = sta->key;
 | 
							if (pairwise)
 | 
				
			||||||
 | 
								key = sta->ptk;
 | 
				
			||||||
 | 
							else if (key_idx < NUM_DEFAULT_KEYS)
 | 
				
			||||||
 | 
								key = sta->gtk[key_idx];
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		key = sdata->keys[key_idx];
 | 
							key = sdata->keys[key_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -549,8 +549,6 @@ struct ieee80211_sub_if_data {
 | 
				
			||||||
	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 | 
						struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
 | 
				
			||||||
	unsigned int fragment_next;
 | 
						unsigned int fragment_next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NUM_DEFAULT_KEYS 4
 | 
					 | 
				
			||||||
#define NUM_DEFAULT_MGMT_KEYS 2
 | 
					 | 
				
			||||||
	struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
 | 
						struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
 | 
				
			||||||
	struct ieee80211_key *default_key;
 | 
						struct ieee80211_key *default_key;
 | 
				
			||||||
	struct ieee80211_key *default_mgmt_key;
 | 
						struct ieee80211_key *default_mgmt_key;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,15 +68,21 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	might_sleep();
 | 
						might_sleep();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!key->local->ops->set_key) {
 | 
						if (!key->local->ops->set_key)
 | 
				
			||||||
		ret = -EOPNOTSUPP;
 | 
					 | 
				
			||||||
		goto out_unsupported;
 | 
							goto out_unsupported;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert_key_lock(key->local);
 | 
						assert_key_lock(key->local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sta = get_sta_for_key(key);
 | 
						sta = get_sta_for_key(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If this is a per-STA GTK, check if it
 | 
				
			||||||
 | 
						 * is supported; if not, return.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
 | 
				
			||||||
 | 
						    !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
 | 
				
			||||||
 | 
							goto out_unsupported;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdata = key->sdata;
 | 
						sdata = key->sdata;
 | 
				
			||||||
	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 | 
						if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 | 
				
			||||||
		sdata = container_of(sdata->bss,
 | 
							sdata = container_of(sdata->bss,
 | 
				
			||||||
| 
						 | 
					@ -85,31 +91,28 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 | 
						ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ret)
 | 
						if (!ret) {
 | 
				
			||||||
		key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 | 
							key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
 | 
						if (ret != -ENOSPC && ret != -EOPNOTSUPP)
 | 
				
			||||||
		wiphy_err(key->local->hw.wiphy,
 | 
							wiphy_err(key->local->hw.wiphy,
 | 
				
			||||||
			  "failed to set key (%d, %pM) to hardware (%d)\n",
 | 
								  "failed to set key (%d, %pM) to hardware (%d)\n",
 | 
				
			||||||
			  key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 | 
								  key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_unsupported:
 | 
					 out_unsupported:
 | 
				
			||||||
	if (ret) {
 | 
						switch (key->conf.cipher) {
 | 
				
			||||||
		switch (key->conf.cipher) {
 | 
						case WLAN_CIPHER_SUITE_WEP40:
 | 
				
			||||||
		case WLAN_CIPHER_SUITE_WEP40:
 | 
						case WLAN_CIPHER_SUITE_WEP104:
 | 
				
			||||||
		case WLAN_CIPHER_SUITE_WEP104:
 | 
						case WLAN_CIPHER_SUITE_TKIP:
 | 
				
			||||||
		case WLAN_CIPHER_SUITE_TKIP:
 | 
						case WLAN_CIPHER_SUITE_CCMP:
 | 
				
			||||||
		case WLAN_CIPHER_SUITE_CCMP:
 | 
						case WLAN_CIPHER_SUITE_AES_CMAC:
 | 
				
			||||||
		case WLAN_CIPHER_SUITE_AES_CMAC:
 | 
							/* all of these we can do in software */
 | 
				
			||||||
			/* all of these we can do in software */
 | 
							return 0;
 | 
				
			||||||
			ret = 0;
 | 
						default:
 | 
				
			||||||
			break;
 | 
							return -EINVAL;
 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			ret = -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 | 
					static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 | 
				
			||||||
| 
						 | 
					@ -147,6 +150,26 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 | 
				
			||||||
	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 | 
						key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ieee80211_key *key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key = container_of(key_conf, struct ieee80211_key, conf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						might_sleep();
 | 
				
			||||||
 | 
						assert_key_lock(key->local);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Flush TX path to avoid attempts to use this key
 | 
				
			||||||
 | 
						 * after this function returns. Until then, drivers
 | 
				
			||||||
 | 
						 * must be prepared to handle the key.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						synchronize_rcu();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(ieee80211_key_removed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
 | 
					static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
					int idx)
 | 
										int idx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -202,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
 | 
					static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
				    struct sta_info *sta,
 | 
									    struct sta_info *sta,
 | 
				
			||||||
 | 
									    bool pairwise,
 | 
				
			||||||
				    struct ieee80211_key *old,
 | 
									    struct ieee80211_key *old,
 | 
				
			||||||
				    struct ieee80211_key *new)
 | 
									    struct ieee80211_key *new)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -210,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
 | 
				
			||||||
	if (new)
 | 
						if (new)
 | 
				
			||||||
		list_add(&new->list, &sdata->key_list);
 | 
							list_add(&new->list, &sdata->key_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sta) {
 | 
						if (sta && pairwise) {
 | 
				
			||||||
		rcu_assign_pointer(sta->key, new);
 | 
							rcu_assign_pointer(sta->ptk, new);
 | 
				
			||||||
 | 
						} else if (sta) {
 | 
				
			||||||
 | 
							if (old)
 | 
				
			||||||
 | 
								idx = old->conf.keyidx;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								idx = new->conf.keyidx;
 | 
				
			||||||
 | 
							rcu_assign_pointer(sta->gtk[idx], new);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
 | 
							WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -355,6 +385,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ieee80211_key *old_key;
 | 
						struct ieee80211_key *old_key;
 | 
				
			||||||
	int idx, ret;
 | 
						int idx, ret;
 | 
				
			||||||
 | 
						bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(!sdata);
 | 
						BUG_ON(!sdata);
 | 
				
			||||||
	BUG_ON(!key);
 | 
						BUG_ON(!key);
 | 
				
			||||||
| 
						 | 
					@ -371,13 +402,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (test_sta_flags(sta, WLAN_STA_WME))
 | 
							if (test_sta_flags(sta, WLAN_STA_WME))
 | 
				
			||||||
			key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
 | 
								key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * This key is for a specific sta interface,
 | 
					 | 
				
			||||||
		 * inform the driver that it should try to store
 | 
					 | 
				
			||||||
		 * this key as pairwise key.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 | 
							if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 | 
				
			||||||
			struct sta_info *ap;
 | 
								struct sta_info *ap;
 | 
				
			||||||
| 
						 | 
					@ -399,12 +423,14 @@ int ieee80211_key_link(struct ieee80211_key *key,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&sdata->local->key_mtx);
 | 
						mutex_lock(&sdata->local->key_mtx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sta)
 | 
						if (sta && pairwise)
 | 
				
			||||||
		old_key = sta->key;
 | 
							old_key = sta->ptk;
 | 
				
			||||||
 | 
						else if (sta)
 | 
				
			||||||
 | 
							old_key = sta->gtk[idx];
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		old_key = sdata->keys[idx];
 | 
							old_key = sdata->keys[idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__ieee80211_key_replace(sdata, sta, old_key, key);
 | 
						__ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
 | 
				
			||||||
	__ieee80211_key_destroy(old_key);
 | 
						__ieee80211_key_destroy(old_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ieee80211_debugfs_key_add(key);
 | 
						ieee80211_debugfs_key_add(key);
 | 
				
			||||||
| 
						 | 
					@ -423,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (key->sdata)
 | 
						if (key->sdata)
 | 
				
			||||||
		__ieee80211_key_replace(key->sdata, key->sta,
 | 
							__ieee80211_key_replace(key->sdata, key->sta,
 | 
				
			||||||
					key, NULL);
 | 
									key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
 | 
				
			||||||
 | 
									key, NULL);
 | 
				
			||||||
	__ieee80211_key_destroy(key);
 | 
						__ieee80211_key_destroy(key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,9 @@
 | 
				
			||||||
#include <linux/rcupdate.h>
 | 
					#include <linux/rcupdate.h>
 | 
				
			||||||
#include <net/mac80211.h>
 | 
					#include <net/mac80211.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NUM_DEFAULT_KEYS 4
 | 
				
			||||||
 | 
					#define NUM_DEFAULT_MGMT_KEYS 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WEP_IV_LEN		4
 | 
					#define WEP_IV_LEN		4
 | 
				
			||||||
#define WEP_ICV_LEN		4
 | 
					#define WEP_ICV_LEN		4
 | 
				
			||||||
#define ALG_TKIP_KEY_LEN	32
 | 
					#define ALG_TKIP_KEY_LEN	32
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -846,7 +846,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 | 
				
			||||||
	int keyidx;
 | 
						int keyidx;
 | 
				
			||||||
	int hdrlen;
 | 
						int hdrlen;
 | 
				
			||||||
	ieee80211_rx_result result = RX_DROP_UNUSABLE;
 | 
						ieee80211_rx_result result = RX_DROP_UNUSABLE;
 | 
				
			||||||
	struct ieee80211_key *stakey = NULL;
 | 
						struct ieee80211_key *sta_ptk = NULL;
 | 
				
			||||||
	int mmie_keyidx = -1;
 | 
						int mmie_keyidx = -1;
 | 
				
			||||||
	__le16 fc;
 | 
						__le16 fc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -888,15 +888,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 | 
				
			||||||
	rx->key = NULL;
 | 
						rx->key = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rx->sta)
 | 
						if (rx->sta)
 | 
				
			||||||
		stakey = rcu_dereference(rx->sta->key);
 | 
							sta_ptk = rcu_dereference(rx->sta->ptk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fc = hdr->frame_control;
 | 
						fc = hdr->frame_control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ieee80211_has_protected(fc))
 | 
						if (!ieee80211_has_protected(fc))
 | 
				
			||||||
		mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
 | 
							mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
 | 
						if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
 | 
				
			||||||
		rx->key = stakey;
 | 
							rx->key = sta_ptk;
 | 
				
			||||||
		if ((status->flag & RX_FLAG_DECRYPTED) &&
 | 
							if ((status->flag & RX_FLAG_DECRYPTED) &&
 | 
				
			||||||
		    (status->flag & RX_FLAG_IV_STRIPPED))
 | 
							    (status->flag & RX_FLAG_IV_STRIPPED))
 | 
				
			||||||
			return RX_CONTINUE;
 | 
								return RX_CONTINUE;
 | 
				
			||||||
| 
						 | 
					@ -912,7 +912,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 | 
				
			||||||
		if (mmie_keyidx < NUM_DEFAULT_KEYS ||
 | 
							if (mmie_keyidx < NUM_DEFAULT_KEYS ||
 | 
				
			||||||
		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
 | 
							    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
 | 
				
			||||||
			return RX_DROP_MONITOR; /* unexpected BIP keyidx */
 | 
								return RX_DROP_MONITOR; /* unexpected BIP keyidx */
 | 
				
			||||||
		rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
 | 
							if (rx->sta)
 | 
				
			||||||
 | 
								rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
 | 
				
			||||||
 | 
							if (!rx->key)
 | 
				
			||||||
 | 
								rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
 | 
				
			||||||
	} else if (!ieee80211_has_protected(fc)) {
 | 
						} else if (!ieee80211_has_protected(fc)) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * The frame was not protected, so skip decryption. However, we
 | 
							 * The frame was not protected, so skip decryption. However, we
 | 
				
			||||||
| 
						 | 
					@ -955,17 +958,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 | 
				
			||||||
		skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
 | 
							skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
 | 
				
			||||||
		keyidx = keyid >> 6;
 | 
							keyidx = keyid >> 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
 | 
							/* check per-station GTK first, if multicast packet */
 | 
				
			||||||
 | 
							if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
 | 
				
			||||||
 | 
								rx->key = rcu_dereference(rx->sta->gtk[keyidx]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/* if not found, try default key */
 | 
				
			||||||
		 * RSNA-protected unicast frames should always be sent with
 | 
							if (!rx->key) {
 | 
				
			||||||
		 * pairwise or station-to-station keys, but for WEP we allow
 | 
								rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
 | 
				
			||||||
		 * using a key index as well.
 | 
					
 | 
				
			||||||
		 */
 | 
								/*
 | 
				
			||||||
		if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
 | 
								 * RSNA-protected unicast frames should always be
 | 
				
			||||||
		    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
 | 
								 * sent with pairwise or station-to-station keys,
 | 
				
			||||||
		    !is_multicast_ether_addr(hdr->addr1))
 | 
								 * but for WEP we allow using a key index as well.
 | 
				
			||||||
			rx->key = NULL;
 | 
								 */
 | 
				
			||||||
 | 
								if (rx->key &&
 | 
				
			||||||
 | 
								    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
 | 
				
			||||||
 | 
								    rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
 | 
				
			||||||
 | 
								    !is_multicast_ether_addr(hdr->addr1))
 | 
				
			||||||
 | 
									rx->key = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rx->key) {
 | 
						if (rx->key) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -616,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
 | 
				
			||||||
	struct ieee80211_sub_if_data *sdata;
 | 
						struct ieee80211_sub_if_data *sdata;
 | 
				
			||||||
	struct sk_buff *skb;
 | 
						struct sk_buff *skb;
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
	int ret;
 | 
						int ret, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	might_sleep();
 | 
						might_sleep();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -644,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sta->key) {
 | 
						for (i = 0; i < NUM_DEFAULT_KEYS; i++)
 | 
				
			||||||
		ieee80211_key_free(local, sta->key);
 | 
							ieee80211_key_free(local, sta->gtk[i]);
 | 
				
			||||||
		WARN_ON(sta->key);
 | 
						if (sta->ptk)
 | 
				
			||||||
	}
 | 
							ieee80211_key_free(local, sta->ptk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sta->dead = true;
 | 
						sta->dead = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -199,7 +199,8 @@ enum plink_state {
 | 
				
			||||||
 * @hnext: hash table linked list pointer
 | 
					 * @hnext: hash table linked list pointer
 | 
				
			||||||
 * @local: pointer to the global information
 | 
					 * @local: pointer to the global information
 | 
				
			||||||
 * @sdata: virtual interface this station belongs to
 | 
					 * @sdata: virtual interface this station belongs to
 | 
				
			||||||
 * @key: peer key negotiated with this station, if any
 | 
					 * @ptk: peer key negotiated with this station, if any
 | 
				
			||||||
 | 
					 * @gtk: group keys negotiated with this station, if any
 | 
				
			||||||
 * @rate_ctrl: rate control algorithm reference
 | 
					 * @rate_ctrl: rate control algorithm reference
 | 
				
			||||||
 * @rate_ctrl_priv: rate control private per-STA pointer
 | 
					 * @rate_ctrl_priv: rate control private per-STA pointer
 | 
				
			||||||
 * @last_tx_rate: rate used for last transmit, to report to userspace as
 | 
					 * @last_tx_rate: rate used for last transmit, to report to userspace as
 | 
				
			||||||
| 
						 | 
					@ -254,7 +255,8 @@ struct sta_info {
 | 
				
			||||||
	struct sta_info *hnext;
 | 
						struct sta_info *hnext;
 | 
				
			||||||
	struct ieee80211_local *local;
 | 
						struct ieee80211_local *local;
 | 
				
			||||||
	struct ieee80211_sub_if_data *sdata;
 | 
						struct ieee80211_sub_if_data *sdata;
 | 
				
			||||||
	struct ieee80211_key *key;
 | 
						struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
 | 
				
			||||||
 | 
						struct ieee80211_key *ptk;
 | 
				
			||||||
	struct rate_control_ref *rate_ctrl;
 | 
						struct rate_control_ref *rate_ctrl;
 | 
				
			||||||
	void *rate_ctrl_priv;
 | 
						void *rate_ctrl_priv;
 | 
				
			||||||
	spinlock_t lock;
 | 
						spinlock_t lock;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -532,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
 | 
						if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
 | 
				
			||||||
		tx->key = NULL;
 | 
							tx->key = NULL;
 | 
				
			||||||
	else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
 | 
						else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
 | 
				
			||||||
		tx->key = key;
 | 
							tx->key = key;
 | 
				
			||||||
	else if (ieee80211_is_mgmt(hdr->frame_control) &&
 | 
						else if (ieee80211_is_mgmt(hdr->frame_control) &&
 | 
				
			||||||
		 is_multicast_ether_addr(hdr->addr1) &&
 | 
							 is_multicast_ether_addr(hdr->addr1) &&
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -375,7 +375,7 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
 | 
				
			||||||
/* internal helpers */
 | 
					/* internal helpers */
 | 
				
			||||||
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 | 
					int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
				   struct key_params *params, int key_idx,
 | 
									   struct key_params *params, int key_idx,
 | 
				
			||||||
				   const u8 *mac_addr);
 | 
									   bool pairwise, const u8 *mac_addr);
 | 
				
			||||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 | 
					void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 | 
				
			||||||
			     size_t ie_len, u16 reason, bool from_ap);
 | 
								     size_t ie_len, u16 reason, bool from_ap);
 | 
				
			||||||
void cfg80211_sme_scan_done(struct net_device *dev);
 | 
					void cfg80211_sme_scan_done(struct net_device *dev);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,7 +160,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (rdev->ops->del_key)
 | 
						if (rdev->ops->del_key)
 | 
				
			||||||
		for (i = 0; i < 6; i++)
 | 
							for (i = 0; i < 6; i++)
 | 
				
			||||||
			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
 | 
								rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wdev->current_bss) {
 | 
						if (wdev->current_bss) {
 | 
				
			||||||
		cfg80211_unhold_bss(wdev->current_bss);
 | 
							cfg80211_unhold_bss(wdev->current_bss);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 | 
				
			||||||
	[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
 | 
						[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
 | 
				
			||||||
	[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
 | 
						[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
 | 
				
			||||||
	[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
 | 
						[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
 | 
				
			||||||
 | 
						[NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
 | 
						[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
 | 
				
			||||||
	[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
 | 
						[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
 | 
				
			||||||
| 
						 | 
					@ -168,7 +169,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 | 
				
			||||||
	[NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
 | 
						[NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* policy for the attributes */
 | 
					/* policy for the key attributes */
 | 
				
			||||||
static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
 | 
					static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
 | 
				
			||||||
	[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
 | 
						[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
 | 
				
			||||||
	[NL80211_KEY_IDX] = { .type = NLA_U8 },
 | 
						[NL80211_KEY_IDX] = { .type = NLA_U8 },
 | 
				
			||||||
| 
						 | 
					@ -176,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
 | 
				
			||||||
	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
 | 
						[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
 | 
				
			||||||
	[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
 | 
						[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
 | 
				
			||||||
	[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
 | 
						[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
 | 
				
			||||||
 | 
						[NL80211_KEY_TYPE] = { .type = NLA_U32 },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ifidx get helper */
 | 
					/* ifidx get helper */
 | 
				
			||||||
| 
						 | 
					@ -306,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
 | 
				
			||||||
struct key_parse {
 | 
					struct key_parse {
 | 
				
			||||||
	struct key_params p;
 | 
						struct key_params p;
 | 
				
			||||||
	int idx;
 | 
						int idx;
 | 
				
			||||||
 | 
						int type;
 | 
				
			||||||
	bool def, defmgmt;
 | 
						bool def, defmgmt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -336,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
 | 
				
			||||||
	if (tb[NL80211_KEY_CIPHER])
 | 
						if (tb[NL80211_KEY_CIPHER])
 | 
				
			||||||
		k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
 | 
							k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tb[NL80211_KEY_TYPE]) {
 | 
				
			||||||
 | 
							k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
 | 
				
			||||||
 | 
							if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -360,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
 | 
				
			||||||
	k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
 | 
						k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
 | 
				
			||||||
	k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
 | 
						k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
 | 
				
			||||||
 | 
							k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
 | 
				
			||||||
 | 
							if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -369,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(k, 0, sizeof(*k));
 | 
						memset(k, 0, sizeof(*k));
 | 
				
			||||||
	k->idx = -1;
 | 
						k->idx = -1;
 | 
				
			||||||
 | 
						k->type = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info->attrs[NL80211_ATTR_KEY])
 | 
						if (info->attrs[NL80211_ATTR_KEY])
 | 
				
			||||||
		err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
 | 
							err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
 | 
				
			||||||
| 
						 | 
					@ -433,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
		} else if (parse.defmgmt)
 | 
							} else if (parse.defmgmt)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
		err = cfg80211_validate_key_settings(rdev, &parse.p,
 | 
							err = cfg80211_validate_key_settings(rdev, &parse.p,
 | 
				
			||||||
						     parse.idx, NULL);
 | 
											     parse.idx, false, NULL);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
		result->params[parse.idx].cipher = parse.p.cipher;
 | 
							result->params[parse.idx].cipher = parse.p.cipher;
 | 
				
			||||||
| 
						 | 
					@ -516,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 | 
				
			||||||
	NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
 | 
						NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
 | 
				
			||||||
		    dev->wiphy.max_scan_ie_len);
 | 
							    dev->wiphy.max_scan_ie_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
 | 
				
			||||||
 | 
							NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
 | 
						NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
 | 
				
			||||||
		sizeof(u32) * dev->wiphy.n_cipher_suites,
 | 
							sizeof(u32) * dev->wiphy.n_cipher_suites,
 | 
				
			||||||
		dev->wiphy.cipher_suites);
 | 
							dev->wiphy.cipher_suites);
 | 
				
			||||||
| 
						 | 
					@ -1446,7 +1465,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	struct net_device *dev = info->user_ptr[1];
 | 
						struct net_device *dev = info->user_ptr[1];
 | 
				
			||||||
	u8 key_idx = 0;
 | 
						u8 key_idx = 0;
 | 
				
			||||||
	u8 *mac_addr = NULL;
 | 
						const u8 *mac_addr = NULL;
 | 
				
			||||||
 | 
						bool pairwise;
 | 
				
			||||||
	struct get_key_cookie cookie = {
 | 
						struct get_key_cookie cookie = {
 | 
				
			||||||
		.error = 0,
 | 
							.error = 0,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -1462,6 +1482,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	if (info->attrs[NL80211_ATTR_MAC])
 | 
						if (info->attrs[NL80211_ATTR_MAC])
 | 
				
			||||||
		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 | 
							mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pairwise = !!mac_addr;
 | 
				
			||||||
 | 
						if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
 | 
				
			||||||
 | 
							u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
 | 
				
			||||||
 | 
							if (kt >= NUM_NL80211_KEYTYPES)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							if (kt != NL80211_KEYTYPE_GROUP &&
 | 
				
			||||||
 | 
							    kt != NL80211_KEYTYPE_PAIRWISE)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rdev->ops->get_key)
 | 
						if (!rdev->ops->get_key)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1482,8 +1513,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	if (mac_addr)
 | 
						if (mac_addr)
 | 
				
			||||||
		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 | 
							NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr,
 | 
						if (pairwise && mac_addr &&
 | 
				
			||||||
				&cookie, get_key_callback);
 | 
						    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise,
 | 
				
			||||||
 | 
									 mac_addr, &cookie, get_key_callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto free_msg;
 | 
							goto free_msg;
 | 
				
			||||||
| 
						 | 
					@ -1553,7 +1588,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	struct net_device *dev = info->user_ptr[1];
 | 
						struct net_device *dev = info->user_ptr[1];
 | 
				
			||||||
	struct key_parse key;
 | 
						struct key_parse key;
 | 
				
			||||||
	u8 *mac_addr = NULL;
 | 
						const u8 *mac_addr = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = nl80211_parse_key(info, &key);
 | 
						err = nl80211_parse_key(info, &key);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -1565,16 +1600,31 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	if (info->attrs[NL80211_ATTR_MAC])
 | 
						if (info->attrs[NL80211_ATTR_MAC])
 | 
				
			||||||
		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 | 
							mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (key.type == -1) {
 | 
				
			||||||
 | 
							if (mac_addr)
 | 
				
			||||||
 | 
								key.type = NL80211_KEYTYPE_PAIRWISE;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								key.type = NL80211_KEYTYPE_GROUP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* for now */
 | 
				
			||||||
 | 
						if (key.type != NL80211_KEYTYPE_PAIRWISE &&
 | 
				
			||||||
 | 
						    key.type != NL80211_KEYTYPE_GROUP)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rdev->ops->add_key)
 | 
						if (!rdev->ops->add_key)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr))
 | 
						if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
 | 
				
			||||||
 | 
										   key.type == NL80211_KEYTYPE_PAIRWISE,
 | 
				
			||||||
 | 
										   mac_addr))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wdev_lock(dev->ieee80211_ptr);
 | 
						wdev_lock(dev->ieee80211_ptr);
 | 
				
			||||||
	err = nl80211_key_allowed(dev->ieee80211_ptr);
 | 
						err = nl80211_key_allowed(dev->ieee80211_ptr);
 | 
				
			||||||
	if (!err)
 | 
						if (!err)
 | 
				
			||||||
		err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
 | 
							err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
 | 
				
			||||||
 | 
										 key.type == NL80211_KEYTYPE_PAIRWISE,
 | 
				
			||||||
					 mac_addr, &key.p);
 | 
										 mac_addr, &key.p);
 | 
				
			||||||
	wdev_unlock(dev->ieee80211_ptr);
 | 
						wdev_unlock(dev->ieee80211_ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1596,13 +1646,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
	if (info->attrs[NL80211_ATTR_MAC])
 | 
						if (info->attrs[NL80211_ATTR_MAC])
 | 
				
			||||||
		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 | 
							mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (key.type == -1) {
 | 
				
			||||||
 | 
							if (mac_addr)
 | 
				
			||||||
 | 
								key.type = NL80211_KEYTYPE_PAIRWISE;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								key.type = NL80211_KEYTYPE_GROUP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* for now */
 | 
				
			||||||
 | 
						if (key.type != NL80211_KEYTYPE_PAIRWISE &&
 | 
				
			||||||
 | 
						    key.type != NL80211_KEYTYPE_GROUP)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rdev->ops->del_key)
 | 
						if (!rdev->ops->del_key)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wdev_lock(dev->ieee80211_ptr);
 | 
						wdev_lock(dev->ieee80211_ptr);
 | 
				
			||||||
	err = nl80211_key_allowed(dev->ieee80211_ptr);
 | 
						err = nl80211_key_allowed(dev->ieee80211_ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr &&
 | 
				
			||||||
 | 
						    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
 | 
				
			||||||
 | 
							err = -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!err)
 | 
						if (!err)
 | 
				
			||||||
		err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
 | 
							err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx,
 | 
				
			||||||
 | 
										 key.type == NL80211_KEYTYPE_PAIRWISE,
 | 
				
			||||||
 | 
										 mac_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CFG80211_WEXT
 | 
					#ifdef CONFIG_CFG80211_WEXT
 | 
				
			||||||
	if (!err) {
 | 
						if (!err) {
 | 
				
			||||||
| 
						 | 
					@ -3212,6 +3281,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (key.idx >= 0) {
 | 
						if (key.idx >= 0) {
 | 
				
			||||||
 | 
							if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
		if (!key.p.key || !key.p.key_len)
 | 
							if (!key.p.key || !key.p.key_len)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
 | 
							if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -698,7 +698,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (rdev->ops->del_key)
 | 
						if (rdev->ops->del_key)
 | 
				
			||||||
		for (i = 0; i < 6; i++)
 | 
							for (i = 0; i < 6; i++)
 | 
				
			||||||
			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
 | 
								rdev->ops->del_key(wdev->wiphy, dev, i, false, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CFG80211_WEXT
 | 
					#ifdef CONFIG_CFG80211_WEXT
 | 
				
			||||||
	memset(&wrqu, 0, sizeof(wrqu));
 | 
						memset(&wrqu, 0, sizeof(wrqu));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,19 +144,25 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 | 
					int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
				   struct key_params *params, int key_idx,
 | 
									   struct key_params *params, int key_idx,
 | 
				
			||||||
				   const u8 *mac_addr)
 | 
									   bool pairwise, const u8 *mac_addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (key_idx > 5)
 | 
						if (key_idx > 5)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pairwise && !mac_addr)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Disallow pairwise keys with non-zero index unless it's WEP
 | 
						 * Disallow pairwise keys with non-zero index unless it's WEP
 | 
				
			||||||
	 * (because current deployments use pairwise WEP keys with
 | 
						 * (because current deployments use pairwise WEP keys with
 | 
				
			||||||
	 * non-zero indizes but 802.11i clearly specifies to use zero)
 | 
						 * non-zero indizes but 802.11i clearly specifies to use zero)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (mac_addr && key_idx &&
 | 
						if (pairwise && key_idx &&
 | 
				
			||||||
	    params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
 | 
						    params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
 | 
				
			||||||
	    params->cipher != WLAN_CIPHER_SUITE_WEP104)
 | 
						    params->cipher != WLAN_CIPHER_SUITE_WEP104)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -677,7 +683,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
 | 
				
			||||||
	for (i = 0; i < 6; i++) {
 | 
						for (i = 0; i < 6; i++) {
 | 
				
			||||||
		if (!wdev->connect_keys->params[i].cipher)
 | 
							if (!wdev->connect_keys->params[i].cipher)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
 | 
							if (rdev->ops->add_key(wdev->wiphy, dev, i, false, NULL,
 | 
				
			||||||
					&wdev->connect_keys->params[i])) {
 | 
										&wdev->connect_keys->params[i])) {
 | 
				
			||||||
			printk(KERN_ERR "%s: failed to set key %d\n",
 | 
								printk(KERN_ERR "%s: failed to set key %d\n",
 | 
				
			||||||
				dev->name, i);
 | 
									dev->name, i);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -432,14 +432,17 @@ int cfg80211_wext_giwretry(struct net_device *dev,
 | 
				
			||||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
 | 
					EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 | 
					static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
				     struct net_device *dev, const u8 *addr,
 | 
									     struct net_device *dev, bool pairwise,
 | 
				
			||||||
				     bool remove, bool tx_key, int idx,
 | 
									     const u8 *addr, bool remove, bool tx_key,
 | 
				
			||||||
				     struct key_params *params)
 | 
									     int idx, struct key_params *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct wireless_dev *wdev = dev->ieee80211_ptr;
 | 
						struct wireless_dev *wdev = dev->ieee80211_ptr;
 | 
				
			||||||
	int err, i;
 | 
						int err, i;
 | 
				
			||||||
	bool rejoin = false;
 | 
						bool rejoin = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pairwise && !addr)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!wdev->wext.keys) {
 | 
						if (!wdev->wext.keys) {
 | 
				
			||||||
		wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
 | 
							wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
 | 
				
			||||||
					      GFP_KERNEL);
 | 
										      GFP_KERNEL);
 | 
				
			||||||
| 
						 | 
					@ -478,7 +481,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
				__cfg80211_leave_ibss(rdev, wdev->netdev, true);
 | 
									__cfg80211_leave_ibss(rdev, wdev->netdev, true);
 | 
				
			||||||
				rejoin = true;
 | 
									rejoin = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
 | 
					
 | 
				
			||||||
 | 
								if (!pairwise && addr &&
 | 
				
			||||||
 | 
								    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
 | 
				
			||||||
 | 
									err = -ENOENT;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									err = rdev->ops->del_key(&rdev->wiphy, dev, idx,
 | 
				
			||||||
 | 
												 pairwise, addr);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		wdev->wext.connect.privacy = false;
 | 
							wdev->wext.connect.privacy = false;
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
| 
						 | 
					@ -507,12 +516,13 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
	if (addr)
 | 
						if (addr)
 | 
				
			||||||
		tx_key = false;
 | 
							tx_key = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cfg80211_validate_key_settings(rdev, params, idx, addr))
 | 
						if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = 0;
 | 
						err = 0;
 | 
				
			||||||
	if (wdev->current_bss)
 | 
						if (wdev->current_bss)
 | 
				
			||||||
		err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
 | 
							err = rdev->ops->add_key(&rdev->wiphy, dev, idx,
 | 
				
			||||||
 | 
										 pairwise, addr, params);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -563,17 +573,17 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 | 
					static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
 | 
				
			||||||
				   struct net_device *dev, const u8 *addr,
 | 
									   struct net_device *dev, bool pairwise,
 | 
				
			||||||
				   bool remove, bool tx_key, int idx,
 | 
									   const u8 *addr, bool remove, bool tx_key,
 | 
				
			||||||
				   struct key_params *params)
 | 
									   int idx, struct key_params *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* devlist mutex needed for possible IBSS re-join */
 | 
						/* devlist mutex needed for possible IBSS re-join */
 | 
				
			||||||
	mutex_lock(&rdev->devlist_mtx);
 | 
						mutex_lock(&rdev->devlist_mtx);
 | 
				
			||||||
	wdev_lock(dev->ieee80211_ptr);
 | 
						wdev_lock(dev->ieee80211_ptr);
 | 
				
			||||||
	err = __cfg80211_set_encryption(rdev, dev, addr, remove,
 | 
						err = __cfg80211_set_encryption(rdev, dev, pairwise, addr,
 | 
				
			||||||
					tx_key, idx, params);
 | 
										remove, tx_key, idx, params);
 | 
				
			||||||
	wdev_unlock(dev->ieee80211_ptr);
 | 
						wdev_unlock(dev->ieee80211_ptr);
 | 
				
			||||||
	mutex_unlock(&rdev->devlist_mtx);
 | 
						mutex_unlock(&rdev->devlist_mtx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -635,7 +645,7 @@ int cfg80211_wext_siwencode(struct net_device *dev,
 | 
				
			||||||
	else if (!remove)
 | 
						else if (!remove)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cfg80211_set_encryption(rdev, dev, NULL, remove,
 | 
						return cfg80211_set_encryption(rdev, dev, false, NULL, remove,
 | 
				
			||||||
				       wdev->wext.default_key == -1,
 | 
									       wdev->wext.default_key == -1,
 | 
				
			||||||
				       idx, ¶ms);
 | 
									       idx, ¶ms);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -725,7 +735,9 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cfg80211_set_encryption(
 | 
						return cfg80211_set_encryption(
 | 
				
			||||||
			rdev, dev, addr, remove,
 | 
								rdev, dev,
 | 
				
			||||||
 | 
								!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY),
 | 
				
			||||||
 | 
								addr, remove,
 | 
				
			||||||
			ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
 | 
								ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
 | 
				
			||||||
			idx, ¶ms);
 | 
								idx, ¶ms);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue