[01/25] Add driver API to get current channel parameters

Message ID 20180806194643.1328-2-Mathy.Vanhoef@cs.kuleuven.be
State New
Headers show
Series
  • Add support for Operating Channel Validation (OCV)
Related show

Commit Message

Mathy Vanhoef Aug. 6, 2018, 7:46 p.m.
This adds driver API functions to get the current operating channel
parameters. This encompasses the center frequency, channel bandwidth,
frequency segment 1 index (for 80+80 channels), and so on.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
---
 src/drivers/driver.h         | 27 ++++++++++++++++
 src/drivers/driver_nl80211.c | 63 ++++++++++++++++++++++++++++++++++++
 src/drivers/driver_nl80211.h |  2 ++
 3 files changed, 92 insertions(+)

Patch

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 9922962ea..b111fbecb 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1915,6 +1915,26 @@  struct wpa_signal_info {
 	int center_frq2;
 };
 
+/**
+ * struct wpa_signal_info - Information about the current channel
+ * @frequency: Center frequency of the primary 20 MHz channel
+ * @chanwidth: Width of the current operating channel
+ * @sec_channel: Location of the secondary 20 MHz channel (either +1 or -1).
+ *  This field is only filled in when using a 40 MHz channel.
+ * @center_frq1: Center frequency of frequency segment 0
+ * @center_frq2: Center frequency of frequency segment 1 (for 80+80 channels)
+ * @seg1_idx: Frequency segment 1 index when using a 80+80 channel. This is
+ *  derived from center_frq2 for convenience.
+ */
+struct wpa_channel_info {
+	u32 frequency;
+	enum chan_width chanwidth;
+	int sec_channel;
+	int center_frq1;
+	int center_frq2;
+	int seg1_idx;
+};
+
 /**
  * struct beacon_data - Beacon data
  * @head: Head portion of Beacon frame (before TIM IE)
@@ -3350,6 +3370,13 @@  struct wpa_driver_ops {
 	 */
 	int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
 
+	/**
+	 * channel_info - Get parameters of the current operating channel
+	 * @priv: Private driver interface data
+	 * @channel_info: Channel info structure
+	 */
+	int (*channel_info)(void *priv, struct wpa_channel_info *channel_info);
+
 	/**
 	 * set_authmode - Set authentication algorithm(s) for static WEP
 	 * @priv: Private driver interface data
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 16bae4907..cdeec86af 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1484,6 +1484,68 @@  int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static int get_channel_info(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1] = {0};
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wpa_channel_info *chan_info = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	memset(chan_info, 0, sizeof(struct wpa_channel_info));
+	chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+	if (tb[NL80211_ATTR_WIPHY_FREQ])
+		chan_info->frequency =
+			nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+	if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+		chan_info->chanwidth = convert2width(
+			nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+		enum nl80211_channel_type ct =
+			nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+		switch (ct) {
+		case NL80211_CHAN_HT40MINUS:
+			chan_info->sec_channel = -1;
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			chan_info->sec_channel = 1;
+			break;
+		default:
+			chan_info->sec_channel = 0;
+			break;
+		}
+	}
+	if (tb[NL80211_ATTR_CENTER_FREQ1])
+		chan_info->center_frq1 =
+			nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+	if (tb[NL80211_ATTR_CENTER_FREQ2])
+		chan_info->center_frq2 =
+			nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+	if (chan_info->center_frq2) {
+		u8 seg1_idx = 0;
+		ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx);
+		chan_info->seg1_idx = seg1_idx;
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+	return send_and_recv_msgs(drv, msg, get_channel_info, ci);
+}
+
+
 static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
 					     void *handle)
 {
@@ -10637,6 +10699,7 @@  const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.resume = wpa_driver_nl80211_resume,
 	.signal_monitor = nl80211_signal_monitor,
 	.signal_poll = nl80211_signal_poll,
+	.channel_info = nl80211_channel_info,
 	.send_frame = nl80211_send_frame,
 	.set_param = nl80211_set_param,
 	.get_radio_name = nl80211_get_radio_name,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 5ac0c7dfc..143ff1346 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -247,6 +247,8 @@  int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
 			    struct wpa_signal_info *sig);
 int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
 			   struct wpa_signal_info *sig_change);
+int nl80211_get_channel_info(struct wpa_driver_nl80211_data *drv,
+			     struct wpa_channel_info *chan);
 int nl80211_get_wiphy_index(struct i802_bss *bss);
 int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
 				enum nl80211_iftype nlmode);