diff options
Diffstat (limited to 'package/network/services/hostapd/patches/015-mesh-fix-DFS-deinit-init.patch')
-rw-r--r-- | package/network/services/hostapd/patches/015-mesh-fix-DFS-deinit-init.patch | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/package/network/services/hostapd/patches/015-mesh-fix-DFS-deinit-init.patch b/package/network/services/hostapd/patches/015-mesh-fix-DFS-deinit-init.patch new file mode 100644 index 0000000000..c540dd6786 --- /dev/null +++ b/package/network/services/hostapd/patches/015-mesh-fix-DFS-deinit-init.patch @@ -0,0 +1,262 @@ +From d017f5d98a143c46c3c3fcb0e6507ca0b2bebdb0 Mon Sep 17 00:00:00 2001 +From: Markus Theil <markus.theil@tu-ilmenau.de> +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 <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(-) + +--- 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) |