From patchwork Tue Nov 10 16:23:11 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Holger Schurig X-Patchwork-Id: 59090 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nAAGNuhD016145 for ; Tue, 10 Nov 2009 16:23:56 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754792AbZKJQXt (ORCPT ); Tue, 10 Nov 2009 11:23:49 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1756137AbZKJQXt (ORCPT ); Tue, 10 Nov 2009 11:23:49 -0500 Received: from mx51.mymxserver.com ([85.199.173.110]:8662 "EHLO mx51.mymxserver.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754269AbZKJQXs (ORCPT ); Tue, 10 Nov 2009 11:23:48 -0500 Received: from localhost (localhost [127.0.0.1]) by localhost.mx51.mymxserver.com (Postfix) with ESMTP id 9E6A05000A; Tue, 10 Nov 2009 17:23:53 +0100 (CET) X-Virus-Scanned: by Mittwald Mailscanner Received: from mx51.mymxserver.com ([127.0.0.1]) by localhost (mx51.mymxserver.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2CQB8M+XKE6r; Tue, 10 Nov 2009 17:23:53 +0100 (CET) Received: from lin01.mn-solutions.de (pD95F8B6C.dip0.t-ipconnect.de [217.95.139.108]) by mx51.mymxserver.com (Postfix) with ESMTP id 34B7C50004; Tue, 10 Nov 2009 17:23:52 +0100 (CET) Received: by lin01.mn-solutions.de (Postfix, from userid 116) id 88CE31E0050; Tue, 10 Nov 2009 17:23:52 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.1.7-deb3 (2006-10-05) on lin01.mn-logistik.de X-Spam-Level: X-Spam-Status: No, score=-4.4 required=5.0 tests=ALL_TRUSTED,BAYES_00 autolearn=ham version=3.1.7-deb3 Received: from schurig.mn-solutions.de (mnz66.mn-solutions.de [192.168.233.66]) by lin01.mn-solutions.de (Postfix) with ESMTP id 0DB381E0010; Tue, 10 Nov 2009 17:23:44 +0100 (CET) From: Holger Schurig To: linux-wireless@vger.kernel.org Subject: [RFC, v3] cfg80211: first stab at channel survey Date: Tue, 10 Nov 2009 17:23:11 +0100 User-Agent: KMail/1.9.7 Cc: Johannes Berg MIME-Version: 1.0 Content-Disposition: inline Message-Id: <200911101723.11304.holgerschurig@gmail.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org --- linux-wl.orig/include/linux/nl80211.h +++ linux-wl/include/linux/nl80211.h @@ -160,6 +160,11 @@ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, * partial scan results may be available * + * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation + * or noise level + * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to + * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) + * * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain * has been changed and provides details of the request information * that caused the change such as who initiated the regulatory request @@ -341,6 +346,9 @@ NL80211_CMD_SET_WIPHY_NETNS, + NL80211_CMD_GET_SURVEY, + NL80211_CMD_NEW_SURVEY_RESULTS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -584,6 +592,10 @@ * changed then the list changed and the dump should be repeated * completely from scratch. * + * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of + * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute + * containing info as possible, see &enum survey_info. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -714,6 +726,8 @@ NL80211_ATTR_PID, + NL80211_ATTR_SURVEY_INFO, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1117,6 +1131,26 @@ }; /** + * enum nl80211_survey_info - survey information + * + * These attribute types are used with %NL80211_ATTR_SURVEY_INFO + * when getting information about a survey. + * + * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved + * @NL80211_SURVEY_FREQUENCY: center frequency of channel + * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) + */ +enum nl80211_survey_info { + __NL80211_SURVEY_INFO_INVALID, + NL80211_SURVEY_FREQUENCY, + NL80211_SURVEY_INFO_NOISE, + + /* keep last */ + __NL80211_SURVEY_INFO_AFTER_LAST, + NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 +}; + +/** * enum nl80211_mntr_flags - monitor configuration flags * * Monitor configuration flags. --- linux-wl.orig/include/net/cfg80211.h +++ linux-wl/include/net/cfg80211.h @@ -233,6 +233,35 @@ }; /** + * enum survey_info_flags - survey information flags + * + * Used by the driver to indicate which info in &struct survey_info + * it has filled in during the get_survey(). + */ +enum survey_info_flags { + SURVEY_INFO_NOISE_DBM = 1<<0, +}; + +/** + * struct survey_info - channel survey response + * + * Used by dump_survey() to report back per-channel survey information. + * + * @channel: the channel this survey record reports, mandatory + * @filled: bitflag of flags from &enum survey_info_flags + * @noise: channel noise in dBm. This and all following fields are + * optional + * + * This structure can later be expanded with things like + * channel duty cycle etc. + */ +struct survey_info { + struct ieee80211_channel *channel; + u32 filled; + s8 noise; +}; + +/** * struct beacon_parameters - beacon parameters * * Used to configure the beacon for an interface. @@ -941,6 +970,8 @@ * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting * functions to adjust rfkill hw state * + * @dump_survey: get site survey information. + * * @testmode_cmd: run a test mode command */ struct cfg80211_ops { @@ -1060,6 +1091,9 @@ const u8 *peer, const struct cfg80211_bitrate_mask *mask); + int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev, + int idx, struct survey_info *info); + /* some temporary stuff to finish wext */ int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); --- linux-wl.orig/net/wireless/nl80211.c +++ linux-wl/net/wireless/nl80211.c @@ -3229,6 +3229,108 @@ 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 -1; + + hdr = nl80211hdr_put(msg, pid, seq, flags, + NL80211_CMD_NEW_SURVEY_RESULTS); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + + infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); + if (!infoattr) + goto nla_put_failure; + + /* I could possibly use nl80211_msg_put_channel() and nest this into my + * own NL80211_SURVEY_FREQUENCY. Would that be a better interface or + * would all those regulatory fields distract us? */ + NLA_PUT_U32(msg, NL80211_SURVEY_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 err; + + if (!ifidx) + ifidx = nl80211_get_ifidx(cb); + if (ifidx < 0) + return ifidx; + + rtnl_lock(); + + netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); + if (!netdev) { + err = -ENODEV; + goto out_rtnl; + } + + dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_rtnl; + } + + if (!dev->ops->dump_survey) { + err = -EOPNOTSUPP; + goto out_err; + } + + while (1) { + err = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, + &survey); + if (err == -ENOENT) + break; + if (err) + 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; + err = skb->len; + out_err: + cfg80211_unlock_rdev(dev); + out_rtnl: + rtnl_unlock(); + + return err; +} + static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) { return auth_type <= NL80211_AUTHTYPE_MAX; @@ -4306,6 +4408,11 @@ .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",