Merge tag 'mac80211-next-for-davem-2017-04-18' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says: ==================== My last pull request has been a while, we now have: * connection quality monitoring with multiple thresholds * support for FILS shared key authentication offload * pre-CAC regulatory compliance - only ETSI allows this * sanity check for some rate confusion that hit ChromeOS (but nobody else uses it, evidently) * some documentation updates * lots of cleanups ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
这个提交包含在:
@@ -410,6 +410,15 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
.len = sizeof(struct nl80211_bss_select_rssi_adjust)
|
||||
},
|
||||
[NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
|
||||
.len = FILS_ERP_MAX_USERNAME_LEN },
|
||||
[NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
|
||||
.len = FILS_ERP_MAX_REALM_LEN },
|
||||
[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
|
||||
.len = FILS_ERP_MAX_RRK_LEN },
|
||||
[NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
|
||||
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -2705,9 +2714,74 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
|
||||
if (flags[flag])
|
||||
*mntrflags |= (1<<flag);
|
||||
|
||||
*mntrflags |= MONITOR_FLAG_CHANGED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype type,
|
||||
struct genl_info *info,
|
||||
struct vif_params *params)
|
||||
{
|
||||
bool change = false;
|
||||
int err;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
|
||||
if (type != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
|
||||
err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
|
||||
¶ms->flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (params->flags & MONITOR_FLAG_ACTIVE &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
|
||||
const u8 *mumimo_groups;
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (type != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mumimo_groups =
|
||||
nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
|
||||
|
||||
/* bits 0 and 63 are reserved and must be zero */
|
||||
if ((mumimo_groups[0] & BIT(7)) ||
|
||||
(mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
|
||||
return -EINVAL;
|
||||
|
||||
params->vht_mumimo_groups = mumimo_groups;
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (type != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
params->vht_mumimo_follow_addr =
|
||||
nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]);
|
||||
change = true;
|
||||
}
|
||||
|
||||
return change ? 1 : 0;
|
||||
}
|
||||
|
||||
static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u8 use_4addr,
|
||||
enum nl80211_iftype iftype)
|
||||
@@ -2741,7 +2815,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
int err;
|
||||
enum nl80211_iftype otype, ntype;
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
u32 _flags, *flags = NULL;
|
||||
bool change = false;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
@@ -2784,56 +2857,14 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
params.use_4addr = -1;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
|
||||
if (ntype != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
|
||||
&_flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
flags = &_flags;
|
||||
err = nl80211_parse_mon_options(rdev, ntype, info, ¶ms);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err > 0)
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
|
||||
const u8 *mumimo_groups;
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mumimo_groups =
|
||||
nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
|
||||
|
||||
/* bits 0 and 63 are reserved and must be zero */
|
||||
if ((mumimo_groups[0] & BIT(7)) ||
|
||||
(mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(params.vht_mumimo_groups, mumimo_groups,
|
||||
VHT_MUMIMO_GROUPS_DATA_LEN);
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
nla_memcpy(params.macaddr,
|
||||
info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR],
|
||||
ETH_ALEN);
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (change)
|
||||
err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms);
|
||||
err = cfg80211_change_iface(rdev, dev, ntype, ¶ms);
|
||||
else
|
||||
err = 0;
|
||||
|
||||
@@ -2851,7 +2882,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
struct sk_buff *msg;
|
||||
int err;
|
||||
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
||||
u32 flags;
|
||||
|
||||
/* to avoid failing a new interface creation due to pending removal */
|
||||
cfg80211_destroy_ifaces(rdev);
|
||||
@@ -2887,13 +2917,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
|
||||
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
|
||||
&flags);
|
||||
|
||||
if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
err = nl80211_parse_mon_options(rdev, type, info, ¶ms);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
@@ -2901,8 +2927,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
wdev = rdev_add_virtual_intf(rdev,
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
|
||||
NET_NAME_USER, type, err ? NULL : &flags,
|
||||
¶ms);
|
||||
NET_NAME_USER, type, ¶ms);
|
||||
if (WARN_ON(!wdev)) {
|
||||
nlmsg_free(msg);
|
||||
return -EPROTO;
|
||||
@@ -3820,6 +3845,19 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
|
||||
return false;
|
||||
return true;
|
||||
case NL80211_CMD_CONNECT:
|
||||
/* SAE not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_SAE)
|
||||
return false;
|
||||
/* FILS with SK PFS or PK not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
|
||||
auth_type == NL80211_AUTHTYPE_FILS_PK)
|
||||
return false;
|
||||
if (!wiphy_ext_feature_isset(
|
||||
&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
|
||||
auth_type == NL80211_AUTHTYPE_FILS_SK)
|
||||
return false;
|
||||
return true;
|
||||
case NL80211_CMD_START_AP:
|
||||
/* SAE not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_SAE)
|
||||
@@ -4153,7 +4191,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
struct nlattr *rate;
|
||||
u32 bitrate;
|
||||
u16 bitrate_compat;
|
||||
enum nl80211_attrs rate_flg;
|
||||
enum nl80211_rate_info rate_flg;
|
||||
|
||||
rate = nla_nest_start(msg, attr);
|
||||
if (!rate)
|
||||
@@ -5705,7 +5743,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
|
||||
cur_params.dot11MeshGateAnnouncementProtocol) ||
|
||||
nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
|
||||
cur_params.dot11MeshForwarding) ||
|
||||
nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
|
||||
nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
|
||||
cur_params.rssi_threshold) ||
|
||||
nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
|
||||
cur_params.ht_opmode) ||
|
||||
@@ -6548,6 +6586,19 @@ static int nl80211_parse_random_mac(struct nlattr **attrs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
|
||||
{
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!cfg80211_beaconing_iface_active(wdev))
|
||||
return true;
|
||||
|
||||
if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return true;
|
||||
|
||||
return regulatory_pre_cac_allowed(wdev->wiphy);
|
||||
}
|
||||
|
||||
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
@@ -6673,6 +6724,25 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
request->n_channels = i;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (!cfg80211_off_channel_oper_allowed(wdev)) {
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
if (request->n_channels != 1) {
|
||||
wdev_unlock(wdev);
|
||||
err = -EBUSY;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
chan = request->channels[0];
|
||||
if (chan->center_freq != wdev->chandef.chan->center_freq) {
|
||||
wdev_unlock(wdev);
|
||||
err = -EBUSY;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
i = 0;
|
||||
if (n_ssids) {
|
||||
nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
|
||||
@@ -7295,8 +7365,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
||||
|
||||
rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
|
||||
|
||||
nl80211_send_sched_scan(rdev, dev,
|
||||
NL80211_CMD_START_SCHED_SCAN);
|
||||
nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
@@ -8873,6 +8942,35 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
if (wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
|
||||
connect.fils_erp_username =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
|
||||
connect.fils_erp_username_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
|
||||
connect.fils_erp_realm =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
|
||||
connect.fils_erp_realm_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
|
||||
connect.fils_erp_next_seq_num =
|
||||
nla_get_u16(
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
|
||||
connect.fils_erp_rrk =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
|
||||
connect.fils_erp_rrk_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
|
||||
} else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
|
||||
kzfree(connkeys);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
|
||||
err = cfg80211_connect(rdev, dev, &connect, connkeys,
|
||||
@@ -8992,14 +9090,28 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC])
|
||||
return -EINVAL;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_PMKID])
|
||||
return -EINVAL;
|
||||
|
||||
pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
|
||||
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC]) {
|
||||
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
} else if (info->attrs[NL80211_ATTR_SSID] &&
|
||||
info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
|
||||
(info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
|
||||
info->attrs[NL80211_ATTR_PMK])) {
|
||||
pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
|
||||
pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
|
||||
pmksa.cache_id =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (info->attrs[NL80211_ATTR_PMK]) {
|
||||
pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
|
||||
pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
|
||||
}
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
@@ -9102,6 +9214,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct wireless_dev *wdev = info->user_ptr[1];
|
||||
struct cfg80211_chan_def chandef;
|
||||
const struct cfg80211_chan_def *compat_chandef;
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
u64 cookie;
|
||||
@@ -9130,6 +9243,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (!cfg80211_off_channel_oper_allowed(wdev) &&
|
||||
!cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
|
||||
compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
|
||||
&chandef);
|
||||
if (compat_chandef != &chandef) {
|
||||
wdev_unlock(wdev);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
@@ -9305,6 +9430,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!chandef.chan && params.offchan)
|
||||
return -EINVAL;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
|
||||
wdev_unlock(wdev);
|
||||
return -EBUSY;
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
|
||||
params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
|
||||
|
||||
@@ -9472,7 +9604,7 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
static const struct nla_policy
|
||||
nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
|
||||
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
|
||||
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
|
||||
@@ -9501,28 +9633,123 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
|
||||
return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
|
||||
}
|
||||
|
||||
static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
s32 last, low, high;
|
||||
u32 hyst;
|
||||
int i, n;
|
||||
int err;
|
||||
|
||||
/* RSSI reporting disabled? */
|
||||
if (!wdev->cqm_config)
|
||||
return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
|
||||
|
||||
/*
|
||||
* Obtain current RSSI value if possible, if not and no RSSI threshold
|
||||
* event has been received yet, we should receive an event after a
|
||||
* connection is established and enough beacons received to calculate
|
||||
* the average.
|
||||
*/
|
||||
if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
|
||||
rdev->ops->get_station) {
|
||||
struct station_info sinfo;
|
||||
u8 *mac_addr;
|
||||
|
||||
mac_addr = wdev->current_bss->pub.bssid;
|
||||
|
||||
err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
|
||||
wdev->cqm_config->last_rssi_event_value =
|
||||
(s8) sinfo.rx_beacon_signal_avg;
|
||||
}
|
||||
|
||||
last = wdev->cqm_config->last_rssi_event_value;
|
||||
hyst = wdev->cqm_config->rssi_hyst;
|
||||
n = wdev->cqm_config->n_rssi_thresholds;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (last < wdev->cqm_config->rssi_thresholds[i])
|
||||
break;
|
||||
|
||||
low = i > 0 ?
|
||||
(wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN;
|
||||
high = i < n ?
|
||||
(wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX;
|
||||
|
||||
return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
|
||||
}
|
||||
|
||||
static int nl80211_set_cqm_rssi(struct genl_info *info,
|
||||
s32 threshold, u32 hysteresis)
|
||||
const s32 *thresholds, int n_thresholds,
|
||||
u32 hysteresis)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int i, err;
|
||||
s32 prev = S32_MIN;
|
||||
|
||||
if (threshold > 0)
|
||||
return -EINVAL;
|
||||
/* Check all values negative and sorted */
|
||||
for (i = 0; i < n_thresholds; i++) {
|
||||
if (thresholds[i] > 0 || thresholds[i] <= prev)
|
||||
return -EINVAL;
|
||||
|
||||
/* disabling - hysteresis should also be zero then */
|
||||
if (threshold == 0)
|
||||
hysteresis = 0;
|
||||
|
||||
if (!rdev->ops->set_cqm_rssi_config)
|
||||
return -EOPNOTSUPP;
|
||||
prev = thresholds[i];
|
||||
}
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_STATION &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
|
||||
wdev_lock(wdev);
|
||||
cfg80211_cqm_config_free(wdev);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
|
||||
if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
|
||||
return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
|
||||
|
||||
return rdev_set_cqm_rssi_config(rdev, dev,
|
||||
thresholds[0], hysteresis);
|
||||
}
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_CQM_RSSI_LIST))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
|
||||
n_thresholds = 0;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (n_thresholds) {
|
||||
struct cfg80211_cqm_config *cqm_config;
|
||||
|
||||
cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
|
||||
n_thresholds * sizeof(s32), GFP_KERNEL);
|
||||
if (!cqm_config) {
|
||||
err = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
cqm_config->rssi_hyst = hysteresis;
|
||||
cqm_config->n_rssi_thresholds = n_thresholds;
|
||||
memcpy(cqm_config->rssi_thresholds, thresholds,
|
||||
n_thresholds * sizeof(s32));
|
||||
|
||||
wdev->cqm_config = cqm_config;
|
||||
}
|
||||
|
||||
err = cfg80211_cqm_rssi_update(rdev, dev);
|
||||
|
||||
unlock:
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
|
||||
@@ -9542,10 +9769,16 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
|
||||
attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
|
||||
s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
||||
const s32 *thresholds =
|
||||
nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
||||
int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
||||
u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
|
||||
|
||||
return nl80211_set_cqm_rssi(info, threshold, hysteresis);
|
||||
if (len % 4)
|
||||
return -EINVAL;
|
||||
|
||||
return nl80211_set_cqm_rssi(info, thresholds, len / 4,
|
||||
hysteresis);
|
||||
}
|
||||
|
||||
if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
|
||||
@@ -12977,18 +13210,19 @@ static int nl80211_prep_scan_msg(struct sk_buff *msg,
|
||||
|
||||
static int
|
||||
nl80211_prep_sched_scan_msg(struct sk_buff *msg,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
u32 portid, u32 seq, int flags, u32 cmd)
|
||||
struct cfg80211_sched_scan_request *req, u32 cmd)
|
||||
{
|
||||
void *hdr;
|
||||
|
||||
hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
|
||||
if (!hdr)
|
||||
return -1;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY,
|
||||
wiphy_to_rdev(req->wiphy)->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) ||
|
||||
nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid,
|
||||
NL80211_ATTR_PAD))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
@@ -13048,8 +13282,7 @@ void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
|
||||
NL80211_MCGRP_SCAN, GFP_KERNEL);
|
||||
}
|
||||
|
||||
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u32 cmd)
|
||||
void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
||||
@@ -13057,12 +13290,12 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
|
||||
if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0,
|
||||
NL80211_MCGRP_SCAN, GFP_KERNEL);
|
||||
}
|
||||
|
||||
@@ -13303,17 +13536,16 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
|
||||
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
int status,
|
||||
enum nl80211_timeout_reason timeout_reason,
|
||||
struct net_device *netdev,
|
||||
struct cfg80211_connect_resp_params *cr,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
|
||||
msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
|
||||
cr->fils_kek_len + cr->pmk_len +
|
||||
(cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
@@ -13325,17 +13557,31 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
|
||||
(bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
|
||||
(cr->bssid &&
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
|
||||
nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
|
||||
status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
|
||||
status) ||
|
||||
(status < 0 &&
|
||||
cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
|
||||
cr->status) ||
|
||||
(cr->status < 0 &&
|
||||
(nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
|
||||
(req_ie &&
|
||||
nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
|
||||
(resp_ie &&
|
||||
nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
|
||||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
|
||||
cr->timeout_reason))) ||
|
||||
(cr->req_ie &&
|
||||
nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
|
||||
(cr->resp_ie &&
|
||||
nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
|
||||
cr->resp_ie)) ||
|
||||
(cr->update_erp_next_seq_num &&
|
||||
nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
|
||||
cr->fils_erp_next_seq_num)) ||
|
||||
(cr->status == WLAN_STATUS_SUCCESS &&
|
||||
((cr->fils_kek &&
|
||||
nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
|
||||
cr->fils_kek)) ||
|
||||
(cr->pmk &&
|
||||
nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
|
||||
(cr->pmkid &&
|
||||
nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
@@ -13975,6 +14221,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
||||
s32 rssi_level, gfp_t gfp)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
|
||||
trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
|
||||
|
||||
@@ -13982,6 +14230,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
||||
rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
|
||||
return;
|
||||
|
||||
if (wdev->cqm_config) {
|
||||
wdev->cqm_config->last_rssi_event_value = rssi_level;
|
||||
|
||||
cfg80211_cqm_rssi_update(rdev, dev);
|
||||
|
||||
if (rssi_level == 0)
|
||||
rssi_level = wdev->cqm_config->last_rssi_event_value;
|
||||
}
|
||||
|
||||
msg = cfg80211_prepare_cqm(dev, NULL, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
在新工单中引用
屏蔽一个用户