From c30a4ab045cef9c6d8936fb710105262b3c6dbe5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Mar 2013 02:01:46 +0200 Subject: [PATCH] nl80211: Fix mode settings with split wiphy dump When the wiphy information is split, there's no guarantee that the channels are processed before the bitrates; in fact, with the current kernel it happens the other way around. Therefore, the mode information isn't set up correctly and there's no 11g mode. Fix this by doing the 11b/11g determination as part of the postprocessing. Signed-hostap: Johannes Berg --- src/drivers/driver_nl80211.c | 50 ++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 0c7098d04..ebc3f6fbd 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -5082,21 +5082,19 @@ static void phy_info_freq(struct hostapd_hw_modes *mode, struct hostapd_channel_data *chan, struct nlattr *tb_freq[]) { + enum hostapd_hw_mode m; + chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); chan->flag = 0; - /* mode is not set */ - if (mode->mode >= NUM_HOSTAPD_MODES) { - /* crude heuristic */ - if (chan->freq < 4000) - mode->mode = HOSTAPD_MODE_IEEE80211B; - else if (chan->freq > 50000) - mode->mode = HOSTAPD_MODE_IEEE80211AD; - else - mode->mode = HOSTAPD_MODE_IEEE80211A; - } + if (chan->freq < 4000) + m = HOSTAPD_MODE_IEEE80211B; + else if (chan->freq > 50000) + m = HOSTAPD_MODE_IEEE80211AD; + else + m = HOSTAPD_MODE_IEEE80211A; - switch (mode->mode) { + switch (m) { case HOSTAPD_MODE_IEEE80211AD: chan->chan = (chan->freq - 56160) / 2160; break; @@ -5220,12 +5218,6 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb) continue; mode->rates[idx] = nla_get_u32( tb_rate[NL80211_BITRATE_ATTR_RATE]); - - /* crude heuristic */ - if (mode->mode == HOSTAPD_MODE_IEEE80211B && - mode->rates[idx] > 200) - mode->mode = HOSTAPD_MODE_IEEE80211G; - idx++; } @@ -5303,12 +5295,31 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) static struct hostapd_hw_modes * -wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes) +wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes, + u16 *num_modes) { u16 m; struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; int i, mode11g_idx = -1; + /* heuristic to set up modes */ + for (m = 0; m < *num_modes; m++) { + if (!modes[m].num_channels) + continue; + if (modes[m].channels[0].freq < 4000) { + modes[m].mode = HOSTAPD_MODE_IEEE80211B; + for (i = 0; i < modes[m].num_rates; i++) { + if (modes[m].rates[i] > 200) { + modes[m].mode = HOSTAPD_MODE_IEEE80211G; + break; + } + } + } else if (modes[m].channels[0].freq > 50000) + modes[m].mode = HOSTAPD_MODE_IEEE80211AD; + else + modes[m].mode = HOSTAPD_MODE_IEEE80211A; + } + /* If only 802.11g mode is included, use it to construct matching * 802.11b mode data. */ @@ -5554,7 +5565,8 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) { nl80211_set_ht40_flags(drv, &result); - return wpa_driver_nl80211_add_11b(result.modes, num_modes); + return wpa_driver_nl80211_postprocess_modes(result.modes, + num_modes); } msg = NULL; nla_put_failure: