diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index e2ae0ad44..7af4f095a 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1347,21 +1347,29 @@ static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd) static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd, - const char *band) + const char *bands) { union wpa_event_data event; - enum set_band setband; - - if (os_strcmp(band, "AUTO") == 0) - setband = WPA_SETBAND_AUTO; - else if (os_strcmp(band, "5G") == 0) - setband = WPA_SETBAND_5G; - else if (os_strcmp(band, "2G") == 0) - setband = WPA_SETBAND_2G; - else - return -1; + u32 setband_mask = WPA_SETBAND_AUTO; + + /* + * For example: + * SET setband 2G,6G + * SET setband 5G + * SET setband AUTO + */ + if (!os_strstr(bands, "AUTO")) { + if (os_strstr(bands, "5G")) + setband_mask |= WPA_SETBAND_5G; + if (os_strstr(bands, "6G")) + setband_mask |= WPA_SETBAND_6G; + if (os_strstr(bands, "2G")) + setband_mask |= WPA_SETBAND_2G; + if (setband_mask == WPA_SETBAND_AUTO) + return -1; + } - if (hostapd_drv_set_band(hapd, setband) == 0) { + if (hostapd_drv_set_band(hapd, setband_mask) == 0) { os_memset(&event, 0, sizeof(event)); event.channel_list_changed.initiator = REGDOM_SET_BY_USER; event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index cc7ea07a2..0257c3a65 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -385,11 +385,11 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd, } static inline int -hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band) +hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask) { if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band) return -1; - return hapd->driver->set_band(hapd->drv_priv, band); + return hapd->driver->set_band(hapd->drv_priv, band_mask); } #endif /* AP_DRV_OPS */ diff --git a/src/common/defs.h b/src/common/defs.h index bbe3120de..b01ab03b6 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -388,9 +388,10 @@ enum mesh_plink_state { }; enum set_band { - WPA_SETBAND_AUTO, - WPA_SETBAND_5G, - WPA_SETBAND_2G + WPA_SETBAND_AUTO = 0, + WPA_SETBAND_5G = BIT(0), + WPA_SETBAND_2G = BIT(1), + WPA_SETBAND_6G = BIT(2), }; enum wpa_radio_work_band { diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 58a7bd776..b0543e7b4 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -4277,12 +4277,12 @@ struct wpa_driver_ops { int (*do_acs)(void *priv, struct drv_acs_params *params); /** - * set_band - Notify driver of band selection + * set_band - Notify driver of band(s) selection * @priv: Private driver interface data - * @band: The selected band(s) + * @band_mask: The selected band(s) bit mask (from enum set_band) * Returns 0 on success, -1 on failure */ - int (*set_band)(void *priv, enum set_band band); + int (*set_band)(void *priv, u32 band_mask); /** * get_pref_freq_list - Get preferred frequency list for an interface diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 8ba1bf72f..448c404f3 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -10795,38 +10795,49 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params) } -static int nl80211_set_band(void *priv, enum set_band band) +static int nl80211_set_band(void *priv, u32 band_mask) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; struct nlattr *data; int ret; - enum qca_set_band qca_band; + enum qca_set_band qca_band_value; + u32 qca_band_mask = QCA_SETBAND_AUTO; - if (!drv->setband_vendor_cmd_avail) + if (!drv->setband_vendor_cmd_avail || + (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G))) return -1; - switch (band) { - case WPA_SETBAND_AUTO: - qca_band = QCA_SETBAND_AUTO; - break; - case WPA_SETBAND_5G: - qca_band = QCA_SETBAND_5G; - break; - case WPA_SETBAND_2G: - qca_band = QCA_SETBAND_2G; - break; - default: - return -1; - } + if (band_mask & WPA_SETBAND_5G) + qca_band_mask |= QCA_SETBAND_5G; + if (band_mask & WPA_SETBAND_2G) + qca_band_mask |= QCA_SETBAND_2G; + if (band_mask & WPA_SETBAND_6G) + qca_band_mask |= QCA_SETBAND_6G; + + /* + * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make + * it suite to its values (AUTO/5G/2G) for backwards compatibility. + */ + qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) && + (qca_band_mask & QCA_SETBAND_2G)) ? + QCA_SETBAND_AUTO : + qca_band_mask & ~QCA_SETBAND_6G; + + wpa_printf(MSG_DEBUG, + "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d", + qca_band_mask, qca_band_value); if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, QCA_NL80211_VENDOR_SUBCMD_SETBAND) || !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || - nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) { + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, + qca_band_value) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK, + qca_band_mask)) { nlmsg_free(msg); return -ENOBUFS; } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 8306950a5..7ce2a90e8 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -299,20 +299,30 @@ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd) } -static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band) +static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *bands) { union wpa_event_data event; + u32 setband_mask = WPA_SETBAND_AUTO; - if (os_strcmp(band, "AUTO") == 0) - wpa_s->setband = WPA_SETBAND_AUTO; - else if (os_strcmp(band, "5G") == 0) - wpa_s->setband = WPA_SETBAND_5G; - else if (os_strcmp(band, "2G") == 0) - wpa_s->setband = WPA_SETBAND_2G; - else - return -1; + /* + * For example: + * SET setband 2G,6G + * SET setband 5G + * SET setband AUTO + */ + if (!os_strstr(bands, "AUTO")) { + if (os_strstr(bands, "5G")) + setband_mask |= WPA_SETBAND_5G; + if (os_strstr(bands, "6G")) + setband_mask |= WPA_SETBAND_6G; + if (os_strstr(bands, "2G")) + setband_mask |= WPA_SETBAND_2G; + if (setband_mask == WPA_SETBAND_AUTO) + return -1; + } - if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) { + wpa_s->setband_mask = setband_mask; + if (wpa_drv_setband(wpa_s, wpa_s->setband_mask) == 0) { os_memset(&event, 0, sizeof(event)); event.channel_list_changed.initiator = REGDOM_SET_BY_USER; event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 3a2828982..237f4e085 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -954,11 +954,11 @@ static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s, #endif /* CONFIG_MACSEC */ static inline int wpa_drv_setband(struct wpa_supplicant *wpa_s, - enum set_band band) + u32 band_mask) { if (!wpa_s->driver->set_band) return -1; - return wpa_s->driver->set_band(wpa_s->drv_priv, band); + return wpa_s->driver->set_band(wpa_s->drv_priv, band_mask); } static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index edf3ca800..5339b796b 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -713,12 +713,15 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, if (params->freqs) return; /* already using a limited channel set */ - if (wpa_s->setband == WPA_SETBAND_5G) + if (wpa_s->setband_mask & WPA_SETBAND_5G) wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params, 0); - else if (wpa_s->setband == WPA_SETBAND_2G) + if (wpa_s->setband_mask & WPA_SETBAND_2G) wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params, 0); + if (wpa_s->setband_mask & WPA_SETBAND_6G) + wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params, + 1); } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index ddd43e5d2..5560197bd 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -5111,6 +5111,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent) wpa_s->parent = parent ? parent : wpa_s; wpa_s->p2pdev = wpa_s->parent; wpa_s->sched_scanning = 0; + wpa_s->setband_mask = WPA_SETBAND_AUTO; dl_list_init(&wpa_s->bss_tmp_disallowed); dl_list_init(&wpa_s->fils_hlp_req); diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index ffaacf948..212cc37b6 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -594,7 +594,7 @@ struct wpa_supplicant { struct wpa_ssid_value *disallow_aps_ssid; size_t disallow_aps_ssid_count; - enum set_band setband; + u32 setband_mask; /* Preferred network for the next connection attempt */ struct wpa_ssid *next_ssid;