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: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Jouni Malinen
2013-02-14 21:10:13 +02:00
committed by Johannes Berg
parent c6f9d6c3bd
commit 9d62a98617
3 changed files with 54 additions and 0 deletions

View File

@@ -368,6 +368,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
[NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
[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 */
@@ -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]);
}
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] ||
info->attrs[NL80211_ATTR_HT_CAPABILITY])
return -EINVAL;
@@ -3505,6 +3520,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
/* reject other things that can't change */
if (params.supported_rates)
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 */
params.vlan = get_vlan(info, rdev);
@@ -3537,6 +3556,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
if (params.supported_rates)
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
* mesh code doesn't have this bug.
@@ -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)
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])
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);