]>
Commit | Line | Data |
---|---|---|
ee2e7db9 PM |
1 | From fee48f3bdd7516bb63da507213916227cf147211 Mon Sep 17 00:00:00 2001 |
2 | From: Johannes Berg <johannes.berg@intel.com> | |
3 | Date: Thu, 13 Oct 2022 20:15:59 +0200 | |
4 | Subject: [PATCH] mac80211: always allocate struct ieee802_11_elems | |
5 | ||
6 | As the 802.11 spec evolves, we need to parse more and more | |
7 | elements. This is causing the struct to grow, and we can no | |
8 | longer get away with putting it on the stack. | |
9 | ||
10 | Change the API to always dynamically allocate and return an | |
11 | allocated pointer that must be kfree()d later. | |
12 | ||
13 | As an alternative, I contemplated a scheme whereby we'd say | |
14 | in the code which elements we needed, e.g. | |
15 | ||
16 | DECLARE_ELEMENT_PARSER(elems, | |
17 | SUPPORTED_CHANNELS, | |
18 | CHANNEL_SWITCH, | |
19 | EXT(KEY_DELIVERY)); | |
20 | ||
21 | ieee802_11_parse_elems(..., &elems, ...); | |
22 | ||
23 | and while I think this is possible and will save us a lot | |
24 | since most individual places only care about a small subset | |
25 | of the elements, it ended up being a bit more work since a | |
26 | lot of places do the parsing and then pass the struct to | |
27 | other functions, sometimes with multiple levels. | |
28 | ||
29 | Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid | |
30 | Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
31 | Cc: Felix Fietkau <nbd@nbd.name> | |
32 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
33 | --- | |
34 | net/mac80211/agg-rx.c | 11 +-- | |
35 | net/mac80211/ibss.c | 25 +++--- | |
36 | net/mac80211/ieee80211_i.h | 22 ++--- | |
37 | net/mac80211/mesh.c | 85 ++++++++++-------- | |
38 | net/mac80211/mesh_hwmp.c | 44 +++++----- | |
39 | net/mac80211/mesh_plink.c | 11 +-- | |
40 | net/mac80211/mlme.c | 176 +++++++++++++++++++++---------------- | |
41 | net/mac80211/scan.c | 16 ++-- | |
42 | net/mac80211/tdls.c | 63 +++++++------ | |
43 | net/mac80211/util.c | 20 +++-- | |
44 | 10 files changed, 272 insertions(+), 201 deletions(-) | |
45 | ||
46 | diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c | |
47 | index e43176794149..ffa4f31f6c2b 100644 | |
48 | --- a/net/mac80211/agg-rx.c | |
49 | +++ b/net/mac80211/agg-rx.c | |
50 | @@ -478,7 +478,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |
51 | size_t len) | |
52 | { | |
53 | u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; | |
54 | - struct ieee802_11_elems elems = { }; | |
55 | + struct ieee802_11_elems *elems = NULL; | |
56 | u8 dialog_token; | |
57 | int ies_len; | |
58 | ||
59 | @@ -496,16 +496,17 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |
60 | ies_len = len - offsetof(struct ieee80211_mgmt, | |
61 | u.action.u.addba_req.variable); | |
62 | if (ies_len) { | |
63 | - ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, | |
64 | - ies_len, true, &elems, mgmt->bssid, NULL); | |
65 | - if (elems.parse_error) | |
66 | + elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable, | |
67 | + ies_len, true, mgmt->bssid, NULL); | |
68 | + if (!elems || elems->parse_error) | |
69 | return; | |
70 | } | |
71 | ||
72 | __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, | |
73 | start_seq_num, ba_policy, tid, | |
74 | buf_size, true, false, | |
75 | - elems.addba_ext_ie); | |
76 | + elems ? elems->addba_ext_ie : NULL); | |
77 | + kfree(elems); | |
78 | } | |
79 | ||
80 | void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif, | |
81 | diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c | |
82 | index 1e133ca58e78..4b721b48f86a 100644 | |
83 | --- a/net/mac80211/ibss.c | |
84 | +++ b/net/mac80211/ibss.c | |
85 | @@ -9,7 +9,7 @@ | |
86 | * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> | |
87 | * Copyright 2013-2014 Intel Mobile Communications GmbH | |
88 | * Copyright(c) 2016 Intel Deutschland GmbH | |
89 | - * Copyright(c) 2018-2020 Intel Corporation | |
90 | + * Copyright(c) 2018-2021 Intel Corporation | |
91 | */ | |
92 | ||
93 | #include <linux/delay.h> | |
94 | @@ -1593,7 +1593,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata, | |
95 | struct ieee80211_rx_status *rx_status) | |
96 | { | |
97 | size_t baselen; | |
98 | - struct ieee802_11_elems elems; | |
99 | + struct ieee802_11_elems *elems; | |
100 | ||
101 | BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) != | |
102 | offsetof(typeof(mgmt->u.beacon), variable)); | |
103 | @@ -1606,10 +1606,14 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata, | |
104 | if (baselen > len) | |
105 | return; | |
106 | ||
107 | - ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | |
108 | - false, &elems, mgmt->bssid, NULL); | |
109 | + elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, | |
110 | + len - baselen, false, | |
111 | + mgmt->bssid, NULL); | |
112 | ||
113 | - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | |
114 | + if (elems) { | |
115 | + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems); | |
116 | + kfree(elems); | |
117 | + } | |
118 | } | |
119 | ||
120 | void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
121 | @@ -1618,7 +1622,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
122 | struct ieee80211_rx_status *rx_status; | |
123 | struct ieee80211_mgmt *mgmt; | |
124 | u16 fc; | |
125 | - struct ieee802_11_elems elems; | |
126 | + struct ieee802_11_elems *elems; | |
127 | int ies_len; | |
128 | ||
129 | rx_status = IEEE80211_SKB_RXCB(skb); | |
130 | @@ -1655,15 +1659,16 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
131 | if (ies_len < 0) | |
132 | break; | |
133 | ||
134 | - ieee802_11_parse_elems( | |
135 | + elems = ieee802_11_parse_elems( | |
136 | mgmt->u.action.u.chan_switch.variable, | |
137 | - ies_len, true, &elems, mgmt->bssid, NULL); | |
138 | + ies_len, true, mgmt->bssid, NULL); | |
139 | ||
140 | - if (elems.parse_error) | |
141 | + if (!elems || elems->parse_error) | |
142 | break; | |
143 | ||
144 | ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len, | |
145 | - rx_status, &elems); | |
146 | + rx_status, elems); | |
147 | + kfree(elems); | |
148 | break; | |
149 | } | |
150 | } | |
151 | diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h | |
152 | index c5f0ff805010..3633e49239c7 100644 | |
153 | --- a/net/mac80211/ieee80211_i.h | |
154 | +++ b/net/mac80211/ieee80211_i.h | |
155 | @@ -2217,18 +2217,18 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, | |
156 | ieee80211_tx_skb_tid(sdata, skb, 7); | |
157 | } | |
158 | ||
159 | -void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
160 | - struct ieee802_11_elems *elems, | |
161 | - u64 filter, u32 crc, u8 *transmitter_bssid, | |
162 | - u8 *bss_bssid); | |
163 | -static inline void ieee802_11_parse_elems(const u8 *start, size_t len, | |
164 | - bool action, | |
165 | - struct ieee802_11_elems *elems, | |
166 | - u8 *transmitter_bssid, | |
167 | - u8 *bss_bssid) | |
168 | +struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, | |
169 | + bool action, | |
170 | + u64 filter, u32 crc, | |
171 | + const u8 *transmitter_bssid, | |
172 | + const u8 *bss_bssid); | |
173 | +static inline struct ieee802_11_elems * | |
174 | +ieee802_11_parse_elems(const u8 *start, size_t len, bool action, | |
175 | + const u8 *transmitter_bssid, | |
176 | + const u8 *bss_bssid) | |
177 | { | |
178 | - ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0, | |
179 | - transmitter_bssid, bss_bssid); | |
180 | + return ieee802_11_parse_elems_crc(start, len, action, 0, 0, | |
181 | + transmitter_bssid, bss_bssid); | |
182 | } | |
183 | ||
184 | ||
185 | diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c | |
186 | index 9f6414a68d71..6847fdf93439 100644 | |
187 | --- a/net/mac80211/mesh.c | |
188 | +++ b/net/mac80211/mesh.c | |
189 | @@ -1247,7 +1247,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, | |
190 | struct sk_buff *presp; | |
191 | struct beacon_data *bcn; | |
192 | struct ieee80211_mgmt *hdr; | |
193 | - struct ieee802_11_elems elems; | |
194 | + struct ieee802_11_elems *elems; | |
195 | size_t baselen; | |
196 | u8 *pos; | |
197 | ||
198 | @@ -1256,22 +1256,24 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, | |
199 | if (baselen > len) | |
200 | return; | |
201 | ||
202 | - ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid, | |
203 | - NULL); | |
204 | - | |
205 | - if (!elems.mesh_id) | |
206 | + elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid, | |
207 | + NULL); | |
208 | + if (!elems) | |
209 | return; | |
210 | ||
211 | + if (!elems->mesh_id) | |
212 | + goto free; | |
213 | + | |
214 | /* 802.11-2012 10.1.4.3.2 */ | |
215 | if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && | |
216 | !is_broadcast_ether_addr(mgmt->da)) || | |
217 | - elems.ssid_len != 0) | |
218 | - return; | |
219 | + elems->ssid_len != 0) | |
220 | + goto free; | |
221 | ||
222 | - if (elems.mesh_id_len != 0 && | |
223 | - (elems.mesh_id_len != ifmsh->mesh_id_len || | |
224 | - memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) | |
225 | - return; | |
226 | + if (elems->mesh_id_len != 0 && | |
227 | + (elems->mesh_id_len != ifmsh->mesh_id_len || | |
228 | + memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) | |
229 | + goto free; | |
230 | ||
231 | rcu_read_lock(); | |
232 | bcn = rcu_dereference(ifmsh->beacon); | |
233 | @@ -1295,6 +1297,8 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, | |
234 | ieee80211_tx_skb(sdata, presp); | |
235 | out: | |
236 | rcu_read_unlock(); | |
237 | +free: | |
238 | + kfree(elems); | |
239 | } | |
240 | ||
241 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |
242 | @@ -1305,7 +1309,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |
243 | { | |
244 | struct ieee80211_local *local = sdata->local; | |
245 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | |
246 | - struct ieee802_11_elems elems; | |
247 | + struct ieee802_11_elems *elems; | |
248 | struct ieee80211_channel *channel; | |
249 | size_t baselen; | |
250 | int freq; | |
251 | @@ -1320,42 +1324,47 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |
252 | if (baselen > len) | |
253 | return; | |
254 | ||
255 | - ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | |
256 | - false, &elems, mgmt->bssid, NULL); | |
257 | + elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable, | |
258 | + len - baselen, | |
259 | + false, mgmt->bssid, NULL); | |
260 | + if (!elems) | |
261 | + return; | |
262 | ||
263 | /* ignore non-mesh or secure / unsecure mismatch */ | |
264 | - if ((!elems.mesh_id || !elems.mesh_config) || | |
265 | - (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || | |
266 | - (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) | |
267 | - return; | |
268 | + if ((!elems->mesh_id || !elems->mesh_config) || | |
269 | + (elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || | |
270 | + (!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) | |
271 | + goto free; | |
272 | ||
273 | - if (elems.ds_params) | |
274 | - freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); | |
275 | + if (elems->ds_params) | |
276 | + freq = ieee80211_channel_to_frequency(elems->ds_params[0], band); | |
277 | else | |
278 | freq = rx_status->freq; | |
279 | ||
280 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | |
281 | ||
282 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | |
283 | - return; | |
284 | + goto free; | |
285 | ||
286 | - if (mesh_matches_local(sdata, &elems)) { | |
287 | + if (mesh_matches_local(sdata, elems)) { | |
288 | mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n", | |
289 | sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal); | |
290 | if (!sdata->u.mesh.user_mpm || | |
291 | sdata->u.mesh.mshcfg.rssi_threshold == 0 || | |
292 | sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal) | |
293 | - mesh_neighbour_update(sdata, mgmt->sa, &elems, | |
294 | + mesh_neighbour_update(sdata, mgmt->sa, elems, | |
295 | rx_status); | |
296 | ||
297 | if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && | |
298 | !sdata->vif.csa_active) | |
299 | - ieee80211_mesh_process_chnswitch(sdata, &elems, true); | |
300 | + ieee80211_mesh_process_chnswitch(sdata, elems, true); | |
301 | } | |
302 | ||
303 | if (ifmsh->sync_ops) | |
304 | ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len, | |
305 | - elems.mesh_config, rx_status); | |
306 | + elems->mesh_config, rx_status); | |
307 | +free: | |
308 | + kfree(elems); | |
309 | } | |
310 | ||
311 | int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) | |
312 | @@ -1447,7 +1456,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, | |
313 | struct ieee80211_mgmt *mgmt, size_t len) | |
314 | { | |
315 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | |
316 | - struct ieee802_11_elems elems; | |
317 | + struct ieee802_11_elems *elems; | |
318 | u16 pre_value; | |
319 | bool fwd_csa = true; | |
320 | size_t baselen; | |
321 | @@ -1460,33 +1469,37 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, | |
322 | pos = mgmt->u.action.u.chan_switch.variable; | |
323 | baselen = offsetof(struct ieee80211_mgmt, | |
324 | u.action.u.chan_switch.variable); | |
325 | - ieee802_11_parse_elems(pos, len - baselen, true, &elems, | |
326 | - mgmt->bssid, NULL); | |
327 | - | |
328 | - if (!mesh_matches_local(sdata, &elems)) | |
329 | + elems = ieee802_11_parse_elems(pos, len - baselen, true, | |
330 | + mgmt->bssid, NULL); | |
331 | + if (!elems) | |
332 | return; | |
333 | ||
334 | - ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl; | |
335 | + if (!mesh_matches_local(sdata, elems)) | |
336 | + goto free; | |
337 | + | |
338 | + ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl; | |
339 | if (!--ifmsh->chsw_ttl) | |
340 | fwd_csa = false; | |
341 | ||
342 | - pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value); | |
343 | + pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value); | |
344 | if (ifmsh->pre_value >= pre_value) | |
345 | - return; | |
346 | + goto free; | |
347 | ||
348 | ifmsh->pre_value = pre_value; | |
349 | ||
350 | if (!sdata->vif.csa_active && | |
351 | - !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { | |
352 | + !ieee80211_mesh_process_chnswitch(sdata, elems, false)) { | |
353 | mcsa_dbg(sdata, "Failed to process CSA action frame"); | |
354 | - return; | |
355 | + goto free; | |
356 | } | |
357 | ||
358 | /* forward or re-broadcast the CSA frame */ | |
359 | if (fwd_csa) { | |
360 | - if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) | |
361 | + if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0) | |
362 | mcsa_dbg(sdata, "Failed to forward the CSA frame"); | |
363 | } | |
364 | +free: | |
365 | + kfree(elems); | |
366 | } | |
367 | ||
368 | static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |
369 | diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c | |
370 | index a05b615deb51..44a6fdb6efbd 100644 | |
371 | --- a/net/mac80211/mesh_hwmp.c | |
372 | +++ b/net/mac80211/mesh_hwmp.c | |
373 | @@ -1,7 +1,7 @@ | |
374 | // SPDX-License-Identifier: GPL-2.0-only | |
375 | /* | |
376 | * Copyright (c) 2008, 2009 open80211s Ltd. | |
377 | - * Copyright (C) 2019 Intel Corporation | |
378 | + * Copyright (C) 2019, 2021 Intel Corporation | |
379 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | |
380 | */ | |
381 | ||
382 | @@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | |
383 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |
384 | struct ieee80211_mgmt *mgmt, size_t len) | |
385 | { | |
386 | - struct ieee802_11_elems elems; | |
387 | + struct ieee802_11_elems *elems; | |
388 | size_t baselen; | |
389 | u32 path_metric; | |
390 | struct sta_info *sta; | |
391 | @@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |
392 | rcu_read_unlock(); | |
393 | ||
394 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; | |
395 | - ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | |
396 | - len - baselen, false, &elems, mgmt->bssid, NULL); | |
397 | + elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | |
398 | + len - baselen, false, mgmt->bssid, NULL); | |
399 | + if (!elems) | |
400 | + return; | |
401 | ||
402 | - if (elems.preq) { | |
403 | - if (elems.preq_len != 37) | |
404 | + if (elems->preq) { | |
405 | + if (elems->preq_len != 37) | |
406 | /* Right now we support just 1 destination and no AE */ | |
407 | - return; | |
408 | - path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, | |
409 | + goto free; | |
410 | + path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq, | |
411 | MPATH_PREQ); | |
412 | if (path_metric) | |
413 | - hwmp_preq_frame_process(sdata, mgmt, elems.preq, | |
414 | + hwmp_preq_frame_process(sdata, mgmt, elems->preq, | |
415 | path_metric); | |
416 | } | |
417 | - if (elems.prep) { | |
418 | - if (elems.prep_len != 31) | |
419 | + if (elems->prep) { | |
420 | + if (elems->prep_len != 31) | |
421 | /* Right now we support no AE */ | |
422 | - return; | |
423 | - path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, | |
424 | + goto free; | |
425 | + path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep, | |
426 | MPATH_PREP); | |
427 | if (path_metric) | |
428 | - hwmp_prep_frame_process(sdata, mgmt, elems.prep, | |
429 | + hwmp_prep_frame_process(sdata, mgmt, elems->prep, | |
430 | path_metric); | |
431 | } | |
432 | - if (elems.perr) { | |
433 | - if (elems.perr_len != 15) | |
434 | + if (elems->perr) { | |
435 | + if (elems->perr_len != 15) | |
436 | /* Right now we support only one destination per PERR */ | |
437 | - return; | |
438 | - hwmp_perr_frame_process(sdata, mgmt, elems.perr); | |
439 | + goto free; | |
440 | + hwmp_perr_frame_process(sdata, mgmt, elems->perr); | |
441 | } | |
442 | - if (elems.rann) | |
443 | - hwmp_rann_frame_process(sdata, mgmt, elems.rann); | |
444 | + if (elems->rann) | |
445 | + hwmp_rann_frame_process(sdata, mgmt, elems->rann); | |
446 | +free: | |
447 | + kfree(elems); | |
448 | } | |
449 | ||
450 | /** | |
451 | diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c | |
452 | index a6915847d78a..a829470dd59e 100644 | |
453 | --- a/net/mac80211/mesh_plink.c | |
454 | +++ b/net/mac80211/mesh_plink.c | |
455 | @@ -1,7 +1,7 @@ | |
456 | // SPDX-License-Identifier: GPL-2.0-only | |
457 | /* | |
458 | * Copyright (c) 2008, 2009 open80211s Ltd. | |
459 | - * Copyright (C) 2019 Intel Corporation | |
460 | + * Copyright (C) 2019, 2021 Intel Corporation | |
461 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | |
462 | */ | |
463 | #include <linux/gfp.h> | |
464 | @@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |
465 | struct ieee80211_mgmt *mgmt, size_t len, | |
466 | struct ieee80211_rx_status *rx_status) | |
467 | { | |
468 | - struct ieee802_11_elems elems; | |
469 | + struct ieee802_11_elems *elems; | |
470 | size_t baselen; | |
471 | u8 *baseaddr; | |
472 | ||
473 | @@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |
474 | if (baselen > len) | |
475 | return; | |
476 | } | |
477 | - ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems, | |
478 | - mgmt->bssid, NULL); | |
479 | - mesh_process_plink_frame(sdata, mgmt, &elems, rx_status); | |
480 | + elems = ieee802_11_parse_elems(baseaddr, len - baselen, true, | |
481 | + mgmt->bssid, NULL); | |
482 | + mesh_process_plink_frame(sdata, mgmt, elems, rx_status); | |
483 | + kfree(elems); | |
484 | } | |
485 | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c | |
486 | index 548cd14c5503..45efa1d1c550 100644 | |
487 | --- a/net/mac80211/mlme.c | |
488 | +++ b/net/mac80211/mlme.c | |
489 | @@ -3317,8 +3317,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |
490 | aid = 0; /* TODO */ | |
491 | } | |
492 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | |
493 | - ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems, | |
494 | - mgmt->bssid, assoc_data->bss->bssid); | |
495 | + elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, | |
496 | + mgmt->bssid, assoc_data->bss->bssid); | |
497 | + | |
498 | + if (!elems) | |
499 | + return false; | |
500 | ||
501 | if (elems->aid_resp) | |
502 | aid = le16_to_cpu(elems->aid_resp->aid); | |
503 | @@ -3340,7 +3343,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |
504 | ||
505 | if (!is_s1g && !elems->supp_rates) { | |
506 | sdata_info(sdata, "no SuppRates element in AssocResp\n"); | |
507 | - return false; | |
508 | + ret = false; | |
509 | + goto out; | |
510 | } | |
511 | ||
512 | sdata->vif.bss_conf.aid = aid; | |
513 | @@ -3362,7 +3366,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |
514 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | |
515 | (!elems->vht_cap_elem || !elems->vht_operation)))) { | |
516 | const struct cfg80211_bss_ies *ies; | |
517 | - struct ieee802_11_elems bss_elems; | |
518 | + struct ieee802_11_elems *bss_elems; | |
519 | ||
520 | rcu_read_lock(); | |
521 | ies = rcu_dereference(cbss->ies); | |
522 | @@ -3373,13 +3377,17 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |
523 | if (!bss_ies) | |
524 | return false; | |
525 | ||
526 | - ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | |
527 | - false, &bss_elems, | |
528 | - mgmt->bssid, | |
529 | - assoc_data->bss->bssid); | |
530 | + bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | |
531 | + false, mgmt->bssid, | |
532 | + assoc_data->bss->bssid); | |
533 | + if (!bss_elems) { | |
534 | + ret = false; | |
535 | + goto out; | |
536 | + } | |
537 | + | |
538 | if (assoc_data->wmm && | |
539 | - !elems->wmm_param && bss_elems.wmm_param) { | |
540 | - elems->wmm_param = bss_elems.wmm_param; | |
541 | + !elems->wmm_param && bss_elems->wmm_param) { | |
542 | + elems->wmm_param = bss_elems->wmm_param; | |
543 | sdata_info(sdata, | |
544 | "AP bug: WMM param missing from AssocResp\n"); | |
545 | } | |
546 | @@ -3388,30 +3396,32 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |
547 | * Also check if we requested HT/VHT, otherwise the AP doesn't | |
548 | * have to include the IEs in the (re)association response. | |
549 | */ | |
550 | - if (!elems->ht_cap_elem && bss_elems.ht_cap_elem && | |
551 | + if (!elems->ht_cap_elem && bss_elems->ht_cap_elem && | |
552 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | |
553 | - elems->ht_cap_elem = bss_elems.ht_cap_elem; | |
554 | + elems->ht_cap_elem = bss_elems->ht_cap_elem; | |
555 | sdata_info(sdata, | |
556 | "AP bug: HT capability missing from AssocResp\n"); | |
557 | } | |
558 | - if (!elems->ht_operation && bss_elems.ht_operation && | |
559 | + if (!elems->ht_operation && bss_elems->ht_operation && | |
560 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | |
561 | - elems->ht_operation = bss_elems.ht_operation; | |
562 | + elems->ht_operation = bss_elems->ht_operation; | |
563 | sdata_info(sdata, | |
564 | "AP bug: HT operation missing from AssocResp\n"); | |
565 | } | |
566 | - if (!elems->vht_cap_elem && bss_elems.vht_cap_elem && | |
567 | + if (!elems->vht_cap_elem && bss_elems->vht_cap_elem && | |
568 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | |
569 | - elems->vht_cap_elem = bss_elems.vht_cap_elem; | |
570 | + elems->vht_cap_elem = bss_elems->vht_cap_elem; | |
571 | sdata_info(sdata, | |
572 | "AP bug: VHT capa missing from AssocResp\n"); | |
573 | } | |
574 | - if (!elems->vht_operation && bss_elems.vht_operation && | |
575 | + if (!elems->vht_operation && bss_elems->vht_operation && | |
576 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | |
577 | - elems->vht_operation = bss_elems.vht_operation; | |
578 | + elems->vht_operation = bss_elems->vht_operation; | |
579 | sdata_info(sdata, | |
580 | "AP bug: VHT operation missing from AssocResp\n"); | |
581 | } | |
582 | + | |
583 | + kfree(bss_elems); | |
584 | } | |
585 | ||
586 | /* | |
587 | @@ -3662,6 +3672,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |
588 | ||
589 | ret = true; | |
590 | out: | |
591 | + kfree(elems); | |
592 | kfree(bss_ies); | |
593 | return ret; | |
594 | } | |
595 | @@ -3673,7 +3684,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |
596 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | |
597 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | |
598 | u16 capab_info, status_code, aid; | |
599 | - struct ieee802_11_elems elems; | |
600 | + struct ieee802_11_elems *elems; | |
601 | int ac, uapsd_queues = -1; | |
602 | u8 *pos; | |
603 | bool reassoc; | |
604 | @@ -3730,14 +3741,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |
605 | fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0) | |
606 | return; | |
607 | ||
608 | - ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems, | |
609 | - mgmt->bssid, assoc_data->bss->bssid); | |
610 | + elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, | |
611 | + mgmt->bssid, assoc_data->bss->bssid); | |
612 | + if (!elems) | |
613 | + goto notify_driver; | |
614 | ||
615 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | |
616 | - elems.timeout_int && | |
617 | - elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { | |
618 | + elems->timeout_int && | |
619 | + elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) { | |
620 | u32 tu, ms; | |
621 | - tu = le32_to_cpu(elems.timeout_int->value); | |
622 | + tu = le32_to_cpu(elems->timeout_int->value); | |
623 | ms = tu * 1024 / 1000; | |
624 | sdata_info(sdata, | |
625 | "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", | |
626 | @@ -3757,7 +3770,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |
627 | event.u.mlme.reason = status_code; | |
628 | drv_event_callback(sdata->local, sdata, &event); | |
629 | } else { | |
630 | - if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) { | |
631 | + if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) { | |
632 | /* oops -- internal error -- send timeout for now */ | |
633 | ieee80211_destroy_assoc_data(sdata, false, false); | |
634 | cfg80211_assoc_timeout(sdata->dev, cbss); | |
635 | @@ -3787,6 +3800,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |
636 | ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len); | |
637 | notify_driver: | |
638 | drv_mgd_complete_tx(sdata->local, sdata, &info); | |
639 | + kfree(elems); | |
640 | } | |
641 | ||
642 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |
643 | @@ -3991,7 +4005,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
644 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | |
645 | struct ieee80211_mgmt *mgmt = (void *) hdr; | |
646 | size_t baselen; | |
647 | - struct ieee802_11_elems elems; | |
648 | + struct ieee802_11_elems *elems; | |
649 | struct ieee80211_local *local = sdata->local; | |
650 | struct ieee80211_chanctx_conf *chanctx_conf; | |
651 | struct ieee80211_channel *chan; | |
652 | @@ -4037,15 +4051,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
653 | ||
654 | if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && | |
655 | ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) { | |
656 | - ieee802_11_parse_elems(variable, | |
657 | - len - baselen, false, &elems, | |
658 | - bssid, | |
659 | - ifmgd->assoc_data->bss->bssid); | |
660 | + elems = ieee802_11_parse_elems(variable, len - baselen, false, | |
661 | + bssid, | |
662 | + ifmgd->assoc_data->bss->bssid); | |
663 | + if (!elems) | |
664 | + return; | |
665 | ||
666 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); | |
667 | ||
668 | - if (elems.dtim_period) | |
669 | - ifmgd->dtim_period = elems.dtim_period; | |
670 | + if (elems->dtim_period) | |
671 | + ifmgd->dtim_period = elems->dtim_period; | |
672 | ifmgd->have_beacon = true; | |
673 | ifmgd->assoc_data->need_beacon = false; | |
674 | if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { | |
675 | @@ -4053,17 +4068,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
676 | le64_to_cpu(mgmt->u.beacon.timestamp); | |
677 | sdata->vif.bss_conf.sync_device_ts = | |
678 | rx_status->device_timestamp; | |
679 | - sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; | |
680 | + sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; | |
681 | } | |
682 | ||
683 | - if (elems.mbssid_config_ie) | |
684 | + if (elems->mbssid_config_ie) | |
685 | bss_conf->profile_periodicity = | |
686 | - elems.mbssid_config_ie->profile_periodicity; | |
687 | + elems->mbssid_config_ie->profile_periodicity; | |
688 | else | |
689 | bss_conf->profile_periodicity = 0; | |
690 | ||
691 | - if (elems.ext_capab_len >= 11 && | |
692 | - (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) | |
693 | + if (elems->ext_capab_len >= 11 && | |
694 | + (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT)) | |
695 | bss_conf->ema_ap = true; | |
696 | else | |
697 | bss_conf->ema_ap = false; | |
698 | @@ -4072,6 +4087,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
699 | ifmgd->assoc_data->timeout = jiffies; | |
700 | ifmgd->assoc_data->timeout_started = true; | |
701 | run_again(sdata, ifmgd->assoc_data->timeout); | |
702 | + kfree(elems); | |
703 | return; | |
704 | } | |
705 | ||
706 | @@ -4103,14 +4119,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
707 | */ | |
708 | if (!ieee80211_is_s1g_beacon(hdr->frame_control)) | |
709 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | |
710 | - ieee802_11_parse_elems_crc(variable, | |
711 | - len - baselen, false, &elems, | |
712 | - care_about_ies, ncrc, | |
713 | - mgmt->bssid, bssid); | |
714 | - ncrc = elems.crc; | |
715 | + elems = ieee802_11_parse_elems_crc(variable, len - baselen, | |
716 | + false, care_about_ies, ncrc, | |
717 | + mgmt->bssid, bssid); | |
718 | + if (!elems) | |
719 | + return; | |
720 | + ncrc = elems->crc; | |
721 | ||
722 | if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && | |
723 | - ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) { | |
724 | + ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) { | |
725 | if (local->hw.conf.dynamic_ps_timeout > 0) { | |
726 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | |
727 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | |
728 | @@ -4180,12 +4197,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
729 | le64_to_cpu(mgmt->u.beacon.timestamp); | |
730 | sdata->vif.bss_conf.sync_device_ts = | |
731 | rx_status->device_timestamp; | |
732 | - sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; | |
733 | + sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count; | |
734 | } | |
735 | ||
736 | if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) || | |
737 | ieee80211_is_s1g_short_beacon(mgmt->frame_control)) | |
738 | - return; | |
739 | + goto free; | |
740 | ifmgd->beacon_crc = ncrc; | |
741 | ifmgd->beacon_crc_valid = true; | |
742 | ||
743 | @@ -4193,12 +4210,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
744 | ||
745 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | |
746 | rx_status->device_timestamp, | |
747 | - &elems, true); | |
748 | + elems, true); | |
749 | ||
750 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && | |
751 | - ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, | |
752 | - elems.wmm_param_len, | |
753 | - elems.mu_edca_param_set)) | |
754 | + ieee80211_sta_wmm_params(local, sdata, elems->wmm_param, | |
755 | + elems->wmm_param_len, | |
756 | + elems->mu_edca_param_set)) | |
757 | changed |= BSS_CHANGED_QOS; | |
758 | ||
759 | /* | |
760 | @@ -4207,7 +4224,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
761 | */ | |
762 | if (!ifmgd->have_beacon) { | |
763 | /* a few bogus AP send dtim_period = 0 or no TIM IE */ | |
764 | - bss_conf->dtim_period = elems.dtim_period ?: 1; | |
765 | + bss_conf->dtim_period = elems->dtim_period ?: 1; | |
766 | ||
767 | changed |= BSS_CHANGED_BEACON_INFO; | |
768 | ifmgd->have_beacon = true; | |
769 | @@ -4219,9 +4236,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
770 | ieee80211_recalc_ps_vif(sdata); | |
771 | } | |
772 | ||
773 | - if (elems.erp_info) { | |
774 | + if (elems->erp_info) { | |
775 | erp_valid = true; | |
776 | - erp_value = elems.erp_info[0]; | |
777 | + erp_value = elems->erp_info[0]; | |
778 | } else { | |
779 | erp_valid = false; | |
780 | } | |
781 | @@ -4234,12 +4251,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
782 | mutex_lock(&local->sta_mtx); | |
783 | sta = sta_info_get(sdata, bssid); | |
784 | ||
785 | - changed |= ieee80211_recalc_twt_req(sdata, sta, &elems); | |
786 | + changed |= ieee80211_recalc_twt_req(sdata, sta, elems); | |
787 | ||
788 | - if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem, | |
789 | - elems.vht_cap_elem, elems.ht_operation, | |
790 | - elems.vht_operation, elems.he_operation, | |
791 | - elems.s1g_oper, bssid, &changed)) { | |
792 | + if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem, | |
793 | + elems->vht_cap_elem, elems->ht_operation, | |
794 | + elems->vht_operation, elems->he_operation, | |
795 | + elems->s1g_oper, bssid, &changed)) { | |
796 | mutex_unlock(&local->sta_mtx); | |
797 | sdata_info(sdata, | |
798 | "failed to follow AP %pM bandwidth change, disconnect\n", | |
799 | @@ -4251,21 +4268,23 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |
800 | sizeof(deauth_buf), true, | |
801 | WLAN_REASON_DEAUTH_LEAVING, | |
802 | false); | |
803 | - return; | |
804 | + goto free; | |
805 | } | |
806 | ||
807 | - if (sta && elems.opmode_notif) | |
808 | - ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif, | |
809 | + if (sta && elems->opmode_notif) | |
810 | + ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif, | |
811 | rx_status->band); | |
812 | mutex_unlock(&local->sta_mtx); | |
813 | ||
814 | changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt, | |
815 | - elems.country_elem, | |
816 | - elems.country_elem_len, | |
817 | - elems.pwr_constr_elem, | |
818 | - elems.cisco_dtpc_elem); | |
819 | + elems->country_elem, | |
820 | + elems->country_elem_len, | |
821 | + elems->pwr_constr_elem, | |
822 | + elems->cisco_dtpc_elem); | |
823 | ||
824 | ieee80211_bss_info_change_notify(sdata, changed); | |
825 | +free: | |
826 | + kfree(elems); | |
827 | } | |
828 | ||
829 | void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, | |
830 | @@ -4294,7 +4313,6 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
831 | struct ieee80211_rx_status *rx_status; | |
832 | struct ieee80211_mgmt *mgmt; | |
833 | u16 fc; | |
834 | - struct ieee802_11_elems elems; | |
835 | int ies_len; | |
836 | ||
837 | rx_status = (struct ieee80211_rx_status *) skb->cb; | |
838 | @@ -4326,6 +4344,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
839 | break; | |
840 | case IEEE80211_STYPE_ACTION: | |
841 | if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { | |
842 | + struct ieee802_11_elems *elems; | |
843 | + | |
844 | ies_len = skb->len - | |
845 | offsetof(struct ieee80211_mgmt, | |
846 | u.action.u.chan_switch.variable); | |
847 | @@ -4334,18 +4354,21 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
848 | break; | |
849 | ||
850 | /* CSA IE cannot be overridden, no need for BSSID */ | |
851 | - ieee802_11_parse_elems( | |
852 | - mgmt->u.action.u.chan_switch.variable, | |
853 | - ies_len, true, &elems, mgmt->bssid, NULL); | |
854 | + elems = ieee802_11_parse_elems( | |
855 | + mgmt->u.action.u.chan_switch.variable, | |
856 | + ies_len, true, mgmt->bssid, NULL); | |
857 | ||
858 | - if (elems.parse_error) | |
859 | + if (!elems || elems->parse_error) | |
860 | break; | |
861 | ||
862 | ieee80211_sta_process_chanswitch(sdata, | |
863 | rx_status->mactime, | |
864 | rx_status->device_timestamp, | |
865 | - &elems, false); | |
866 | + elems, false); | |
867 | + kfree(elems); | |
868 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | |
869 | + struct ieee802_11_elems *elems; | |
870 | + | |
871 | ies_len = skb->len - | |
872 | offsetof(struct ieee80211_mgmt, | |
873 | u.action.u.ext_chan_switch.variable); | |
874 | @@ -4357,21 +4380,22 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |
875 | * extended CSA IE can't be overridden, no need for | |
876 | * BSSID | |
877 | */ | |
878 | - ieee802_11_parse_elems( | |
879 | - mgmt->u.action.u.ext_chan_switch.variable, | |
880 | - ies_len, true, &elems, mgmt->bssid, NULL); | |
881 | + elems = ieee802_11_parse_elems( | |
882 | + mgmt->u.action.u.ext_chan_switch.variable, | |
883 | + ies_len, true, mgmt->bssid, NULL); | |
884 | ||
885 | - if (elems.parse_error) | |
886 | + if (!elems || elems->parse_error) | |
887 | break; | |
888 | ||
889 | /* for the handling code pretend this was also an IE */ | |
890 | - elems.ext_chansw_ie = | |
891 | + elems->ext_chansw_ie = | |
892 | &mgmt->u.action.u.ext_chan_switch.data; | |
893 | ||
894 | ieee80211_sta_process_chanswitch(sdata, | |
895 | rx_status->mactime, | |
896 | rx_status->device_timestamp, | |
897 | - &elems, false); | |
898 | + elems, false); | |
899 | + kfree(elems); | |
900 | } | |
901 | break; | |
902 | } | |
903 | diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c | |
904 | index d6afaacaf7ef..e692a2487eb5 100644 | |
905 | --- a/net/mac80211/scan.c | |
906 | +++ b/net/mac80211/scan.c | |
907 | @@ -9,7 +9,7 @@ | |
908 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | |
909 | * Copyright 2013-2015 Intel Mobile Communications GmbH | |
910 | * Copyright 2016-2017 Intel Deutschland GmbH | |
911 | - * Copyright (C) 2018-2020 Intel Corporation | |
912 | + * Copyright (C) 2018-2021 Intel Corporation | |
913 | */ | |
914 | ||
915 | #include <linux/if_arp.h> | |
916 | @@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |
917 | }; | |
918 | bool signal_valid; | |
919 | struct ieee80211_sub_if_data *scan_sdata; | |
920 | - struct ieee802_11_elems elems; | |
921 | + struct ieee802_11_elems *elems; | |
922 | size_t baselen; | |
923 | u8 *elements; | |
924 | ||
925 | @@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |
926 | if (baselen > len) | |
927 | return NULL; | |
928 | ||
929 | - ieee802_11_parse_elems(elements, len - baselen, false, &elems, | |
930 | - mgmt->bssid, cbss->bssid); | |
931 | + elems = ieee802_11_parse_elems(elements, len - baselen, false, | |
932 | + mgmt->bssid, cbss->bssid); | |
933 | + if (!elems) | |
934 | + return NULL; | |
935 | ||
936 | /* In case the signal is invalid update the status */ | |
937 | signal_valid = channel == cbss->channel; | |
938 | @@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |
939 | rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; | |
940 | ||
941 | bss = (void *)cbss->priv; | |
942 | - ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon); | |
943 | + ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon); | |
944 | ||
945 | list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) { | |
946 | non_tx_bss = (void *)non_tx_cbss->priv; | |
947 | ||
948 | - ieee80211_update_bss_from_elems(local, non_tx_bss, &elems, | |
949 | + ieee80211_update_bss_from_elems(local, non_tx_bss, elems, | |
950 | rx_status, beacon); | |
951 | } | |
952 | ||
953 | + kfree(elems); | |
954 | + | |
955 | return bss; | |
956 | } | |
957 | ||
958 | diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c | |
959 | index 45e532ad1215..137be9ec94af 100644 | |
960 | --- a/net/mac80211/tdls.c | |
961 | +++ b/net/mac80211/tdls.c | |
962 | @@ -6,7 +6,7 @@ | |
963 | * Copyright 2014, Intel Corporation | |
964 | * Copyright 2014 Intel Mobile Communications GmbH | |
965 | * Copyright 2015 - 2016 Intel Deutschland GmbH | |
966 | - * Copyright (C) 2019 Intel Corporation | |
967 | + * Copyright (C) 2019, 2021 Intel Corporation | |
968 | */ | |
969 | ||
970 | #include <linux/ieee80211.h> | |
971 | @@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata, | |
972 | struct sk_buff *skb) | |
973 | { | |
974 | struct ieee80211_local *local = sdata->local; | |
975 | - struct ieee802_11_elems elems; | |
976 | + struct ieee802_11_elems *elems = NULL; | |
977 | struct sta_info *sta; | |
978 | struct ieee80211_tdls_data *tf = (void *)skb->data; | |
979 | bool local_initiator; | |
980 | @@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata, | |
981 | goto call_drv; | |
982 | } | |
983 | ||
984 | - ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, | |
985 | - skb->len - baselen, false, &elems, | |
986 | - NULL, NULL); | |
987 | - if (elems.parse_error) { | |
988 | + elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, | |
989 | + skb->len - baselen, false, NULL, NULL); | |
990 | + if (!elems) { | |
991 | + ret = -ENOMEM; | |
992 | + goto out; | |
993 | + } | |
994 | + | |
995 | + if (elems->parse_error) { | |
996 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); | |
997 | ret = -EINVAL; | |
998 | goto out; | |
999 | } | |
1000 | ||
1001 | - if (!elems.ch_sw_timing || !elems.lnk_id) { | |
1002 | + if (!elems->ch_sw_timing || !elems->lnk_id) { | |
1003 | tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); | |
1004 | ret = -EINVAL; | |
1005 | goto out; | |
1006 | @@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata, | |
1007 | ||
1008 | /* validate the initiator is set correctly */ | |
1009 | local_initiator = | |
1010 | - !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
1011 | + !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
1012 | if (local_initiator == sta->sta.tdls_initiator) { | |
1013 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | |
1014 | ret = -EINVAL; | |
1015 | goto out; | |
1016 | } | |
1017 | ||
1018 | - params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | |
1019 | - params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | |
1020 | + params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); | |
1021 | + params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); | |
1022 | ||
1023 | params.tmpl_skb = | |
1024 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); | |
1025 | @@ -1763,6 +1767,7 @@ call_drv: | |
1026 | out: | |
1027 | mutex_unlock(&local->sta_mtx); | |
1028 | dev_kfree_skb_any(params.tmpl_skb); | |
1029 | + kfree(elems); | |
1030 | return ret; | |
1031 | } | |
1032 | ||
1033 | @@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | |
1034 | struct sk_buff *skb) | |
1035 | { | |
1036 | struct ieee80211_local *local = sdata->local; | |
1037 | - struct ieee802_11_elems elems; | |
1038 | + struct ieee802_11_elems *elems; | |
1039 | struct cfg80211_chan_def chandef; | |
1040 | struct ieee80211_channel *chan; | |
1041 | enum nl80211_channel_type chan_type; | |
1042 | @@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | |
1043 | return -EINVAL; | |
1044 | } | |
1045 | ||
1046 | - ieee802_11_parse_elems(tf->u.chan_switch_req.variable, | |
1047 | - skb->len - baselen, false, &elems, NULL, NULL); | |
1048 | - if (elems.parse_error) { | |
1049 | + elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable, | |
1050 | + skb->len - baselen, false, NULL, NULL); | |
1051 | + if (!elems) | |
1052 | + return -ENOMEM; | |
1053 | + | |
1054 | + if (elems->parse_error) { | |
1055 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); | |
1056 | - return -EINVAL; | |
1057 | + ret = -EINVAL; | |
1058 | + goto free; | |
1059 | } | |
1060 | ||
1061 | - if (!elems.ch_sw_timing || !elems.lnk_id) { | |
1062 | + if (!elems->ch_sw_timing || !elems->lnk_id) { | |
1063 | tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); | |
1064 | - return -EINVAL; | |
1065 | + ret = -EINVAL; | |
1066 | + goto free; | |
1067 | } | |
1068 | ||
1069 | - if (!elems.sec_chan_offs) { | |
1070 | + if (!elems->sec_chan_offs) { | |
1071 | chan_type = NL80211_CHAN_HT20; | |
1072 | } else { | |
1073 | - switch (elems.sec_chan_offs->sec_chan_offs) { | |
1074 | + switch (elems->sec_chan_offs->sec_chan_offs) { | |
1075 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | |
1076 | chan_type = NL80211_CHAN_HT40PLUS; | |
1077 | break; | |
1078 | @@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | |
1079 | if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef, | |
1080 | sdata->wdev.iftype)) { | |
1081 | tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n"); | |
1082 | - return -EINVAL; | |
1083 | + ret = -EINVAL; | |
1084 | + goto free; | |
1085 | } | |
1086 | ||
1087 | mutex_lock(&local->sta_mtx); | |
1088 | @@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | |
1089 | ||
1090 | /* validate the initiator is set correctly */ | |
1091 | local_initiator = | |
1092 | - !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
1093 | + !memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | |
1094 | if (local_initiator == sta->sta.tdls_initiator) { | |
1095 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | |
1096 | ret = -EINVAL; | |
1097 | @@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | |
1098 | } | |
1099 | ||
1100 | /* peer should have known better */ | |
1101 | - if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs && | |
1102 | - elems.sec_chan_offs->sec_chan_offs) { | |
1103 | + if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs && | |
1104 | + elems->sec_chan_offs->sec_chan_offs) { | |
1105 | tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n"); | |
1106 | ret = -ENOTSUPP; | |
1107 | goto out; | |
1108 | } | |
1109 | ||
1110 | params.chandef = &chandef; | |
1111 | - params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | |
1112 | - params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | |
1113 | + params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time); | |
1114 | + params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout); | |
1115 | ||
1116 | params.tmpl_skb = | |
1117 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, | |
1118 | @@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | |
1119 | out: | |
1120 | mutex_unlock(&local->sta_mtx); | |
1121 | dev_kfree_skb_any(params.tmpl_skb); | |
1122 | +free: | |
1123 | + kfree(elems); | |
1124 | return ret; | |
1125 | } | |
1126 | ||
1127 | diff --git a/net/mac80211/util.c b/net/mac80211/util.c | |
1128 | index 664c32b6db19..2ac61e68b6b4 100644 | |
1129 | --- a/net/mac80211/util.c | |
1130 | +++ b/net/mac80211/util.c | |
1131 | @@ -1396,8 +1396,8 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
1132 | ||
1133 | static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, | |
1134 | struct ieee802_11_elems *elems, | |
1135 | - u8 *transmitter_bssid, | |
1136 | - u8 *bss_bssid, | |
1137 | + const u8 *transmitter_bssid, | |
1138 | + const u8 *bss_bssid, | |
1139 | u8 *nontransmitted_profile) | |
1140 | { | |
1141 | const struct element *elem, *sub; | |
1142 | @@ -1464,16 +1464,20 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, | |
1143 | return found ? profile_len : 0; | |
1144 | } | |
1145 | ||
1146 | -void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
1147 | - struct ieee802_11_elems *elems, | |
1148 | - u64 filter, u32 crc, u8 *transmitter_bssid, | |
1149 | - u8 *bss_bssid) | |
1150 | +struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len, | |
1151 | + bool action, u64 filter, | |
1152 | + u32 crc, | |
1153 | + const u8 *transmitter_bssid, | |
1154 | + const u8 *bss_bssid) | |
1155 | { | |
1156 | + struct ieee802_11_elems *elems; | |
1157 | const struct element *non_inherit = NULL; | |
1158 | u8 *nontransmitted_profile; | |
1159 | int nontransmitted_profile_len = 0; | |
1160 | ||
1161 | - memset(elems, 0, sizeof(*elems)); | |
1162 | + elems = kzalloc(sizeof(*elems), GFP_ATOMIC); | |
1163 | + if (!elems) | |
1164 | + return NULL; | |
1165 | elems->ie_start = start; | |
1166 | elems->total_len = len; | |
1167 | ||
1168 | @@ -1520,6 +1524,8 @@ void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |
1169 | kfree(nontransmitted_profile); | |
1170 | ||
1171 | elems->crc = crc; | |
1172 | + | |
1173 | + return elems; | |
1174 | } | |
1175 | ||
1176 | void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata, | |
1177 | -- | |
1178 | 2.30.2 | |
1179 |