|
|
@@ -0,0 +1,262 @@
|
|
|
+From d017f5d98a143c46c3c3fcb0e6507ca0b2bebdb0 Mon Sep 17 00:00:00 2001
|
|
|
+From: Markus Theil <[email protected]>
|
|
|
+Date: Tue, 30 Jun 2020 14:19:03 +0200
|
|
|
+Subject: [PATCH 15/19] mesh: fix DFS deinit/init
|
|
|
+
|
|
|
+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 <[email protected]>
|
|
|
+---
|
|
|
+ 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(-)
|
|
|
+
|
|
|
+--- a/src/ap/dfs.c
|
|
|
++++ b/src/ap/dfs.c
|
|
|
+@@ -1112,7 +1112,7 @@ static int hostapd_dfs_start_channel_swi
|
|
|
+ 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");
|
|
|
+--- a/src/ap/hostapd.c
|
|
|
++++ b/src/ap/hostapd.c
|
|
|
+@@ -354,7 +354,7 @@ static int hostapd_broadcast_wep_set(str
|
|
|
+ #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 host
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+-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(st
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+-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_
|
|
|
+ {
|
|
|
+ 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
|
|
|
+ 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);
|
|
|
+--- 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(struc
|
|
|
+ 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);
|
|
|
+--- 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
|
|
|
+ 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
|
|
|
+ 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 *
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
++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(stru
|
|
|
+ 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(stru
|
|
|
+
|
|
|
+ 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_
|
|
|
+ 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
|
|
|
+
|
|
|
+ /* 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)
|