|
@@ -6267,8 +6267,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
|
|
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .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,
|
|
static int nl80211_set_cqm_rssi(struct genl_info *info,
|
|
s32 threshold, u32 hysteresis)
|
|
s32 threshold, u32 hysteresis)
|
|
{
|
|
{
|
|
@@ -6316,6 +6343,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
|
|
threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
|
threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
|
hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
|
|
hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
|
|
err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
|
|
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
|
|
} else
|
|
err = -EINVAL;
|
|
err = -EINVAL;
|
|
|
|
|
|
@@ -8495,6 +8530,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
|
|
nlmsg_free(msg);
|
|
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
|
|
void
|
|
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
|
|
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
|
|
struct net_device *netdev, const u8 *peer,
|
|
struct net_device *netdev, const u8 *peer,
|