|
@@ -354,6 +354,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
|
[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
|
|
|
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
|
|
|
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
|
|
|
+ [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
|
|
|
};
|
|
|
|
|
|
/* policy for the key attributes */
|
|
@@ -1759,11 +1760,17 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|
|
(cfg80211_rdev_list_generation << 2)))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
- if (rdev->monitor_channel) {
|
|
|
- if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
|
|
- rdev->monitor_channel->center_freq) ||
|
|
|
- nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
|
|
|
- rdev->monitor_channel_type))
|
|
|
+ if (rdev->ops->get_channel) {
|
|
|
+ struct ieee80211_channel *chan;
|
|
|
+ enum nl80211_channel_type channel_type;
|
|
|
+
|
|
|
+ chan = rdev->ops->get_channel(&rdev->wiphy, wdev,
|
|
|
+ &channel_type);
|
|
|
+ if (chan &&
|
|
|
+ (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
|
|
+ chan->center_freq) ||
|
|
|
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
|
|
|
+ channel_type)))
|
|
|
goto nla_put_failure;
|
|
|
}
|
|
|
|
|
@@ -3576,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
|
|
{
|
|
|
int r;
|
|
|
char *data = NULL;
|
|
|
+ enum nl80211_user_reg_hint_type user_reg_hint_type;
|
|
|
|
|
|
/*
|
|
|
* You should only get this when cfg80211 hasn't yet initialized
|
|
@@ -3595,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
|
|
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
|
|
|
|
|
|
- r = regulatory_hint_user(data);
|
|
|
+ if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
|
|
|
+ user_reg_hint_type =
|
|
|
+ nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
|
|
|
+ else
|
|
|
+ user_reg_hint_type = NL80211_USER_REG_HINT_USER;
|
|
|
+
|
|
|
+ switch (user_reg_hint_type) {
|
|
|
+ case NL80211_USER_REG_HINT_USER:
|
|
|
+ case NL80211_USER_REG_HINT_CELL_BASE:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ r = regulatory_hint_user(data, user_reg_hint_type);
|
|
|
|
|
|
return r;
|
|
|
}
|
|
@@ -3965,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
|
|
|
cfg80211_regdomain->dfs_region)))
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
+ if (reg_last_request_cell_base() &&
|
|
|
+ nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
|
|
|
+ NL80211_USER_REG_HINT_CELL_BASE))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
|
|
|
if (!nl_reg_rules)
|
|
|
goto nla_put_failure;
|
|
@@ -6261,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
|
|
|
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
|
|
|
[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 },
|
|
|
+ [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
|
|
|
+ [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
|
|
|
};
|
|
|
|
|
|
+static int nl80211_set_cqm_txe(struct genl_info *info,
|
|
|
+ u32 rate, u32 pkts, u32 intvl)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
+ struct wireless_dev *wdev;
|
|
|
+ struct net_device *dev = info->user_ptr[1];
|
|
|
+
|
|
|
+ if ((rate < 0 || rate > 100) ||
|
|
|
+ (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ wdev = dev->ieee80211_ptr;
|
|
|
+
|
|
|
+ if (!rdev->ops->set_cqm_txe_config)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
|
|
|
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev,
|
|
|
+ rate, pkts, intvl);
|
|
|
+}
|
|
|
+
|
|
|
static int nl80211_set_cqm_rssi(struct genl_info *info,
|
|
|
s32 threshold, u32 hysteresis)
|
|
|
{
|
|
@@ -6310,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
|
|
|
threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
|
|
hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
|
|
|
err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
|
|
|
+ } else if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
|
|
|
+ attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
|
|
|
+ attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
|
|
|
+ u32 rate, pkts, intvl;
|
|
|
+ rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
|
|
|
+ pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
|
|
|
+ intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
|
|
|
+ err = nl80211_set_cqm_txe(info, rate, pkts, intvl);
|
|
|
} else
|
|
|
err = -EINVAL;
|
|
|
|
|
@@ -6466,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|
|
{
|
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
|
|
|
- struct cfg80211_wowlan no_triggers = {};
|
|
|
struct cfg80211_wowlan new_triggers = {};
|
|
|
+ struct cfg80211_wowlan *ntrig;
|
|
|
struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
|
|
|
int err, i;
|
|
|
bool prev_enabled = rdev->wowlan;
|
|
@@ -6475,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS])
|
|
|
- goto no_triggers;
|
|
|
+ if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
|
|
|
+ cfg80211_rdev_free_wowlan(rdev);
|
|
|
+ rdev->wowlan = NULL;
|
|
|
+ goto set_wakeup;
|
|
|
+ }
|
|
|
|
|
|
err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
|
|
|
nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
|
|
@@ -6587,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) {
|
|
|
- struct cfg80211_wowlan *ntrig;
|
|
|
- ntrig = kmemdup(&new_triggers, sizeof(new_triggers),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!ntrig) {
|
|
|
- err = -ENOMEM;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- cfg80211_rdev_free_wowlan(rdev);
|
|
|
- rdev->wowlan = ntrig;
|
|
|
- } else {
|
|
|
- no_triggers:
|
|
|
- cfg80211_rdev_free_wowlan(rdev);
|
|
|
- rdev->wowlan = NULL;
|
|
|
+ ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
|
|
|
+ if (!ntrig) {
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto error;
|
|
|
}
|
|
|
+ cfg80211_rdev_free_wowlan(rdev);
|
|
|
+ rdev->wowlan = ntrig;
|
|
|
|
|
|
+ set_wakeup:
|
|
|
if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
|
|
|
rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
|
|
|
|
|
@@ -8099,7 +8157,7 @@ static void nl80211_send_remain_on_chan_event(
|
|
|
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
|
|
(wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
|
|
|
wdev->netdev->ifindex)) ||
|
|
|
- nla_put_u32(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
|
|
|
+ nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
|
|
|
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
|
|
|
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) ||
|
|
|
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
|
|
@@ -8493,6 +8551,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
|
|
|
nlmsg_free(msg);
|
|
|
}
|
|
|
|
|
|
+void
|
|
|
+nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
|
|
|
+ struct net_device *netdev, const u8 *peer,
|
|
|
+ u32 num_packets, u32 rate, u32 intvl, gfp_t gfp)
|
|
|
+{
|
|
|
+ struct sk_buff *msg;
|
|
|
+ struct nlattr *pinfoattr;
|
|
|
+ void *hdr;
|
|
|
+
|
|
|
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
|
|
|
+ if (!msg)
|
|
|
+ return;
|
|
|
+
|
|
|
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
|
|
+ if (!hdr) {
|
|
|
+ nlmsg_free(msg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
|
|
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
|
|
|
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
|
|
|
+ if (!pinfoattr)
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
|
|
|
+ goto nla_put_failure;
|
|
|
+
|
|
|
+ nla_nest_end(msg, pinfoattr);
|
|
|
+
|
|
|
+ genlmsg_end(msg, hdr);
|
|
|
+
|
|
|
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
|
|
+ nl80211_mlme_mcgrp.id, gfp);
|
|
|
+ return;
|
|
|
+
|
|
|
+ nla_put_failure:
|
|
|
+ genlmsg_cancel(msg, hdr);
|
|
|
+ nlmsg_free(msg);
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
|
|
|
struct net_device *netdev, const u8 *peer,
|