Add bandwidth and center freq info to signal_poll

Signed-hostap: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-hostap: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
Andrei Otcheretianski 2013-06-22 11:56:24 +03:00 committed by Jouni Malinen
parent 1e0e943e19
commit 2cc8d8f4e8
3 changed files with 135 additions and 3 deletions

View 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;
};
/**

View 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);
}

View 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;
}