diff --git a/src/drivers/driver.h b/src/drivers/driver.h index a85ed3258..cf4984777 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3603,6 +3603,23 @@ struct wpa_driver_ops { * Returns: 0 on success or -1 on failure */ int (*p2p_lo_stop)(void *priv); + + /** + * set_default_scan_ies - Set default scan IEs + * @priv: Private driver interface data + * @ies: Scan default IEs buffer + * @ies_len: Length of IEs in bytes + * Returns: 0 on success or -1 on failure + * + * The driver can use these by default when there are no scan IEs coming + * in the subsequent scan requests. Also in case of one or more of IEs + * given in set_default_scan_ies() are missing in the subsequent scan + * request, the driver should merge the missing scan IEs in the scan + * request from the IEs set by set_default_scan_ies() in the Probe + * Request frames sent. + */ + int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len); + }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index ae40f427b..7743bd521 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -9469,6 +9469,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_prob_oper_freq = nl80211_set_prob_oper_freq, .p2p_lo_start = nl80211_p2p_lo_start, .p2p_lo_stop = nl80211_p2p_lo_stop, + .set_default_scan_ies = nl80211_set_default_scan_ies, #endif /* CONFIG_DRIVER_NL80211_QCA */ .configure_data_frame_filters = nl80211_configure_data_frame_filters, .get_ext_capab = nl80211_get_ext_capab, diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 283dfd99b..d0ec48c9f 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -159,6 +159,7 @@ struct wpa_driver_nl80211_data { unsigned int set_prob_oper_freq:1; unsigned int scan_vendor_cmd_avail:1; unsigned int connect_reassoc:1; + unsigned int set_wifi_conf_vendor_cmd_avail:1; u64 vendor_scan_cookie; u64 remain_on_chan_cookie; @@ -301,5 +302,6 @@ void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv); int wpa_driver_nl80211_abort_scan(void *priv); int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss, struct wpa_driver_scan_params *params); +int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len); #endif /* DRIVER_NL80211_H */ diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 1134886ad..df10c21dc 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -709,6 +709,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: drv->scan_vendor_cmd_avail = 1; break; + case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION: + drv->set_wifi_conf_vendor_cmd_avail = 1; + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ } } diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index c08989146..c115b6b31 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -1070,4 +1070,54 @@ fail: return ret; } + +/** + * nl80211_set_default_scan_ies - Set the scan default IEs to the driver + * @priv: Pointer to private driver data from wpa_driver_nl80211_init() + * @ies: Pointer to IEs buffer + * @ies_len: Length of IEs in bytes + * Returns: 0 on success, -1 on failure + */ +int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg = NULL; + struct nlattr *attr; + int ret = -1; + + if (!drv->set_wifi_conf_vendor_cmd_avail) + 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_SET_WIFI_CONFIGURATION)) + goto fail; + + attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (attr == NULL) + goto fail; + + wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan default IEs", ies, ies_len); + if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES, + ies_len, ies)) + goto fail; + + nla_nest_end(msg, attr); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Set scan default IEs failed: ret=%d (%s)", + ret, strerror(-ret)); + goto fail; + } + +fail: + nlmsg_free(msg); + return ret; +} + #endif /* CONFIG_DRIVER_NL80211_QCA */ diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 396a0dc20..7a16b7aa3 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -969,4 +969,12 @@ static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s) return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv); } +static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s, + const u8 *ies, size_t len) +{ + if (!wpa_s->driver->set_default_scan_ies) + return -1; + return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len); +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c index 5b5c3e65f..91667b07b 100644 --- a/wpa_supplicant/mbo.c +++ b/wpa_supplicant/mbo.c @@ -18,6 +18,7 @@ #include "wpa_supplicant_i.h" #include "driver_i.h" #include "bss.h" +#include "scan.h" /* type + length + oui + oui type */ #define MBO_IE_HEADER 6 @@ -810,4 +811,5 @@ void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa) cell_capa[6] = mbo_cell_capa; wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7); + wpa_supplicant_set_default_scan_ies(wpa_s); } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 119da28d0..371c16a3e 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -426,6 +426,39 @@ static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, #endif /* CONFIG_INTERWORKING */ +void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) +{ + struct wpabuf *default_ies = NULL; + u8 ext_capab[18]; + int ext_capab_len; + enum wpa_driver_if_type type = WPA_IF_STATION; + +#ifdef CONFIG_P2P + if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) + type = WPA_IF_P2P_CLIENT; +#endif /* CONFIG_P2P */ + + wpa_drv_get_ext_capa(wpa_s, type); + + ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, + sizeof(ext_capab)); + if (ext_capab_len > 0 && + wpabuf_resize(&default_ies, ext_capab_len) == 0) + wpabuf_put_data(default_ies, ext_capab, ext_capab_len); + +#ifdef CONFIG_MBO + /* Send cellular capabilities for potential MBO STAs */ + if (wpabuf_resize(&default_ies, 9) == 0) + wpas_mbo_scan_ie(wpa_s, default_ies); +#endif /* CONFIG_MBO */ + + if (default_ies) + wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies), + wpabuf_len(default_ies)); + wpabuf_free(default_ies); +} + + static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index 9f8d04e76..b2bb386b1 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -56,5 +56,6 @@ void filter_scan_res(struct wpa_supplicant *wpa_s, void scan_snr(struct wpa_scan_res *res); void scan_est_throughput(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res); +void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s); #endif /* SCAN_H */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 7ed7efa4a..91e3a918b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -4875,6 +4875,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan); #endif /* CONFIG_MBO */ + wpa_supplicant_set_default_scan_ies(wpa_s); + return 0; }