Commit 9d62a986 authored by Jouni Malinen's avatar Jouni Malinen Committed by Johannes Berg

cfg80211: Pass station (extended) capability info to kernel

The information of the peer's capabilities and extended capabilities are
required for the driver to perform TDLS Peer UAPSD operations and off
channel operations. This information of the peer is passed from user space
using NL80211_CMD_SET_STATION command. This commit enhances
the function nl80211_set_station to pass the capability information of
the peer to the driver.

Similarly, there may be need for capability information for other modes,
so allow this to be provided with both add_station and change_station.
Signed-off-by: default avatarJouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent c6f9d6c3
...@@ -626,12 +626,14 @@ enum plink_actions { ...@@ -626,12 +626,14 @@ enum plink_actions {
/** /**
* enum station_parameters_apply_mask - station parameter values to apply * enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
* @STATION_PARAM_APPLY_CAPABILITY: apply new capability
* *
* Not all station parameters have in-band "no change" signalling, * Not all station parameters have in-band "no change" signalling,
* for those that don't these flags will are used. * for those that don't these flags will are used.
*/ */
enum station_parameters_apply_mask { enum station_parameters_apply_mask {
STATION_PARAM_APPLY_UAPSD = BIT(0), STATION_PARAM_APPLY_UAPSD = BIT(0),
STATION_PARAM_APPLY_CAPABILITY = BIT(1),
}; };
/** /**
...@@ -662,6 +664,9 @@ enum station_parameters_apply_mask { ...@@ -662,6 +664,9 @@ enum station_parameters_apply_mask {
* see &enum station_parameters_apply_mask * see &enum station_parameters_apply_mask
* @local_pm: local link-specific mesh power save mode (no change when set * @local_pm: local link-specific mesh power save mode (no change when set
* to unknown) * to unknown)
* @capability: station capability
* @ext_capab: extended capabilities of the station
* @ext_capab_len: number of extended capabilities
*/ */
struct station_parameters { struct station_parameters {
u8 *supported_rates; u8 *supported_rates;
...@@ -678,6 +683,9 @@ struct station_parameters { ...@@ -678,6 +683,9 @@ struct station_parameters {
u8 uapsd_queues; u8 uapsd_queues;
u8 max_sp; u8 max_sp;
enum nl80211_mesh_power_mode local_pm; enum nl80211_mesh_power_mode local_pm;
u16 capability;
u8 *ext_capab;
u8 ext_capab_len;
}; };
/** /**
......
...@@ -1361,6 +1361,13 @@ enum nl80211_commands { ...@@ -1361,6 +1361,13 @@ enum nl80211_commands {
* @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver * @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver
* has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields. * has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields.
* *
* @NL80211_ATTR_STA_CAPABILITY: Station capabilities (u16) are advertised to
* the driver, e.g., to enable TDLS power save (PU-APSD).
*
* @NL80211_ATTR_STA_EXT_CAPABILITY: Station extended capabilities are
* advertised to the driver, e.g., to enable TDLS off channel operations
* and PU-APSD.
*
* @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
*/ */
...@@ -1644,6 +1651,9 @@ enum nl80211_attrs { ...@@ -1644,6 +1651,9 @@ enum nl80211_attrs {
NL80211_ATTR_EXT_CAPA, NL80211_ATTR_EXT_CAPA,
NL80211_ATTR_EXT_CAPA_MASK, NL80211_ATTR_EXT_CAPA_MASK,
NL80211_ATTR_STA_CAPABILITY,
NL80211_ATTR_STA_EXT_CAPABILITY,
/* 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,
......
...@@ -368,6 +368,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { ...@@ -368,6 +368,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
[NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
[NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
}; };
/* policy for the key attributes */ /* policy for the key attributes */
...@@ -3435,6 +3437,19 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -3435,6 +3437,19 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
} }
if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
params.capability =
nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
}
if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
params.ext_capab =
nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
params.ext_capab_len =
nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
}
if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL] || if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL] ||
info->attrs[NL80211_ATTR_HT_CAPABILITY]) info->attrs[NL80211_ATTR_HT_CAPABILITY])
return -EINVAL; return -EINVAL;
...@@ -3505,6 +3520,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -3505,6 +3520,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
/* reject other things that can't change */ /* reject other things that can't change */
if (params.supported_rates) if (params.supported_rates)
return -EINVAL; return -EINVAL;
if (info->attrs[NL80211_ATTR_STA_CAPABILITY])
return -EINVAL;
if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY])
return -EINVAL;
/* must be last in here for error handling */ /* must be last in here for error handling */
params.vlan = get_vlan(info, rdev); params.vlan = get_vlan(info, rdev);
...@@ -3537,6 +3556,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -3537,6 +3556,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
if (params.supported_rates) if (params.supported_rates)
return -EINVAL; return -EINVAL;
if (info->attrs[NL80211_ATTR_STA_CAPABILITY])
return -EINVAL;
if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY])
return -EINVAL;
/* /*
* No special handling for TDLS here -- the userspace * No special handling for TDLS here -- the userspace
* mesh code doesn't have this bug. * mesh code doesn't have this bug.
...@@ -3601,6 +3624,19 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) ...@@ -3601,6 +3624,19 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (!params.aid || params.aid > IEEE80211_MAX_AID) if (!params.aid || params.aid > IEEE80211_MAX_AID)
return -EINVAL; return -EINVAL;
if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) {
params.capability =
nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]);
params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY;
}
if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) {
params.ext_capab =
nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
params.ext_capab_len =
nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]);
}
if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
params.ht_capa = params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
......
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