diff mbox series

[RESEND,08/10] mesh: fix DFS deinit/init

Message ID 20200626142822.272002-9-markus.theil@tu-ilmenau.de
State New
Headers show
Series mesh: support for DFS | expand

Commit Message

Markus Theil June 26, 2020, 2:28 p.m. UTC
The hostapd DFS code deinitializes and initializes the
AP interface, if a clean channel switch is not possible.
In this case the AP code paths would deinit the driver, for
example nl80211, without wpa_supplicant code paths getting
notice of this.

Therefore add callbacks for wpa_supplicant mesh methods,
which are called on init/deinit of the AP bss. These
callbacks are then used to handle the reset in the mesh
code.

Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
---
 src/ap/dfs.c          |  2 +-
 src/ap/hostapd.c      | 17 ++++++--
 src/ap/hostapd.h      |  6 +++
 wpa_supplicant/mesh.c | 90 +++++++++++++++++++++++++++++++++++++------
 4 files changed, 100 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index f62da49a7..eb3b8120a 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -1110,7 +1110,7 @@  static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
 				      oper_centr_freq_seg0_idx,
 				      oper_centr_freq_seg1_idx,
 				      cmode->vht_capab,
-				      &cmode->he_capab[IEEE80211_MODE_AP]);
+				      &cmode->he_capab[iface->conf->hw_mode]);
 
 	if (err) {
 		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 04aebe31a..1579ae7fe 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -354,7 +354,7 @@  static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
 #endif /* CONFIG_WEP */
 
 
-static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+void hostapd_free_hapd_data(struct hostapd_data *hapd)
 {
 	os_free(hapd->probereq_cb);
 	hapd->probereq_cb = NULL;
@@ -498,7 +498,7 @@  static void sta_track_deinit(struct hostapd_iface *iface)
 }
 
 
-static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
 {
 	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
 #ifdef NEED_AP_MLME
@@ -626,7 +626,7 @@  static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
 }
 
 
-static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
 {
 	hostapd_free_stas(hapd);
 	hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
@@ -2690,6 +2690,13 @@  int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
 {
 	size_t j;
 
+	if (hapd_iface == NULL)
+		return -1;
+
+	if (hapd_iface->enable_iface_cb != NULL) {
+		return hapd_iface->enable_iface_cb(hapd_iface);
+	}
+
 	if (hapd_iface->bss[0]->drv_priv != NULL) {
 		wpa_printf(MSG_ERROR, "Interface %s already enabled",
 			   hapd_iface->conf->bss[0]->iface);
@@ -2751,6 +2758,10 @@  int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
 	if (hapd_iface == NULL)
 		return -1;
 
+	if (hapd_iface->disable_iface_cb != NULL) {
+		return hapd_iface->disable_iface_cb(hapd_iface);
+	}
+
 	if (hapd_iface->bss[0]->drv_priv == NULL) {
 		wpa_printf(MSG_INFO, "Interface %s already disabled",
 			   hapd_iface->conf->bss[0]->iface);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index b70d13fba..4ce31416d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -589,6 +589,9 @@  struct hostapd_iface {
 
 	/* Previous WMM element information */
 	struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
+
+	int (*enable_iface_cb)(struct hostapd_iface *iface);
+	int (*disable_iface_cb)(struct hostapd_iface *iface);
 };
 
 /* hostapd.c */
@@ -617,6 +620,9 @@  void hostapd_interface_deinit_free(struct hostapd_iface *iface);
 int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
 int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
 int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
+void hostapd_free_hapd_data(struct hostapd_data *hapd);
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
 int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
 int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
 void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 5eb2a29d5..0742cabbc 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -28,15 +28,20 @@ 
 #include "mesh.h"
 
 
-static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s, bool also_clear_hostapd)
 {
-	wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, true);
-	wpa_s->ifmsh = NULL;
-	wpa_s->current_ssid = NULL;
+	wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, also_clear_hostapd);
+	
+	if (also_clear_hostapd) {
+		wpa_s->ifmsh = NULL;
+		wpa_s->current_ssid = NULL;
+		os_free(wpa_s->mesh_params);
+		wpa_s->mesh_params = NULL;
+	}
+
 	os_free(wpa_s->mesh_rsn);
 	wpa_s->mesh_rsn = NULL;
-	os_free(wpa_s->mesh_params);
-	wpa_s->mesh_params = NULL;
+
 	wpa_supplicant_leave_mesh(wpa_s, false);
 }
 
@@ -237,7 +242,7 @@  static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
 				ifmsh->conf->vht_capab,
 				he_capab)) {
 			wpa_printf(MSG_ERROR, "Error updating mesh frequency params.");
-			wpa_supplicant_mesh_deinit(wpa_s);
+			wpa_supplicant_mesh_deinit(wpa_s, true);
 			return -1;
 		}
 	}
@@ -246,7 +251,7 @@  static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
 	    wpas_mesh_init_rsn(wpa_s)) {
 		wpa_printf(MSG_ERROR,
 			   "mesh: RSN initialization failed - deinit mesh");
-		wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh, false);
+		wpa_supplicant_mesh_deinit(wpa_s, false);
 		return -1;
 	}
 
@@ -291,6 +296,67 @@  static void wpas_mesh_complete_cb(void *arg)
 }
 
 
+static int wpa_supplicant_mesh_enable_iface_cb(struct hostapd_iface *ifmsh)
+{
+	struct wpa_supplicant *wpa_s = ifmsh->owner;
+	struct hostapd_data *bss;
+
+	ifmsh->mconf = mesh_config_create(wpa_s, wpa_s->current_ssid);
+	
+	bss = ifmsh->bss[0];
+	bss->msg_ctx = wpa_s;
+	os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
+	bss->driver = wpa_s->driver;
+	bss->drv_priv = wpa_s->drv_priv;
+	bss->iface = ifmsh;
+	bss->mesh_sta_free_cb = mesh_mpm_free_sta;
+	bss->setup_complete_cb = wpas_mesh_complete_cb;
+	bss->setup_complete_cb_ctx = wpa_s;
+
+	bss->conf->start_disabled = 1;
+	bss->conf->mesh = MESH_ENABLED;
+	bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+
+	if (wpa_drv_init_mesh(wpa_s)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
+		return -1;
+	}
+
+	if (hostapd_setup_interface(ifmsh)) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to initialize hostapd interface for mesh");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_mesh_disable_iface_cb(struct hostapd_iface *ifmsh)
+{
+	struct wpa_supplicant *wpa_s = ifmsh->owner;
+	int j;
+
+	wpa_supplicant_mesh_deinit(wpa_s, false);
+
+#ifdef NEED_AP_MLME
+	for (j = 0; j < ifmsh->num_bss; j++)
+		hostapd_cleanup_cs_params(ifmsh->bss[j]);
+#endif /* NEED_AP_MLME */
+
+	/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
+	for (j = 0; j < ifmsh->num_bss; j++) {
+		struct hostapd_data *hapd = ifmsh->bss[j];
+		hostapd_bss_deinit_no_free(hapd);
+		hostapd_free_hapd_data(hapd);
+	}
+
+	hostapd_cleanup_iface_partial(ifmsh);
+
+	return 0;
+}
+
+
 static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
 				    struct wpa_ssid *ssid,
 				    struct hostapd_freq_params *freq)
@@ -318,6 +384,8 @@  static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
 	ifmsh->drv_flags = wpa_s->drv_flags;
 	ifmsh->drv_flags2 = wpa_s->drv_flags2;
 	ifmsh->num_bss = 1;
+	ifmsh->enable_iface_cb = wpa_supplicant_mesh_enable_iface_cb;
+	ifmsh->disable_iface_cb = wpa_supplicant_mesh_disable_iface_cb;
 	ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
 			       sizeof(struct hostapd_data *));
 	if (!ifmsh->bss)
@@ -451,7 +519,7 @@  static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
 
 	return 0;
 out_free:
-	wpa_supplicant_mesh_deinit(wpa_s);
+	wpa_supplicant_mesh_deinit(wpa_s, true);
 	return -ENOMEM;
 }
 
@@ -499,7 +567,7 @@  int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
 		goto out;
 	}
 
-	wpa_supplicant_mesh_deinit(wpa_s);
+	wpa_supplicant_mesh_deinit(wpa_s, true);
 
 	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
 	wpa_s->group_cipher = WPA_CIPHER_NONE;
@@ -588,7 +656,7 @@  int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s, bool need_deinit)
 
 	/* Need to send peering close messages first */
 	if (need_deinit)
-		wpa_supplicant_mesh_deinit(wpa_s);
+		wpa_supplicant_mesh_deinit(wpa_s, true);
 
 	ret = wpa_drv_leave_mesh(wpa_s);
 	if (ret)