diff --git a/src/common/defs.h b/src/common/defs.h index 5b2d7c42b..eb080ea8a 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -328,4 +328,10 @@ enum mesh_plink_state { PLINK_BLOCKED, }; +enum set_band { + WPA_SETBAND_AUTO, + WPA_SETBAND_5G, + WPA_SETBAND_2G +}; + #endif /* DEFS_H */ diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index 1c8496d48..2a6e24298 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -155,6 +155,7 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG = 102, QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103, QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104, + QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105, }; @@ -182,6 +183,8 @@ enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10, /* Unsigned 32-bit value */ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11, + /* Unsigned 32-bit value from enum qca_set_band. */ + QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12, /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1, @@ -314,4 +317,10 @@ enum qca_iface_type { QCA_IFACE_TYPE_TDLS, }; +enum qca_set_band { + QCA_SETBAND_AUTO, + QCA_SETBAND_5G, + QCA_SETBAND_2G, +}; + #endif /* QCA_VENDOR_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 7c8bca2e5..6e39aa3e0 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3387,6 +3387,14 @@ struct wpa_driver_ops { * indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD). */ int (*do_acs)(void *priv, struct drv_acs_params *params); + + /** + * set_band - Notify driver of band selection + * @priv: Private driver interface data + * @band: The selected band(s) + * Returns 0 on success, -1 on failure + */ + int (*set_band)(void *priv, enum set_band band); }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 69e2f2789..a6441e3dc 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -8435,6 +8435,53 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params) } +static int nl80211_set_band(void *priv, enum set_band band) +{ + 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; + + if (!drv->setband_vendor_cmd_avail) + 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 (!(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)) { + nlmsg_free(msg); + return -ENOBUFS; + } + nla_nest_end(msg, data); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: Driver setband function failed: %s", + strerror(errno)); + } + return ret; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -8542,4 +8589,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .add_tx_ts = nl80211_add_ts, .del_tx_ts = nl80211_del_ts, .do_acs = wpa_driver_do_acs, + .set_band = nl80211_set_band, }; diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index acfe959e4..1536d2ffb 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -145,6 +145,7 @@ struct wpa_driver_nl80211_data { unsigned int get_features_vendor_cmd_avail:1; unsigned int set_rekey_offload:1; unsigned int p2p_go_ctwindow_supported:1; + unsigned int setband_vendor_cmd_avail:1; u64 remain_on_chan_cookie; u64 send_action_cookie; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index e23c57edd..4929cea21 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -593,6 +593,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD; break; + case QCA_NL80211_VENDOR_SUBCMD_SETBAND: + drv->setband_vendor_cmd_avail = 1; + break; } } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index f7882ca54..41f9090ef 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -286,6 +286,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) +{ + union wpa_event_data event; + + 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; + + if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) { + os_memset(&event, 0, sizeof(event)); + event.channel_list_changed.initiator = REGDOM_SET_BY_USER; + event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; + wpa_supplicant_event(wpa_s, EVENT_CHANNEL_LIST_CHANGED, &event); + } + + return 0; +} + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -449,14 +473,7 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, ret = wpas_ctrl_set_blob(wpa_s, value); #endif /* CONFIG_NO_CONFIG_BLOBS */ } else if (os_strcasecmp(cmd, "setband") == 0) { - if (os_strcmp(value, "AUTO") == 0) - wpa_s->setband = WPA_SETBAND_AUTO; - else if (os_strcmp(value, "5G") == 0) - wpa_s->setband = WPA_SETBAND_5G; - else if (os_strcmp(value, "2G") == 0) - wpa_s->setband = WPA_SETBAND_2G; - else - ret = -1; + ret = wpas_ctrl_set_band(wpa_s, value); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 1fcb18067..d1f9f8be1 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -885,4 +885,12 @@ 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) +{ + if (!wpa_s->driver->set_band) + return -1; + return wpa_s->driver->set_band(wpa_s->drv_priv, band); +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 1338e17d8..0636ee454 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -482,7 +482,7 @@ struct wpa_supplicant { struct wpa_ssid_value *disallow_aps_ssid; size_t disallow_aps_ssid_count; - enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband; + enum set_band setband; /* Preferred network for the next connection attempt */ struct wpa_ssid *next_ssid;