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