From 2cc8d8f4e8ac87d03ec6d20cbe18594433b12e14 Mon Sep 17 00:00:00 2001 From: Andrei Otcheretianski Date: Sat, 22 Jun 2013 11:56:24 +0300 Subject: [PATCH] Add bandwidth and center freq info to signal_poll Signed-hostap: Andrei Otcheretianski Signed-hostap: Ilan Peer --- src/drivers/driver.h | 14 +++++++++ src/drivers/driver_nl80211.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ wpa_supplicant/ctrl_iface.c | 51 +++++++++++++++++++++++++++++-- 3 files changed, 135 insertions(+), 3 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 03fc2b3..8da99e6 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1090,6 +1090,17 @@ enum wnm_oper { WNM_SLEEP_TFS_IE_DEL /* AP delete the TFS IE */ }; +/* enum chan_width - Channel width definitions */ +enum chan_width { + CHAN_WIDTH_20_NOHT, + CHAN_WIDTH_20, + CHAN_WIDTH_40, + CHAN_WIDTH_80, + CHAN_WIDTH_80P80, + CHAN_WIDTH_160, + CHAN_WIDTH_UNKNOWN +}; + /** * struct wpa_signal_info - Information about channel signal quality */ @@ -1099,6 +1110,9 @@ struct wpa_signal_info { int current_signal; int current_noise; int current_txrate; + enum chan_width chanwidth; + int center_frq1; + int center_frq2; }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index e36374f..5a4f4a9 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -9330,6 +9330,75 @@ nla_put_failure: } +/* Converts nl80211_chan_width to a common format */ +static enum chan_width convert2width(int width) +{ + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + return CHAN_WIDTH_20_NOHT; + case NL80211_CHAN_WIDTH_20: + return CHAN_WIDTH_20; + case NL80211_CHAN_WIDTH_40: + return CHAN_WIDTH_40; + case NL80211_CHAN_WIDTH_80: + return CHAN_WIDTH_80; + case NL80211_CHAN_WIDTH_80P80: + return CHAN_WIDTH_80P80; + case NL80211_CHAN_WIDTH_160: + return CHAN_WIDTH_160; + } + return CHAN_WIDTH_UNKNOWN; +} + + +static int get_channel_width(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wpa_signal_info *sig_change = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + sig_change->center_frq1 = -1; + sig_change->center_frq2 = -1; + sig_change->chanwidth = CHAN_WIDTH_UNKNOWN; + + if (tb[NL80211_ATTR_CHANNEL_WIDTH]) { + sig_change->chanwidth = convert2width( + nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH])); + if (tb[NL80211_ATTR_CENTER_FREQ1]) + sig_change->center_frq1 = + nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]); + if (tb[NL80211_ATTR_CENTER_FREQ2]) + sig_change->center_frq2 = + nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); + } + + return NL_SKIP; +} + + +static int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv, + struct wpa_signal_info *sig) +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + return send_and_recv_msgs(drv, msg, get_channel_width, sig); + +nla_put_failure: + nlmsg_free(msg); + return -ENOBUFS; +} + + static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) { struct i802_bss *bss = priv; @@ -9341,6 +9410,10 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) if (res != 0) return res; + res = nl80211_get_channel_width(drv, si); + if (res != 0) + return res; + return nl80211_get_link_noise(drv, si); } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 49157bf..0c81ed3 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4999,23 +4999,68 @@ static int wpas_ctrl_iface_wnm_bss_query(struct wpa_supplicant *wpa_s, char *cmd #endif /* CONFIG_WNM */ +/* Get string representation of channel width */ +static const char * channel_width_name(enum chan_width width) +{ + switch (width) { + case CHAN_WIDTH_20_NOHT: + return "20 MHz (no HT)"; + case CHAN_WIDTH_20: + return "20 MHz"; + case CHAN_WIDTH_40: + return "40 MHz"; + case CHAN_WIDTH_80: + return "80 MHz"; + case CHAN_WIDTH_80P80: + return "80+80 MHz"; + case CHAN_WIDTH_160: + return "160 MHz"; + default: + return "unknown"; + } +} + + static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, size_t buflen) { struct wpa_signal_info si; int ret; + char *pos, *end; ret = wpa_drv_signal_poll(wpa_s, &si); if (ret) return -1; - ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n" + pos = buf; + end = buf + buflen; + + ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n" "NOISE=%d\nFREQUENCY=%u\n", si.current_signal, si.current_txrate / 1000, si.current_noise, si.frequency); - if (ret < 0 || (unsigned int) ret > buflen) + if (ret < 0 || ret > end - pos) return -1; - return ret; + pos += ret; + + if (si.chanwidth != CHAN_WIDTH_UNKNOWN) { + ret = os_snprintf(pos, end - pos, "WIDTH=%s\n", + channel_width_name(si.chanwidth)); + if (ret < 0 || ret > end - pos) + return -1; + pos += ret; + } + + if (si.center_frq1 > 0 && si.center_frq2 > 0) { + ret = os_snprintf(pos, end - pos, + "CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n", + si.center_frq1, si.center_frq2); + if (ret < 0 || ret > end - pos) + return -1; + pos += ret; + } + + return pos - buf; } -- 2.1.4