Commit dbd2fd65 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

cfg80211/nl80211: separate unicast/multicast default TX keys

Allow userspace to specify that a given key
is default only for unicast and/or multicast
transmissions. Only WEP keys are for both,
WPA/RSN keys set here are GTKs for multicast
only. For more future flexibility, allow to
specify all combiations.

Wireless extensions can only set both so use
nl80211; WEP keys (connect keys) must be set
as default for both (but 802.1X WEP is still
possible).
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 897bed8b
...@@ -225,7 +225,8 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, ...@@ -225,7 +225,8 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
struct net_device *ndev, struct net_device *ndev,
u8 key_index) u8 key_index, bool unicast,
bool multicast)
{ {
struct iwm_priv *iwm = ndev_to_iwm(ndev); struct iwm_priv *iwm = ndev_to_iwm(ndev);
......
...@@ -1422,7 +1422,8 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, ...@@ -1422,7 +1422,8 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev,
static int lbs_cfg_set_default_key(struct wiphy *wiphy, static int lbs_cfg_set_default_key(struct wiphy *wiphy,
struct net_device *netdev, struct net_device *netdev,
u8 key_index) u8 key_index, bool unicast,
bool multicast)
{ {
struct lbs_private *priv = wiphy_priv(wiphy); struct lbs_private *priv = wiphy_priv(wiphy);
......
...@@ -554,7 +554,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, ...@@ -554,7 +554,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, 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, bool unicast, bool multicast);
static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev, static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_info *sinfo); u8 *mac, struct station_info *sinfo);
...@@ -2381,7 +2381,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev, ...@@ -2381,7 +2381,7 @@ static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
} }
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, bool unicast, bool multicast)
{ {
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;
......
...@@ -851,6 +851,10 @@ enum nl80211_commands { ...@@ -851,6 +851,10 @@ enum nl80211_commands {
* *
* @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16) * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
* *
* @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags
* attributes, specifying what a key should be set as default as.
* See &enum nl80211_key_default_types.
*
* @NL80211_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
*/ */
...@@ -1029,6 +1033,8 @@ enum nl80211_attrs { ...@@ -1029,6 +1033,8 @@ enum nl80211_attrs {
NL80211_ATTR_BSS_HT_OPMODE, NL80211_ATTR_BSS_HT_OPMODE,
NL80211_ATTR_KEY_DEFAULT_TYPES,
/* 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,
...@@ -1774,6 +1780,23 @@ enum nl80211_wpa_versions { ...@@ -1774,6 +1780,23 @@ enum nl80211_wpa_versions {
NL80211_WPA_VERSION_2 = 1 << 1, NL80211_WPA_VERSION_2 = 1 << 1,
}; };
/**
* enum nl80211_key_default_types - key default types
* @__NL80211_KEY_DEFAULT_TYPE_INVALID: invalid
* @NL80211_KEY_DEFAULT_TYPE_UNICAST: key should be used as default
* unicast key
* @NL80211_KEY_DEFAULT_TYPE_MULTICAST: key should be used as default
* multicast key
* @NUM_NL80211_KEY_DEFAULT_TYPES: number of default types
*/
enum nl80211_key_default_types {
__NL80211_KEY_DEFAULT_TYPE_INVALID,
NL80211_KEY_DEFAULT_TYPE_UNICAST,
NL80211_KEY_DEFAULT_TYPE_MULTICAST,
NUM_NL80211_KEY_DEFAULT_TYPES
};
/** /**
* enum nl80211_key_attributes - key attributes * enum nl80211_key_attributes - key attributes
* @__NL80211_KEY_INVALID: invalid * @__NL80211_KEY_INVALID: invalid
...@@ -1790,6 +1813,9 @@ enum nl80211_wpa_versions { ...@@ -1790,6 +1813,9 @@ enum nl80211_wpa_versions {
* @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
* specified the default depends on whether a MAC address was * specified the default depends on whether a MAC address was
* given with the command using the key or not (u32) * given with the command using the key or not (u32)
* @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
* attributes, specifying what a key should be set as default as.
* See &enum nl80211_key_default_types.
* @__NL80211_KEY_AFTER_LAST: internal * @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute * @NL80211_KEY_MAX: highest key attribute
*/ */
...@@ -1802,6 +1828,7 @@ enum nl80211_key_attributes { ...@@ -1802,6 +1828,7 @@ enum nl80211_key_attributes {
NL80211_KEY_DEFAULT, NL80211_KEY_DEFAULT,
NL80211_KEY_DEFAULT_MGMT, NL80211_KEY_DEFAULT_MGMT,
NL80211_KEY_TYPE, NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES,
/* keep last */ /* keep last */
__NL80211_KEY_AFTER_LAST, __NL80211_KEY_AFTER_LAST,
......
...@@ -1211,7 +1211,7 @@ struct cfg80211_ops { ...@@ -1211,7 +1211,7 @@ struct cfg80211_ops {
u8 key_index, bool pairwise, 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, bool unicast, bool multicast);
int (*set_default_mgmt_key)(struct wiphy *wiphy, int (*set_default_mgmt_key)(struct wiphy *wiphy,
struct net_device *netdev, struct net_device *netdev,
u8 key_index); u8 key_index);
...@@ -1393,6 +1393,8 @@ struct cfg80211_ops { ...@@ -1393,6 +1393,8 @@ struct cfg80211_ops {
* 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. * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
* @WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS: The device supports separate
* unicast and multicast TX keys.
*/ */
enum wiphy_flags { enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
...@@ -1404,6 +1406,7 @@ enum wiphy_flags { ...@@ -1404,6 +1406,7 @@ enum wiphy_flags {
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(8), WIPHY_FLAG_IBSS_RSN = BIT(8),
WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS= BIT(9),
}; };
struct mac_address { struct mac_address {
......
...@@ -295,7 +295,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, ...@@ -295,7 +295,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
static int ieee80211_config_default_key(struct wiphy *wiphy, static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
u8 key_idx) u8 key_idx, bool uni,
bool multi)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
......
...@@ -171,6 +171,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { ...@@ -171,6 +171,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
[NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
[NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
[NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
}; };
/* policy for the key attributes */ /* policy for the key attributes */
...@@ -182,6 +183,14 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { ...@@ -182,6 +183,14 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
[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 }, [NL80211_KEY_TYPE] = { .type = NLA_U32 },
[NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
};
/* policy for the key default flags */
static const struct nla_policy
nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
[NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
[NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
}; };
/* ifidx get helper */ /* ifidx get helper */
...@@ -314,6 +323,7 @@ struct key_parse { ...@@ -314,6 +323,7 @@ struct key_parse {
int idx; int idx;
int type; int type;
bool def, defmgmt; bool def, defmgmt;
bool def_uni, def_multi;
}; };
static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
...@@ -327,6 +337,13 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) ...@@ -327,6 +337,13 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
k->def = !!tb[NL80211_KEY_DEFAULT]; k->def = !!tb[NL80211_KEY_DEFAULT];
k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
if (k->def) {
k->def_uni = true;
k->def_multi = true;
}
if (k->defmgmt)
k->def_multi = true;
if (tb[NL80211_KEY_IDX]) if (tb[NL80211_KEY_IDX])
k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
...@@ -349,6 +366,19 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) ...@@ -349,6 +366,19 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
return -EINVAL; return -EINVAL;
} }
if (tb[NL80211_KEY_DEFAULT_TYPES]) {
struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
int err = nla_parse_nested(kdt,
NUM_NL80211_KEY_DEFAULT_TYPES - 1,
tb[NL80211_KEY_DEFAULT_TYPES],
nl80211_key_default_policy);
if (err)
return err;
k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
}
return 0; return 0;
} }
...@@ -373,12 +403,32 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) ...@@ -373,12 +403,32 @@ 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 (k->def) {
k->def_uni = true;
k->def_multi = true;
}
if (k->defmgmt)
k->def_multi = true;
if (info->attrs[NL80211_ATTR_KEY_TYPE]) { if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
k->type = nla_get_u32(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) if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
return -EINVAL; return -EINVAL;
} }
if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
int err = nla_parse_nested(
kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
nl80211_key_default_policy);
if (err)
return err;
k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
}
return 0; return 0;
} }
...@@ -401,6 +451,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) ...@@ -401,6 +451,11 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
if (k->def && k->defmgmt) if (k->def && k->defmgmt)
return -EINVAL; return -EINVAL;
if (k->defmgmt) {
if (k->def_uni || !k->def_multi)
return -EINVAL;
}
if (k->idx != -1) { if (k->idx != -1) {
if (k->defmgmt) { if (k->defmgmt) {
if (k->idx < 4 || k->idx > 5) if (k->idx < 4 || k->idx > 5)
...@@ -450,6 +505,8 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev, ...@@ -450,6 +505,8 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
goto error; goto error;
def = 1; def = 1;
result->def = parse.idx; result->def = parse.idx;
if (!parse.def_uni || !parse.def_multi)
goto error;
} 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,
...@@ -1586,8 +1643,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1586,8 +1643,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
struct key_parse key; struct key_parse key;
int err; int err;
struct net_device *dev = info->user_ptr[1]; struct net_device *dev = info->user_ptr[1];
int (*func)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index);
err = nl80211_parse_key(info, &key); err = nl80211_parse_key(info, &key);
if (err) if (err)
...@@ -1600,27 +1655,61 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1600,27 +1655,61 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (!key.def && !key.defmgmt) if (!key.def && !key.defmgmt)
return -EINVAL; return -EINVAL;
if (key.def) wdev_lock(dev->ieee80211_ptr);
func = rdev->ops->set_default_key;
else
func = rdev->ops->set_default_mgmt_key;
if (!func) if (key.def) {
return -EOPNOTSUPP; if (!rdev->ops->set_default_key) {
err = -EOPNOTSUPP;
goto out;
}
wdev_lock(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr); if (err)
if (!err) goto out;
err = func(&rdev->wiphy, dev, key.idx);
if (!(rdev->wiphy.flags &
WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) {
if (!key.def_uni || !key.def_multi) {
err = -EOPNOTSUPP;
goto out;
}
}
err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx,
key.def_uni, key.def_multi);
if (err)
goto out;
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
if (!err) { dev->ieee80211_ptr->wext.default_key = key.idx;
if (func == rdev->ops->set_default_key) #endif
dev->ieee80211_ptr->wext.default_key = key.idx; } else {
else if (key.def_uni || !key.def_multi) {
dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; err = -EINVAL;
} goto out;
}
if (!rdev->ops->set_default_mgmt_key) {
err = -EOPNOTSUPP;
goto out;
}
err = nl80211_key_allowed(dev->ieee80211_ptr);
if (err)
goto out;
err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
dev, key.idx);
if (err)
goto out;
#ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
#endif #endif
}
out:
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
return err; return err;
......
...@@ -689,7 +689,8 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) ...@@ -689,7 +689,8 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
continue; continue;
} }
if (wdev->connect_keys->def == i) if (wdev->connect_keys->def == i)
if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) { if (rdev->ops->set_default_key(wdev->wiphy, dev,
i, true, true)) {
netdev_err(dev, "failed to set defkey %d\n", i); netdev_err(dev, "failed to set defkey %d\n", i);
continue; continue;
} }
......
...@@ -548,8 +548,8 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev, ...@@ -548,8 +548,8 @@ 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->set_default_key(&rdev->wiphy, err = rdev->ops->set_default_key(&rdev->wiphy, dev,
dev, idx); idx, true, true);
} }
if (!err) { if (!err) {
wdev->wext.default_key = idx; wdev->wext.default_key = idx;
...@@ -627,8 +627,8 @@ int cfg80211_wext_siwencode(struct net_device *dev, ...@@ -627,8 +627,8 @@ int cfg80211_wext_siwencode(struct net_device *dev,
err = 0; err = 0;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) if (wdev->current_bss)
err = rdev->ops->set_default_key(&rdev->wiphy, err = rdev->ops->set_default_key(&rdev->wiphy, dev,
dev, idx); idx, true, true);
if (!err) if (!err)
wdev->wext.default_key = idx; wdev->wext.default_key = idx;
wdev_unlock(wdev); wdev_unlock(wdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment