aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services/hostapd/patches/015-mesh-fix-DFS-deinit-init.patch
blob: c540dd67866039ab3385bb5b3475ef2805e99cff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
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)