@@ -1077,7 +1077,10 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos)
if (ret)
return ret;
- return hostapd_switch_channel(hapd, &settings);
+ settings.hapd = hapd;
+ settings.priv = hapd->drv_priv;
+
+ return hostapd_switch_channel(&settings, 1);
#else /* NEED_AP_MLME */
return -1;
#endif /* NEED_AP_MLME */
@@ -263,13 +263,21 @@ static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
return hapd->driver->get_radio_name(hapd->drv_priv);
}
-static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
- struct csa_settings *settings)
+static inline int hostapd_drv_switch_channel(struct csa_settings *settings,
+ int num_settings)
{
+ struct hostapd_data *hapd;
+
+ if (num_settings < 1)
+ return -EINVAL;
+
+ hapd = settings[0].hapd;
+
if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
return -ENOTSUP;
- return hapd->driver->switch_channel(hapd->drv_priv, settings);
+ return hapd->driver->switch_channel(hapd->drv_priv, settings,
+ num_settings);
}
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
@@ -708,6 +708,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
/* Setup CSA request */
os_memset(&csa_settings, 0, sizeof(csa_settings));
+ csa_settings.hapd = hapd;
+ csa_settings.priv = hapd->drv_priv;
csa_settings.cs_count = 5;
csa_settings.block_tx = 1;
err = hostapd_set_freq_params(&csa_settings.freq_params,
@@ -728,7 +730,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
return err;
}
- err = hostapd_switch_channel(hapd, &csa_settings);
+ err = hostapd_switch_channel(&csa_settings, 1);
if (err) {
wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
err);
@@ -2169,9 +2169,9 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
}
-static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
- struct csa_settings *settings)
+static int hostapd_fill_csa_settings(struct csa_settings *settings)
{
+ struct hostapd_data *hapd = settings->hapd;
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
@@ -2225,25 +2225,34 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
}
-int hostapd_switch_channel(struct hostapd_data *hapd,
- struct csa_settings *settings)
+int hostapd_switch_channel(struct csa_settings *settings,
+ int num_settings)
{
- int ret;
- ret = hostapd_fill_csa_settings(hapd, settings);
- if (ret)
- return ret;
+ int i, ret;
+
+ for (i = 0; i < num_settings; i++) {
+ ret = hostapd_fill_csa_settings(&settings[i]);
+ if (ret)
+ return ret;
+ }
- ret = hostapd_drv_switch_channel(hapd, settings);
- free_beacon_data(&settings->beacon_csa);
- free_beacon_data(&settings->beacon_after);
+ ret = hostapd_drv_switch_channel(settings, num_settings);
+
+ for (i = 0; i < num_settings; i++) {
+ free_beacon_data(&settings[i].beacon_csa);
+ free_beacon_data(&settings[i].beacon_after);
+ }
if (ret) {
/* if we failed, clean cs parameters */
- hostapd_cleanup_cs_params(hapd);
+ for (i = 0; i < num_settings; i++)
+ hostapd_cleanup_cs_params(settings[i].hapd);
return ret;
}
- hapd->csa_in_progress = 1;
+ for (i = 0; i < num_settings; i++)
+ settings[i].hapd->csa_in_progress = 1;
+
return 0;
}
@@ -391,8 +391,7 @@ int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
-int hostapd_switch_channel(struct hostapd_data *hapd,
- struct csa_settings *settings);
+int hostapd_switch_channel(struct csa_settings *settings, int num_settings);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
/* utils.c */
@@ -1209,6 +1209,8 @@ struct beacon_data {
/**
* struct csa_settings - Settings for channel switch command
+ * @hapd: Pointer to hostapd context
+ * @priv: Pointer to driver-specific context.
* @cs_count: Count in Beacon frames (TBTT) to perform the switch
* @block_tx: 1 - block transmission for CSA period
* @freq_params: Next channel frequency parameter
@@ -1218,6 +1220,9 @@ struct beacon_data {
* @counter_offset_presp: Offset to the count field in probe resp.
*/
struct csa_settings {
+ struct hostapd_data *hapd;
+ void *priv;
+
u8 cs_count;
u8 block_tx;
@@ -2618,13 +2623,15 @@ struct wpa_driver_ops {
* switch_channel - Announce channel switch and migrate the GO to the
* given frequency
* @priv: Private driver interface data
- * @settings: Settings for CSA period and new channel
+ * @settings: Settings for CSA period and new channel for multiple BSSes
+ * @num_settings: Number of CSA settings for different BSSes
* Returns: 0 on success, -1 on failure
*
* This function is used to move the GO to the legacy STA channel to
* avoid frequency conflict in single channel concurrency.
*/
- int (*switch_channel)(void *priv, struct csa_settings *settings);
+ int (*switch_channel)(void *priv, struct csa_settings *settings,
+ int num_settings);
/**
* start_dfs_cac - Listen for radar interference on the channel
@@ -11390,7 +11390,8 @@ nla_put_failure:
}
-static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
+static int nl80211_switch_channel(void *priv, struct csa_settings *settings,
+ int num_settings)
{
struct nl_msg *msg;
struct i802_bss *bss = priv;
@@ -11398,6 +11399,10 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
struct nlattr *beacon_csa;
int ret = -ENOBUFS;
+ /* multi-BSS not implemented yet */
+ if (num_settings != 1)
+ return -EOPNOTSUPP;
+
wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
settings->cs_count, settings->block_tx,
settings->freq_params.freq, settings->freq_params.bandwidth,
@@ -1068,7 +1068,10 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s,
if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
return -1;
- return hostapd_switch_channel(wpa_s->ap_iface->bss[0], settings);
+ settings->hapd = wpa_s->ap_iface->bss[0];
+ settings->priv = wpa_s->ap_iface->bss[0]->drv_priv;
+
+ return hostapd_switch_channel(settings, 1);
#else /* NEED_AP_MLME */
return -1;
#endif /* NEED_AP_MLME */