diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 72faeae..a73a1d5 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -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 */
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 15a4b26..a729d7c 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -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,
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index caf4092..6037951 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -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);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index b0a859f..d4d032d 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -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;
 }
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 993def0..3510911 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -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 */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index db34ed1..3a9b82c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -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
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 8c8ad51..94c2164 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -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,
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index ea4e6bb..9dbe0b0 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -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 */
