summaryrefslogtreecommitdiff
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c298
1 files changed, 268 insertions, 30 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8c2a246..59f2337 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -328,6 +328,22 @@ he_bss_color_policy[NL80211_HE_BSS_COLOR_ATTR_MAX + 1] = {
[NL80211_HE_BSS_COLOR_ATTR_PARTIAL] = { .type = NLA_FLAG },
};
+static const struct nla_policy
+nl80211_tid_config_attr_policy[NL80211_TID_CONFIG_ATTR_MAX + 1] = {
+ [NL80211_TID_CONFIG_ATTR_VIF_SUPP] = { .type = NLA_U64 },
+ [NL80211_TID_CONFIG_ATTR_PEER_SUPP] = { .type = NLA_U64 },
+ [NL80211_TID_CONFIG_ATTR_OVERRIDE] = { .type = NLA_FLAG },
+ [NL80211_TID_CONFIG_ATTR_TIDS] = NLA_POLICY_RANGE(NLA_U16, 1, 0xff),
+ [NL80211_TID_CONFIG_ATTR_NOACK] =
+ NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
+ [NL80211_TID_CONFIG_ATTR_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
+ [NL80211_TID_CONFIG_ATTR_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
+ [NL80211_TID_CONFIG_ATTR_AMPDU_CTRL] =
+ NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
+ [NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL] =
+ NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
+};
+
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@@ -368,7 +384,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
.len = WLAN_MAX_KEY_LEN },
- [NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 5),
+ [NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 7),
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
@@ -634,8 +650,8 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
[NL80211_ATTR_VLAN_ID] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
[NL80211_ATTR_HE_BSS_COLOR] = NLA_POLICY_NESTED(he_bss_color_policy),
- [NL80211_ATTR_SRC_MAC] = NLA_POLICY_ETH_ADDR,
- [NL80211_ATTR_DST_MAC] = NLA_POLICY_ETH_ADDR,
+ [NL80211_ATTR_TID_CONFIG] =
+ NLA_POLICY_NESTED_ARRAY(nl80211_tid_config_attr_policy),
};
/* policy for the key attributes */
@@ -1039,7 +1055,7 @@ struct key_parse {
struct key_params p;
int idx;
int type;
- bool def, defmgmt;
+ bool def, defmgmt, defbeacon;
bool def_uni, def_multi;
};
@@ -1055,12 +1071,13 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
k->def = !!tb[NL80211_KEY_DEFAULT];
k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
+ k->defbeacon = !!tb[NL80211_KEY_DEFAULT_BEACON];
if (k->def) {
k->def_uni = true;
k->def_multi = true;
}
- if (k->defmgmt)
+ if (k->defmgmt || k->defbeacon)
k->def_multi = true;
if (tb[NL80211_KEY_IDX])
@@ -1167,14 +1184,17 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
if (err)
return err;
- if (k->def && k->defmgmt) {
- GENL_SET_ERR_MSG(info, "key with def && defmgmt is invalid");
+ if ((k->def ? 1 : 0) + (k->defmgmt ? 1 : 0) +
+ (k->defbeacon ? 1 : 0) > 1) {
+ GENL_SET_ERR_MSG(info,
+ "key with multiple default flags is invalid");
return -EINVAL;
}
- if (k->defmgmt) {
+ if (k->defmgmt || k->defbeacon) {
if (k->def_uni || !k->def_multi) {
- GENL_SET_ERR_MSG(info, "defmgmt key must be mcast");
+ GENL_SET_ERR_MSG(info,
+ "defmgmt/defbeacon key must be mcast");
return -EINVAL;
}
}
@@ -1186,14 +1206,20 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
"defmgmt key idx not 4 or 5");
return -EINVAL;
}
+ } else if (k->defbeacon) {
+ if (k->idx < 6 || k->idx > 7) {
+ GENL_SET_ERR_MSG(info,
+ "defbeacon key idx not 6 or 7");
+ return -EINVAL;
+ }
} else if (k->def) {
if (k->idx < 0 || k->idx > 3) {
GENL_SET_ERR_MSG(info, "def key idx not 0-3");
return -EINVAL;
}
} else {
- if (k->idx < 0 || k->idx > 5) {
- GENL_SET_ERR_MSG(info, "key idx not 0-5");
+ if (k->idx < 0 || k->idx > 7) {
+ GENL_SET_ERR_MSG(info, "key idx not 0-7");
return -EINVAL;
}
}
@@ -1939,6 +1965,48 @@ nl80211_put_iftype_akm_suites(struct cfg80211_registered_device *rdev,
return 0;
}
+static int
+nl80211_put_tid_config_support(struct cfg80211_registered_device *rdev,
+ struct sk_buff *msg)
+{
+ struct nlattr *supp;
+
+ if (!rdev->wiphy.tid_config_support.vif &&
+ !rdev->wiphy.tid_config_support.peer)
+ return 0;
+
+ supp = nla_nest_start(msg, NL80211_ATTR_TID_CONFIG);
+ if (!supp)
+ return -ENOSPC;
+
+ if (rdev->wiphy.tid_config_support.vif &&
+ nla_put_u64_64bit(msg, NL80211_TID_CONFIG_ATTR_VIF_SUPP,
+ rdev->wiphy.tid_config_support.vif,
+ NL80211_TID_CONFIG_ATTR_PAD))
+ goto fail;
+
+ if (rdev->wiphy.tid_config_support.peer &&
+ nla_put_u64_64bit(msg, NL80211_TID_CONFIG_ATTR_PEER_SUPP,
+ rdev->wiphy.tid_config_support.peer,
+ NL80211_TID_CONFIG_ATTR_PAD))
+ goto fail;
+
+ /* for now we just use the same value ... makes more sense */
+ if (nla_put_u8(msg, NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
+ rdev->wiphy.tid_config_support.max_retry))
+ goto fail;
+ if (nla_put_u8(msg, NL80211_TID_CONFIG_ATTR_RETRY_LONG,
+ rdev->wiphy.tid_config_support.max_retry))
+ goto fail;
+
+ nla_nest_end(msg, supp);
+
+ return 0;
+fail:
+ nla_nest_cancel(msg, supp);
+ return -ENOBUFS;
+}
+
struct nl80211_dump_wiphy_state {
s64 filter_wiphy;
long start;
@@ -2500,6 +2568,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
if (nl80211_put_iftype_akm_suites(rdev, msg))
goto nla_put_failure;
+ if (nl80211_put_tid_config_support(rdev, msg))
+ goto nla_put_failure;
+
/* done */
state->split_start = 0;
break;
@@ -3819,8 +3890,14 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
void *hdr;
struct sk_buff *msg;
- if (info->attrs[NL80211_ATTR_KEY_IDX])
+ if (info->attrs[NL80211_ATTR_KEY_IDX]) {
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+ if (key_idx > 5 &&
+ !wiphy_ext_feature_isset(
+ &rdev->wiphy,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION))
+ return -EINVAL;
+ }
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -3896,7 +3973,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
/* Only support setting default key and
* Extended Key ID action NL80211_KEY_SET_TX.
*/
- if (!key.def && !key.defmgmt &&
+ if (!key.def && !key.defmgmt && !key.defbeacon &&
!(key.p.mode == NL80211_KEY_SET_TX))
return -EINVAL;
@@ -3943,6 +4020,24 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
#endif
+ } else if (key.defbeacon) {
+ if (key.def_uni || !key.def_multi) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (!rdev->ops->set_default_beacon_key) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ err = nl80211_key_allowed(dev->ieee80211_ptr);
+ if (err)
+ goto out;
+
+ err = rdev_set_default_beacon_key(rdev, dev, key.idx);
+ if (err)
+ goto out;
} else if (key.p.mode == NL80211_KEY_SET_TX &&
wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID)) {
@@ -3980,8 +4075,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
- if (!key.p.key)
+ if (!key.p.key) {
+ GENL_SET_ERR_MSG(info, "no key");
return -EINVAL;
+ }
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -3995,8 +4092,10 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
/* for now */
if (key.type != NL80211_KEYTYPE_PAIRWISE &&
- key.type != NL80211_KEYTYPE_GROUP)
+ key.type != NL80211_KEYTYPE_GROUP) {
+ GENL_SET_ERR_MSG(info, "key type not pairwise or group");
return -EINVAL;
+ }
if (key.type == NL80211_KEYTYPE_GROUP &&
info->attrs[NL80211_ATTR_VLAN_ID])
@@ -4007,15 +4106,22 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE,
- mac_addr))
+ mac_addr)) {
+ GENL_SET_ERR_MSG(info, "key setting validation failed");
return -EINVAL;
+ }
wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr);
- if (!err)
+ if (err)
+ GENL_SET_ERR_MSG(info, "key not allowed");
+ if (!err) {
err = rdev_add_key(rdev, dev, key.idx,
key.type == NL80211_KEYTYPE_PAIRWISE,
mac_addr, &key.p);
+ if (err)
+ GENL_SET_ERR_MSG(info, "key addition failed");
+ }
wdev_unlock(dev->ieee80211_ptr);
return err;
@@ -13698,7 +13804,6 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
const u8 *buf;
size_t len;
u8 *dest;
- u8 src[ETH_ALEN];
u16 proto;
bool noencrypt;
int err;
@@ -13736,13 +13841,6 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
goto out;
}
- /* copy src address under wdev_lock, as we may copy wdev_address */
- if (info->attrs[NL80211_ATTR_SRC_MAC])
- ether_addr_copy(src,
- nla_data(info->attrs[NL80211_ATTR_SRC_MAC]));
- else
- ether_addr_copy(src, wdev_address(wdev));
-
wdev_unlock(wdev);
buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
@@ -13753,7 +13851,7 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]);
return rdev_tx_control_port(rdev, dev, buf, len,
- dest, src, cpu_to_be16(proto), noencrypt);
+ dest, cpu_to_be16(proto), noencrypt);
out:
wdev_unlock(wdev);
@@ -13899,6 +13997,141 @@ static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info)
return rdev_probe_mesh_link(rdev, dev, dest, buf, len);
}
+static int parse_tid_conf(struct cfg80211_registered_device *rdev,
+ struct nlattr *attrs[], struct net_device *dev,
+ struct cfg80211_tid_cfg *tid_conf,
+ struct genl_info *info, const u8 *peer)
+{
+ struct netlink_ext_ack *extack = info->extack;
+ u64 mask;
+ int err;
+
+ if (!attrs[NL80211_TID_CONFIG_ATTR_TIDS])
+ return -EINVAL;
+
+ tid_conf->config_override =
+ nla_get_flag(attrs[NL80211_TID_CONFIG_ATTR_OVERRIDE]);
+ tid_conf->tids = nla_get_u16(attrs[NL80211_TID_CONFIG_ATTR_TIDS]);
+
+ if (tid_conf->config_override) {
+ if (rdev->ops->reset_tid_config) {
+ err = rdev_reset_tid_config(rdev, dev, peer,
+ tid_conf->tids);
+ /* If peer is there no other configuration will be
+ * allowed
+ */
+ if (err || peer)
+ return err;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ if (attrs[NL80211_TID_CONFIG_ATTR_NOACK]) {
+ tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_NOACK);
+ tid_conf->noack =
+ nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_NOACK]);
+ }
+
+ if (attrs[NL80211_TID_CONFIG_ATTR_RETRY_SHORT]) {
+ tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RETRY_SHORT);
+ tid_conf->retry_short =
+ nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RETRY_SHORT]);
+
+ if (tid_conf->retry_short > rdev->wiphy.max_data_retry_count)
+ return -EINVAL;
+ }
+
+ if (attrs[NL80211_TID_CONFIG_ATTR_RETRY_LONG]) {
+ tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG);
+ tid_conf->retry_long =
+ nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RETRY_LONG]);
+
+ if (tid_conf->retry_long > rdev->wiphy.max_data_retry_count)
+ return -EINVAL;
+ }
+
+ if (attrs[NL80211_TID_CONFIG_ATTR_AMPDU_CTRL]) {
+ tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
+ tid_conf->ampdu =
+ nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_AMPDU_CTRL]);
+ }
+
+ if (attrs[NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL]) {
+ tid_conf->mask |= BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL);
+ tid_conf->rtscts =
+ nla_get_u8(attrs[NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL]);
+ }
+
+ if (peer)
+ mask = rdev->wiphy.tid_config_support.peer;
+ else
+ mask = rdev->wiphy.tid_config_support.vif;
+
+ if (tid_conf->mask & ~mask) {
+ NL_SET_ERR_MSG(extack, "unsupported TID configuration");
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int nl80211_set_tid_config(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct nlattr *attrs[NL80211_TID_CONFIG_ATTR_MAX + 1];
+ struct net_device *dev = info->user_ptr[1];
+ struct cfg80211_tid_config *tid_config;
+ struct nlattr *tid;
+ int conf_idx = 0, rem_conf;
+ int ret = -EINVAL;
+ u32 num_conf = 0;
+
+ if (!info->attrs[NL80211_ATTR_TID_CONFIG])
+ return -EINVAL;
+
+ if (!rdev->ops->set_tid_config)
+ return -EOPNOTSUPP;
+
+ nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
+ rem_conf)
+ num_conf++;
+
+ tid_config = kzalloc(struct_size(tid_config, tid_conf, num_conf),
+ GFP_KERNEL);
+ if (!tid_config)
+ return -ENOMEM;
+
+ tid_config->n_tid_conf = num_conf;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ tid_config->peer = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ nla_for_each_nested(tid, info->attrs[NL80211_ATTR_TID_CONFIG],
+ rem_conf) {
+ ret = nla_parse_nested(attrs, NL80211_TID_CONFIG_ATTR_MAX,
+ tid, NULL, NULL);
+
+ if (ret)
+ goto bad_tid_conf;
+
+ ret = parse_tid_conf(rdev, attrs, dev,
+ &tid_config->tid_conf[conf_idx],
+ info, tid_config->peer);
+ if (ret)
+ goto bad_tid_conf;
+
+ conf_idx++;
+ }
+
+ ret = rdev_set_tid_config(rdev, dev, tid_config);
+
+bad_tid_conf:
+ kfree(tid_config);
+ return ret;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -14853,6 +15086,13 @@ static const struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_TID_CONFIG,
+ .doit = nl80211_set_tid_config,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_family nl80211_fam __ro_after_init = {
@@ -16010,8 +16250,7 @@ static int __nl80211_rx_control_port(struct net_device *dev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ethhdr *ehdr = eth_hdr(skb);
- const u8 *daddr = ehdr->h_dest;
- const u8 *saddr = ehdr->h_source;
+ const u8 *addr = ehdr->h_source;
u16 proto = be16_to_cpu(skb->protocol);
struct sk_buff *msg;
void *hdr;
@@ -16036,8 +16275,7 @@ static int __nl80211_rx_control_port(struct net_device *dev,
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
NL80211_ATTR_PAD) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, saddr) ||
- nla_put(msg, NL80211_ATTR_DST_MAC, ETH_ALEN, daddr) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) ||
(unencrypted && nla_put_flag(msg,
NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))