Add driver API to get current channel parameters

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>
This commit is contained in:
Mathy Vanhoef 2018-08-06 15:46:19 -04:00 committed by Jouni Malinen
parent 183a6c93cd
commit 7f00dc6e15
4 changed files with 109 additions and 0 deletions

View file

@ -356,4 +356,12 @@ static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
return hapd->driver->stop_ap(hapd->drv_priv); return hapd->driver->stop_ap(hapd->drv_priv);
} }
static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
struct wpa_channel_info *ci)
{
if (!hapd->driver || !hapd->driver->channel_info)
return -1;
return hapd->driver->channel_info(hapd->drv_priv, ci);
}
#endif /* AP_DRV_OPS */ #endif /* AP_DRV_OPS */

View file

@ -1942,6 +1942,26 @@ struct wpa_signal_info {
int center_frq2; int center_frq2;
}; };
/**
* struct wpa_channel_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;
u8 seg1_idx;
};
/** /**
* struct beacon_data - Beacon data * struct beacon_data - Beacon data
* @head: Head portion of Beacon frame (before TIM IE) * @head: Head portion of Beacon frame (before TIM IE)
@ -3377,6 +3397,14 @@ struct wpa_driver_ops {
*/ */
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info); 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
* Returns: 0 on success, negative (<0) on failure
*/
int (*channel_info)(void *priv, struct wpa_channel_info *channel_info);
/** /**
* set_authmode - Set authentication algorithm(s) for static WEP * set_authmode - Set authentication algorithm(s) for static WEP
* @priv: Private driver interface data * @priv: Private driver interface data

View file

@ -1539,6 +1539,70 @@ 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);
os_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;
if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
NUM_HOSTAPD_MODES)
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, static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
void *handle) void *handle)
{ {
@ -10728,6 +10792,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.resume = wpa_driver_nl80211_resume, .resume = wpa_driver_nl80211_resume,
.signal_monitor = nl80211_signal_monitor, .signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll, .signal_poll = nl80211_signal_poll,
.channel_info = nl80211_channel_info,
.send_frame = nl80211_send_frame, .send_frame = nl80211_send_frame,
.set_param = nl80211_set_param, .set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name, .get_radio_name = nl80211_get_radio_name,

View file

@ -492,6 +492,14 @@ static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
return -1; return -1;
} }
static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
struct wpa_channel_info *ci)
{
if (wpa_s->driver->channel_info)
return wpa_s->driver->channel_info(wpa_s->drv_priv, ci);
return -1;
}
static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s, static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s,
struct hostap_sta_driver_data *sta) struct hostap_sta_driver_data *sta)
{ {