Extend hw_mode to support any band for offloaded ACS case
When device supports dual band operations with offloaded ACS, hw_mode can now be set to any band (hw_mode=any) in order to allow ACS to select the best channel from any band. After a channel is selected, the hw_mode is updated for hostapd. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
1b748e67ae
commit
3784c0589e
10 changed files with 85 additions and 12 deletions
|
@ -2539,6 +2539,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
|
||||||
else if (os_strcmp(pos, "ad") == 0)
|
else if (os_strcmp(pos, "ad") == 0)
|
||||||
conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
|
||||||
|
else if (os_strcmp(pos, "any") == 0)
|
||||||
|
conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
|
||||||
else {
|
else {
|
||||||
wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
|
wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
|
||||||
line, pos);
|
line, pos);
|
||||||
|
|
|
@ -127,7 +127,9 @@ ssid=test
|
||||||
|
|
||||||
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
|
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
|
||||||
# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
|
# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
|
||||||
# specify band)
|
# specify band). When using ACS (see channel parameter), a special value "any"
|
||||||
|
# can be used to indicate that any support band can be used. This special case
|
||||||
|
# is currently supported only with drivers with which offloaded ACS is used.
|
||||||
# Default: IEEE 802.11b
|
# Default: IEEE 802.11b
|
||||||
hw_mode=g
|
hw_mode=g
|
||||||
|
|
||||||
|
|
|
@ -532,7 +532,7 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
|
||||||
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||||
struct acs_selected_channels *acs_res)
|
struct acs_selected_channels *acs_res)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret, i;
|
||||||
|
|
||||||
if (hapd->iconf->channel) {
|
if (hapd->iconf->channel) {
|
||||||
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
|
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
|
||||||
|
@ -540,6 +540,24 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hapd->iface->current_mode) {
|
||||||
|
for (i = 0; i < hapd->iface->num_hw_features; i++) {
|
||||||
|
struct hostapd_hw_modes *mode =
|
||||||
|
&hapd->iface->hw_features[i];
|
||||||
|
|
||||||
|
if (mode->mode == acs_res->hw_mode) {
|
||||||
|
hapd->iface->current_mode = mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hapd->iface->current_mode) {
|
||||||
|
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_WARNING,
|
||||||
|
"driver selected to bad hw_mode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
|
hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
|
||||||
|
|
||||||
if (!acs_res->pri_channel) {
|
if (!acs_res->pri_channel) {
|
||||||
|
|
|
@ -895,14 +895,18 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iface->current_mode == NULL) {
|
if (iface->current_mode == NULL) {
|
||||||
wpa_printf(MSG_ERROR, "Hardware does not support configured "
|
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
|
||||||
"mode");
|
!(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
|
||||||
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
|
{
|
||||||
HOSTAPD_LEVEL_WARNING,
|
wpa_printf(MSG_ERROR,
|
||||||
"Hardware does not support configured mode "
|
"Hardware does not support configured mode");
|
||||||
"(%d) (hw_mode in hostapd.conf)",
|
hostapd_logger(iface->bss[0], NULL,
|
||||||
(int) iface->conf->hw_mode);
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
return -2;
|
HOSTAPD_LEVEL_WARNING,
|
||||||
|
"Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)",
|
||||||
|
(int) iface->conf->hw_mode);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (hostapd_check_chans(iface)) {
|
switch (hostapd_check_chans(iface)) {
|
||||||
|
|
|
@ -295,6 +295,7 @@ enum hostapd_hw_mode {
|
||||||
HOSTAPD_MODE_IEEE80211G,
|
HOSTAPD_MODE_IEEE80211G,
|
||||||
HOSTAPD_MODE_IEEE80211A,
|
HOSTAPD_MODE_IEEE80211A,
|
||||||
HOSTAPD_MODE_IEEE80211AD,
|
HOSTAPD_MODE_IEEE80211AD,
|
||||||
|
HOSTAPD_MODE_IEEE80211ANY,
|
||||||
NUM_HOSTAPD_MODES
|
NUM_HOSTAPD_MODES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,7 @@ enum qca_wlan_vendor_acs_hw_mode {
|
||||||
QCA_ACS_MODE_IEEE80211G,
|
QCA_ACS_MODE_IEEE80211G,
|
||||||
QCA_ACS_MODE_IEEE80211A,
|
QCA_ACS_MODE_IEEE80211A,
|
||||||
QCA_ACS_MODE_IEEE80211AD,
|
QCA_ACS_MODE_IEEE80211AD,
|
||||||
|
QCA_ACS_MODE_IEEE80211ANY,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,10 +231,13 @@ enum qca_wlan_vendor_acs_hw_mode {
|
||||||
* management offload, a mechanism where the station's firmware
|
* management offload, a mechanism where the station's firmware
|
||||||
* does the exchange with the AP to establish the temporal keys
|
* does the exchange with the AP to establish the temporal keys
|
||||||
* after roaming, rather than having the user space wpa_supplicant do it.
|
* after roaming, rather than having the user space wpa_supplicant do it.
|
||||||
|
* @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
|
||||||
|
* band selection based on channel selection results.
|
||||||
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
|
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
|
||||||
*/
|
*/
|
||||||
enum qca_wlan_vendor_features {
|
enum qca_wlan_vendor_features {
|
||||||
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
|
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
|
||||||
|
QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
|
||||||
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
|
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1212,6 +1212,8 @@ struct wpa_driver_capa {
|
||||||
#define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL
|
#define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL
|
||||||
/** Driver supports IBSS with VHT datarates */
|
/** Driver supports IBSS with VHT datarates */
|
||||||
#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
|
#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
|
||||||
|
/** Driver supports automatic band selection */
|
||||||
|
#define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL
|
||||||
u64 flags;
|
u64 flags;
|
||||||
|
|
||||||
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
|
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
|
||||||
|
@ -4563,6 +4565,7 @@ union wpa_event_data {
|
||||||
* @ch_width: Selected Channel width by driver. Driver may choose to
|
* @ch_width: Selected Channel width by driver. Driver may choose to
|
||||||
* change hostapd configured ACS channel width due driver internal
|
* change hostapd configured ACS channel width due driver internal
|
||||||
* channel restrictions.
|
* channel restrictions.
|
||||||
|
* hw_mode: Selected band (used with hw_mode=any)
|
||||||
*/
|
*/
|
||||||
struct acs_selected_channels {
|
struct acs_selected_channels {
|
||||||
u8 pri_channel;
|
u8 pri_channel;
|
||||||
|
@ -4570,6 +4573,7 @@ union wpa_event_data {
|
||||||
u8 vht_seg0_center_ch;
|
u8 vht_seg0_center_ch;
|
||||||
u8 vht_seg1_center_ch;
|
u8 vht_seg1_center_ch;
|
||||||
u16 ch_width;
|
u16 ch_width;
|
||||||
|
enum hostapd_hw_mode hw_mode;
|
||||||
} acs_selected_channels;
|
} acs_selected_channels;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8365,6 +8365,8 @@ static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
|
||||||
return QCA_ACS_MODE_IEEE80211A;
|
return QCA_ACS_MODE_IEEE80211A;
|
||||||
case HOSTAPD_MODE_IEEE80211AD:
|
case HOSTAPD_MODE_IEEE80211AD:
|
||||||
return QCA_ACS_MODE_IEEE80211AD;
|
return QCA_ACS_MODE_IEEE80211AD;
|
||||||
|
case HOSTAPD_MODE_IEEE80211ANY:
|
||||||
|
return QCA_ACS_MODE_IEEE80211ANY;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -813,6 +813,9 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
|
||||||
|
|
||||||
if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
|
if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
|
||||||
drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
|
drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
|
||||||
|
|
||||||
|
if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info))
|
||||||
|
drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1491,6 +1491,25 @@ static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode)
|
||||||
|
{
|
||||||
|
switch (hw_mode) {
|
||||||
|
case QCA_ACS_MODE_IEEE80211B:
|
||||||
|
return HOSTAPD_MODE_IEEE80211B;
|
||||||
|
case QCA_ACS_MODE_IEEE80211G:
|
||||||
|
return HOSTAPD_MODE_IEEE80211G;
|
||||||
|
case QCA_ACS_MODE_IEEE80211A:
|
||||||
|
return HOSTAPD_MODE_IEEE80211A;
|
||||||
|
case QCA_ACS_MODE_IEEE80211AD:
|
||||||
|
return HOSTAPD_MODE_IEEE80211AD;
|
||||||
|
case QCA_ACS_MODE_IEEE80211ANY:
|
||||||
|
return HOSTAPD_MODE_IEEE80211ANY;
|
||||||
|
default:
|
||||||
|
return NUM_HOSTAPD_MODES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
|
static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
|
||||||
const u8 *data, size_t len)
|
const u8 *data, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -1520,14 +1539,28 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
|
||||||
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
|
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
|
||||||
event.acs_selected_channels.ch_width =
|
event.acs_selected_channels.ch_width =
|
||||||
nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
|
nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
|
||||||
|
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
|
||||||
|
u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
|
||||||
|
|
||||||
|
event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode);
|
||||||
|
if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES ||
|
||||||
|
event.acs_selected_channels.hw_mode ==
|
||||||
|
HOSTAPD_MODE_IEEE80211ANY) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"nl80211: Invalid hw_mode %d in ACS selection event",
|
||||||
|
hw_mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wpa_printf(MSG_INFO,
|
wpa_printf(MSG_INFO,
|
||||||
"nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d",
|
"nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
|
||||||
event.acs_selected_channels.pri_channel,
|
event.acs_selected_channels.pri_channel,
|
||||||
event.acs_selected_channels.sec_channel,
|
event.acs_selected_channels.sec_channel,
|
||||||
event.acs_selected_channels.ch_width,
|
event.acs_selected_channels.ch_width,
|
||||||
event.acs_selected_channels.vht_seg0_center_ch,
|
event.acs_selected_channels.vht_seg0_center_ch,
|
||||||
event.acs_selected_channels.vht_seg1_center_ch);
|
event.acs_selected_channels.vht_seg1_center_ch,
|
||||||
|
event.acs_selected_channels.hw_mode);
|
||||||
|
|
||||||
/* Ignore ACS channel list check for backwards compatibility */
|
/* Ignore ACS channel list check for backwards compatibility */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue