Skip to content

Commit

Permalink
cfg80211/mac80211: allow per-station GTKs
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: John W. Linville <[email protected]>
  • Loading branch information
jmberg-intel authored and linvjw committed Oct 6, 2010
1 parent 53f73c0 commit e31b821
Show file tree
Hide file tree
Showing 20 changed files with 293 additions and 109 deletions.
7 changes: 4 additions & 3 deletions drivers/net/wireless/iwmc3200wifi/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
u8 key_index, const u8 *mac_addr,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
Expand All @@ -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,
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*))
{
Expand All @@ -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,
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_key *key = &iwm->keys[key_index];
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/libertas/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
u8 idx, const u8 *mac_addr,
u8 idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct lbs_private *priv = wiphy_priv(wiphy);
Expand Down Expand Up @@ -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,
u8 key_index, const u8 *mac_addr)
u8 key_index, bool pairwise, const u8 *mac_addr)
{

lbs_deb_enter(LBS_DEB_CFG80211);
Expand Down
12 changes: 6 additions & 6 deletions drivers/net/wireless/rndis_wlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, const u8 *mac_addr,
struct key_params *params);
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params);

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,
u8 key_index);
Expand Down Expand Up @@ -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,
u8 key_index, const u8 *mac_addr,
struct key_params *params)
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
Expand Down Expand Up @@ -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,
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 usbnet *usbdev = priv->usbdev;
Expand Down
12 changes: 12 additions & 0 deletions include/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,9 @@ enum nl80211_commands {
* This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
* 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_AFTER_LAST: internal use
*/
Expand Down Expand Up @@ -968,6 +971,8 @@ enum nl80211_attrs {
NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,

NL80211_ATTR_SUPPORT_IBSS_RSN,

/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
Expand Down Expand Up @@ -1659,11 +1664,14 @@ enum nl80211_auth_type {
* @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
* @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
* @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
* @NUM_NL80211_KEYTYPES: number of defined key types
*/
enum nl80211_key_type {
NL80211_KEYTYPE_GROUP,
NL80211_KEYTYPE_PAIRWISE,
NL80211_KEYTYPE_PEERKEY,

NUM_NL80211_KEYTYPES
};

/**
Expand Down Expand Up @@ -1694,6 +1702,9 @@ enum nl80211_wpa_versions {
* CCMP keys, each six bytes in little endian
* @NL80211_KEY_DEFAULT: flag indicating default 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_MAX: highest key attribute
*/
Expand All @@ -1705,6 +1716,7 @@ enum nl80211_key_attributes {
NL80211_KEY_SEQ,
NL80211_KEY_DEFAULT,
NL80211_KEY_DEFAULT_MGMT,
NL80211_KEY_TYPE,

/* keep last */
__NL80211_KEY_AFTER_LAST,
Expand Down
9 changes: 6 additions & 3 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1130,13 +1130,14 @@ struct cfg80211_ops {
struct vif_params *params);

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);
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*));
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,
struct net_device *netdev,
u8 key_index);
Expand Down Expand Up @@ -1304,6 +1305,7 @@ struct cfg80211_ops {
* @WIPHY_FLAG_CONTROL_PORT_PROTOCOL: This device supports setting the
* control port protocol ethertype. The device also honours the
* control_port_no_encrypt flag.
* @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
Expand All @@ -1314,6 +1316,7 @@ enum wiphy_flags {
WIPHY_FLAG_4ADDR_AP = BIT(5),
WIPHY_FLAG_4ADDR_STATION = BIT(6),
WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
WIPHY_FLAG_IBSS_RSN = BIT(7),
};

struct mac_address {
Expand Down
24 changes: 24 additions & 0 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,13 @@ enum ieee80211_tkip_key_type {
* @IEEE80211_HW_NEED_DTIM_PERIOD:
* This device needs to know the DTIM period for the BSS before
* 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 {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
Expand All @@ -1064,6 +1071,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20,
IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21,
};

/**
Expand Down Expand Up @@ -2582,6 +2590,22 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
void ieee80211_request_smps(struct ieee80211_vif *vif,
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 */

/**
Expand Down
32 changes: 23 additions & 9 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
}

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 ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
Expand Down Expand Up @@ -131,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (IS_ERR(key))
return PTR_ERR(key);

if (pairwise)
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;

mutex_lock(&sdata->local->sta_mtx);

if (mac_addr) {
Expand All @@ -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,
u8 key_idx, const u8 *mac_addr)
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
Expand All @@ -170,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
goto out_unlock;

if (sta->key) {
ieee80211_key_free(sdata->local, sta->key);
WARN_ON(sta->key);
ret = 0;
if (pairwise) {
if (sta->ptk) {
ieee80211_key_free(sdata->local, sta->ptk);
ret = 0;
}
} else {
if (sta->gtk[key_idx]) {
ieee80211_key_free(sdata->local,
sta->gtk[key_idx]);
ret = 0;
}
}

goto out_unlock;
Expand All @@ -195,15 +205,16 @@ static int ieee80211_del_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,
struct key_params *params))
{
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta = NULL;
u8 seq[6] = {0};
struct key_params params;
struct ieee80211_key *key;
struct ieee80211_key *key = NULL;
u32 iv32;
u16 iv16;
int err = -ENOENT;
Expand All @@ -217,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
goto out;

key = sta->key;
if (pairwise)
key = sta->ptk;
else if (key_idx < NUM_DEFAULT_KEYS)
key = sta->gtk[key_idx];
} else
key = sdata->keys[key_idx];

Expand Down
2 changes: 0 additions & 2 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,6 @@ struct ieee80211_sub_if_data {
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
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 *default_key;
struct ieee80211_key *default_mgmt_key;
Expand Down
Loading

0 comments on commit e31b821

Please sign in to comment.