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