aboutsummaryrefslogtreecommitdiff
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4dc139cdba5..5c8b3bfada4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3245,6 +3245,106 @@ static int nl80211_dump_scan(struct sk_buff *skb,
return err;
}
+static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
+ int flags, struct net_device *dev,
+ struct survey_info *survey)
+{
+ void *hdr;
+ struct nlattr *infoattr;
+
+ /* Survey without a channel doesn't make sense */
+ if (!survey->channel)
+ return -EINVAL;
+
+ hdr = nl80211hdr_put(msg, pid, seq, flags,
+ NL80211_CMD_NEW_SURVEY_RESULTS);
+ if (!hdr)
+ return -ENOMEM;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+
+ infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
+ if (!infoattr)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY,
+ survey->channel->center_freq);
+ if (survey->filled & SURVEY_INFO_NOISE_DBM)
+ NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
+ survey->noise);
+
+ nla_nest_end(msg, infoattr);
+
+ return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int nl80211_dump_survey(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct survey_info survey;
+ struct cfg80211_registered_device *dev;
+ struct net_device *netdev;
+ int ifidx = cb->args[0];
+ int survey_idx = cb->args[1];
+ int res;
+
+ if (!ifidx)
+ ifidx = nl80211_get_ifidx(cb);
+ if (ifidx < 0)
+ return ifidx;
+ cb->args[0] = ifidx;
+
+ rtnl_lock();
+
+ netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
+ if (!netdev) {
+ res = -ENODEV;
+ goto out_rtnl;
+ }
+
+ dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
+ if (IS_ERR(dev)) {
+ res = PTR_ERR(dev);
+ goto out_rtnl;
+ }
+
+ if (!dev->ops->dump_survey) {
+ res = -EOPNOTSUPP;
+ goto out_err;
+ }
+
+ while (1) {
+ res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
+ &survey);
+ if (res == -ENOENT)
+ break;
+ if (res)
+ goto out_err;
+
+ if (nl80211_send_survey(skb,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ netdev,
+ &survey) < 0)
+ goto out;
+ survey_idx++;
+ }
+
+ out:
+ cb->args[1] = survey_idx;
+ res = skb->len;
+ out_err:
+ cfg80211_unlock_rdev(dev);
+ out_rtnl:
+ rtnl_unlock();
+
+ return res;
+}
+
static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
{
return auth_type <= NL80211_AUTHTYPE_MAX;
@@ -4322,6 +4422,11 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_GET_SURVEY,
+ .policy = nl80211_policy,
+ .dumpit = nl80211_dump_survey,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
.name = "mlme",