diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 352c163bd..3a70bb0bc 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2804,6 +2804,22 @@ struct wpa_driver_ops { */ int (*status)(void *priv, char *buf, size_t buflen); + /** + * roaming - Set roaming policy for driver-based BSS selection + * @priv: Private driver interface data + * @allowed: Whether roaming within ESS is allowed + * @bssid: Forced BSSID if roaming is disabled or %NULL if not set + * Returns: Length of written status information or -1 on failure + * + * This optional callback can be used to update roaming policy from the + * associate() command (bssid being set there indicates that the driver + * should not roam before getting this roaming() call to allow roaming. + * If the driver does not indicate WPA_DRIVER_FLAGS_BSS_SELECTION + * capability, roaming policy is handled within wpa_supplicant and there + * is no need to implement or react to this callback. + */ + int (*roaming)(void *priv, int allowed, const u8 *bssid); + #ifdef CONFIG_MACSEC int (*macsec_init)(void *priv, struct macsec_init_params *params); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index f612b494d..8ddb86ec9 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2564,9 +2564,10 @@ static int wpa_supplicant_ctrl_iface_update_network( static int wpa_supplicant_ctrl_iface_set_network( struct wpa_supplicant *wpa_s, char *cmd) { - int id; + int id, ret, prev_bssid_set; struct wpa_ssid *ssid; char *name, *value; + u8 prev_bssid[ETH_ALEN]; /* cmd: " " */ name = os_strchr(cmd, ' '); @@ -2592,8 +2593,15 @@ static int wpa_supplicant_ctrl_iface_set_network( return -1; } - return wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name, - value); + prev_bssid_set = ssid->bssid_set; + os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN); + ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name, + value); + if (ret == 0 && + (ssid->bssid_set != prev_bssid_set || + os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0)) + wpas_notify_network_bssid_set_changed(wpa_s, ssid); + return ret; } diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 00703d906..49653c2d4 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -632,6 +632,14 @@ static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s, data, data_len, buf); } +static inline int wpa_drv_roaming(struct wpa_supplicant *wpa_s, int allowed, + const u8 *bssid) +{ + if (!wpa_s->driver->roaming) + return -1; + return wpa_s->driver->roaming(wpa_s->drv_priv, allowed, bssid); +} + #ifdef CONFIG_MACSEC diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index b29fdac6d..617ce8491 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -633,3 +633,18 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, "status='%s' parameter='%s'", status, parameter); } + + +void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + if (wpa_s->current_ssid != ssid) + return; + + wpa_dbg(wpa_s, MSG_DEBUG, + "Network bssid config changed for the current network - within-ESS roaming %s", + ssid->bssid_set ? "disabled" : "enabled"); + + wpa_drv_roaming(wpa_s, !ssid->bssid_set, + ssid->bssid_set ? ssid->bssid : NULL); +} diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 5dda608b4..7feb53044 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -128,5 +128,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s, const u8 *ie, size_t ie_len, u32 ssi_signal); void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); +void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); #endif /* NOTIFY_H */