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 <markus.theil@tu-ilmenau.de>
This commit is contained in:
parent
0896c442dc
commit
7c2cad969a
4 changed files with 107 additions and 15 deletions
|
@ -1032,6 +1032,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
|||
int err = 1;
|
||||
struct hostapd_hw_modes *cmode = iface->current_mode;
|
||||
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
|
||||
int ieee80211_mode = IEEE80211_MODE_AP;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
|
||||
__func__, iface->cac_started ? "yes" : "no",
|
||||
|
@ -1099,6 +1100,10 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
|||
os_memset(&csa_settings, 0, sizeof(csa_settings));
|
||||
csa_settings.cs_count = 5;
|
||||
csa_settings.block_tx = 1;
|
||||
#ifdef CONFIG_MESH
|
||||
if (iface->mconf)
|
||||
ieee80211_mode = IEEE80211_MODE_MESH;
|
||||
#endif /* CONFIG_MESH */
|
||||
err = hostapd_set_freq_params(&csa_settings.freq_params,
|
||||
iface->conf->hw_mode,
|
||||
channel->freq,
|
||||
|
@ -1113,7 +1118,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[ieee80211_mode]);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
|
||||
|
|
|
@ -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,12 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
|
|||
{
|
||||
size_t j;
|
||||
|
||||
if (!hapd_iface)
|
||||
return -1;
|
||||
|
||||
if (hapd_iface->enable_iface_cb)
|
||||
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 +2757,9 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
|
|||
if (hapd_iface == NULL)
|
||||
return -1;
|
||||
|
||||
if (hapd_iface->disable_iface_cb)
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -28,15 +28,22 @@
|
|||
#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_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_rsn);
|
||||
wpa_s->mesh_rsn = NULL;
|
||||
os_free(wpa_s->mesh_params);
|
||||
wpa_s->mesh_params = NULL;
|
||||
}
|
||||
|
||||
os_free(wpa_s->mesh_rsn);
|
||||
wpa_s->mesh_rsn = NULL;
|
||||
|
||||
wpa_supplicant_leave_mesh(wpa_s, false);
|
||||
}
|
||||
|
||||
|
@ -242,7 +249,7 @@ static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +258,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;
|
||||
}
|
||||
|
||||
|
@ -297,6 +304,69 @@ 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;
|
||||
size_t 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 control
|
||||
* interface */
|
||||
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)
|
||||
|
@ -324,6 +394,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)
|
||||
|
@ -459,7 +531,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;
|
||||
}
|
||||
|
||||
|
@ -507,7 +579,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;
|
||||
|
@ -596,7 +668,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)
|
||||
|
|
Loading…
Reference in a new issue