Add bandwidth and center freq info to signal_poll
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Sat, 22 Jun 2013 08:56:24 +0000 (11:56 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 22 Jun 2013 09:00:46 +0000 (12:00 +0300)
Signed-hostap: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-hostap: Ilan Peer <ilan.peer@intel.com>

src/drivers/driver.h
src/drivers/driver_nl80211.c
wpa_supplicant/ctrl_iface.c

index 03fc2b3..8da99e6 100644 (file)
@@ -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;
 };
 
 /**
index e36374f..5a4f4a9 100644 (file)
@@ -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);
 }
 
index 49157bf..0c81ed3 100644 (file)
@@ -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;
 }