Skip to content

Commit 5d24828

Browse files
committed
mac80211: always allocate struct ieee802_11_elems
As the 802.11 spec evolves, we need to parse more and more elements. This is causing the struct to grow, and we can no longer get away with putting it on the stack. Change the API to always dynamically allocate and return an allocated pointer that must be kfree()d later. As an alternative, I contemplated a scheme whereby we'd say in the code which elements we needed, e.g. DECLARE_ELEMENT_PARSER(elems, SUPPORTED_CHANNELS, CHANNEL_SWITCH, EXT(KEY_DELIVERY)); ieee802_11_parse_elems(..., &elems, ...); and while I think this is possible and will save us a lot since most individual places only care about a small subset of the elements, it ended up being a bit more work since a lot of places do the parsing and then pass the struct to other functions, sometimes with multiple levels. Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent 49a765d commit 5d24828

File tree

10 files changed

+272
-201
lines changed

10 files changed

+272
-201
lines changed

net/mac80211/agg-rx.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
477477
size_t len)
478478
{
479479
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
480-
struct ieee802_11_elems elems = { };
480+
struct ieee802_11_elems *elems = NULL;
481481
u8 dialog_token;
482482
int ies_len;
483483

@@ -495,16 +495,17 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
495495
ies_len = len - offsetof(struct ieee80211_mgmt,
496496
u.action.u.addba_req.variable);
497497
if (ies_len) {
498-
ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
499-
ies_len, true, &elems, mgmt->bssid, NULL);
500-
if (elems.parse_error)
498+
elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
499+
ies_len, true, mgmt->bssid, NULL);
500+
if (!elems || elems->parse_error)
501501
return;
502502
}
503503

504504
__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
505505
start_seq_num, ba_policy, tid,
506506
buf_size, true, false,
507-
elems.addba_ext_ie);
507+
elems ? elems->addba_ext_ie : NULL);
508+
kfree(elems);
508509
}
509510

510511
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,

net/mac80211/ibss.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Copyright 2009, Johannes Berg <[email protected]>
1010
* Copyright 2013-2014 Intel Mobile Communications GmbH
1111
* Copyright(c) 2016 Intel Deutschland GmbH
12-
* Copyright(c) 2018-2020 Intel Corporation
12+
* Copyright(c) 2018-2021 Intel Corporation
1313
*/
1414

1515
#include <linux/delay.h>
@@ -1589,7 +1589,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
15891589
struct ieee80211_rx_status *rx_status)
15901590
{
15911591
size_t baselen;
1592-
struct ieee802_11_elems elems;
1592+
struct ieee802_11_elems *elems;
15931593

15941594
BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
15951595
offsetof(typeof(mgmt->u.beacon), variable));
@@ -1602,10 +1602,14 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
16021602
if (baselen > len)
16031603
return;
16041604

1605-
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
1606-
false, &elems, mgmt->bssid, NULL);
1605+
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
1606+
len - baselen, false,
1607+
mgmt->bssid, NULL);
16071608

1608-
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
1609+
if (elems) {
1610+
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
1611+
kfree(elems);
1612+
}
16091613
}
16101614

16111615
void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -1614,7 +1618,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
16141618
struct ieee80211_rx_status *rx_status;
16151619
struct ieee80211_mgmt *mgmt;
16161620
u16 fc;
1617-
struct ieee802_11_elems elems;
1621+
struct ieee802_11_elems *elems;
16181622
int ies_len;
16191623

16201624
rx_status = IEEE80211_SKB_RXCB(skb);
@@ -1651,15 +1655,16 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
16511655
if (ies_len < 0)
16521656
break;
16531657

1654-
ieee802_11_parse_elems(
1658+
elems = ieee802_11_parse_elems(
16551659
mgmt->u.action.u.chan_switch.variable,
1656-
ies_len, true, &elems, mgmt->bssid, NULL);
1660+
ies_len, true, mgmt->bssid, NULL);
16571661

1658-
if (elems.parse_error)
1662+
if (!elems || elems->parse_error)
16591663
break;
16601664

16611665
ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
1662-
rx_status, &elems);
1666+
rx_status, elems);
1667+
kfree(elems);
16631668
break;
16641669
}
16651670
}

net/mac80211/ieee80211_i.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,18 +2192,18 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
21922192
ieee80211_tx_skb_tid(sdata, skb, 7);
21932193
}
21942194

2195-
void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
2196-
struct ieee802_11_elems *elems,
2197-
u64 filter, u32 crc, u8 *transmitter_bssid,
2198-
u8 *bss_bssid);
2199-
static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
2200-
bool action,
2201-
struct ieee802_11_elems *elems,
2202-
u8 *transmitter_bssid,
2203-
u8 *bss_bssid)
2195+
struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
2196+
bool action,
2197+
u64 filter, u32 crc,
2198+
const u8 *transmitter_bssid,
2199+
const u8 *bss_bssid);
2200+
static inline struct ieee802_11_elems *
2201+
ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
2202+
const u8 *transmitter_bssid,
2203+
const u8 *bss_bssid)
22042204
{
2205-
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0,
2206-
transmitter_bssid, bss_bssid);
2205+
return ieee802_11_parse_elems_crc(start, len, action, 0, 0,
2206+
transmitter_bssid, bss_bssid);
22072207
}
22082208

22092209

net/mac80211/mesh.c

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,7 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
12461246
struct sk_buff *presp;
12471247
struct beacon_data *bcn;
12481248
struct ieee80211_mgmt *hdr;
1249-
struct ieee802_11_elems elems;
1249+
struct ieee802_11_elems *elems;
12501250
size_t baselen;
12511251
u8 *pos;
12521252

@@ -1255,22 +1255,24 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
12551255
if (baselen > len)
12561256
return;
12571257

1258-
ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
1259-
NULL);
1260-
1261-
if (!elems.mesh_id)
1258+
elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid,
1259+
NULL);
1260+
if (!elems)
12621261
return;
12631262

1263+
if (!elems->mesh_id)
1264+
goto free;
1265+
12641266
/* 802.11-2012 10.1.4.3.2 */
12651267
if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
12661268
!is_broadcast_ether_addr(mgmt->da)) ||
1267-
elems.ssid_len != 0)
1268-
return;
1269+
elems->ssid_len != 0)
1270+
goto free;
12691271

1270-
if (elems.mesh_id_len != 0 &&
1271-
(elems.mesh_id_len != ifmsh->mesh_id_len ||
1272-
memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
1273-
return;
1272+
if (elems->mesh_id_len != 0 &&
1273+
(elems->mesh_id_len != ifmsh->mesh_id_len ||
1274+
memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
1275+
goto free;
12741276

12751277
rcu_read_lock();
12761278
bcn = rcu_dereference(ifmsh->beacon);
@@ -1294,6 +1296,8 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
12941296
ieee80211_tx_skb(sdata, presp);
12951297
out:
12961298
rcu_read_unlock();
1299+
free:
1300+
kfree(elems);
12971301
}
12981302

12991303
static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
@@ -1304,7 +1308,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
13041308
{
13051309
struct ieee80211_local *local = sdata->local;
13061310
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1307-
struct ieee802_11_elems elems;
1311+
struct ieee802_11_elems *elems;
13081312
struct ieee80211_channel *channel;
13091313
size_t baselen;
13101314
int freq;
@@ -1319,42 +1323,47 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
13191323
if (baselen > len)
13201324
return;
13211325

1322-
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
1323-
false, &elems, mgmt->bssid, NULL);
1326+
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
1327+
len - baselen,
1328+
false, mgmt->bssid, NULL);
1329+
if (!elems)
1330+
return;
13241331

13251332
/* ignore non-mesh or secure / unsecure mismatch */
1326-
if ((!elems.mesh_id || !elems.mesh_config) ||
1327-
(elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
1328-
(!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
1329-
return;
1333+
if ((!elems->mesh_id || !elems->mesh_config) ||
1334+
(elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
1335+
(!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
1336+
goto free;
13301337

1331-
if (elems.ds_params)
1332-
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
1338+
if (elems->ds_params)
1339+
freq = ieee80211_channel_to_frequency(elems->ds_params[0], band);
13331340
else
13341341
freq = rx_status->freq;
13351342

13361343
channel = ieee80211_get_channel(local->hw.wiphy, freq);
13371344

13381345
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
1339-
return;
1346+
goto free;
13401347

1341-
if (mesh_matches_local(sdata, &elems)) {
1348+
if (mesh_matches_local(sdata, elems)) {
13421349
mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n",
13431350
sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal);
13441351
if (!sdata->u.mesh.user_mpm ||
13451352
sdata->u.mesh.mshcfg.rssi_threshold == 0 ||
13461353
sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal)
1347-
mesh_neighbour_update(sdata, mgmt->sa, &elems,
1354+
mesh_neighbour_update(sdata, mgmt->sa, elems,
13481355
rx_status);
13491356

13501357
if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
13511358
!sdata->vif.csa_active)
1352-
ieee80211_mesh_process_chnswitch(sdata, &elems, true);
1359+
ieee80211_mesh_process_chnswitch(sdata, elems, true);
13531360
}
13541361

13551362
if (ifmsh->sync_ops)
13561363
ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
1357-
elems.mesh_config, rx_status);
1364+
elems->mesh_config, rx_status);
1365+
free:
1366+
kfree(elems);
13581367
}
13591368

13601369
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
@@ -1446,7 +1455,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
14461455
struct ieee80211_mgmt *mgmt, size_t len)
14471456
{
14481457
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
1449-
struct ieee802_11_elems elems;
1458+
struct ieee802_11_elems *elems;
14501459
u16 pre_value;
14511460
bool fwd_csa = true;
14521461
size_t baselen;
@@ -1459,33 +1468,37 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
14591468
pos = mgmt->u.action.u.chan_switch.variable;
14601469
baselen = offsetof(struct ieee80211_mgmt,
14611470
u.action.u.chan_switch.variable);
1462-
ieee802_11_parse_elems(pos, len - baselen, true, &elems,
1463-
mgmt->bssid, NULL);
1464-
1465-
if (!mesh_matches_local(sdata, &elems))
1471+
elems = ieee802_11_parse_elems(pos, len - baselen, true,
1472+
mgmt->bssid, NULL);
1473+
if (!elems)
14661474
return;
14671475

1468-
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
1476+
if (!mesh_matches_local(sdata, elems))
1477+
goto free;
1478+
1479+
ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl;
14691480
if (!--ifmsh->chsw_ttl)
14701481
fwd_csa = false;
14711482

1472-
pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
1483+
pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value);
14731484
if (ifmsh->pre_value >= pre_value)
1474-
return;
1485+
goto free;
14751486

14761487
ifmsh->pre_value = pre_value;
14771488

14781489
if (!sdata->vif.csa_active &&
1479-
!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
1490+
!ieee80211_mesh_process_chnswitch(sdata, elems, false)) {
14801491
mcsa_dbg(sdata, "Failed to process CSA action frame");
1481-
return;
1492+
goto free;
14821493
}
14831494

14841495
/* forward or re-broadcast the CSA frame */
14851496
if (fwd_csa) {
1486-
if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
1497+
if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0)
14871498
mcsa_dbg(sdata, "Failed to forward the CSA frame");
14881499
}
1500+
free:
1501+
kfree(elems);
14891502
}
14901503

14911504
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,

net/mac80211/mesh_hwmp.c

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
33
* Copyright (c) 2008, 2009 open80211s Ltd.
4-
* Copyright (C) 2019 Intel Corporation
4+
* Copyright (C) 2019, 2021 Intel Corporation
55
* Author: Luis Carlos Cobo <[email protected]>
66
*/
77

@@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
908908
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
909909
struct ieee80211_mgmt *mgmt, size_t len)
910910
{
911-
struct ieee802_11_elems elems;
911+
struct ieee802_11_elems *elems;
912912
size_t baselen;
913913
u32 path_metric;
914914
struct sta_info *sta;
@@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
926926
rcu_read_unlock();
927927

928928
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
929-
ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
930-
len - baselen, false, &elems, mgmt->bssid, NULL);
929+
elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
930+
len - baselen, false, mgmt->bssid, NULL);
931+
if (!elems)
932+
return;
931933

932-
if (elems.preq) {
933-
if (elems.preq_len != 37)
934+
if (elems->preq) {
935+
if (elems->preq_len != 37)
934936
/* Right now we support just 1 destination and no AE */
935-
return;
936-
path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
937+
goto free;
938+
path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq,
937939
MPATH_PREQ);
938940
if (path_metric)
939-
hwmp_preq_frame_process(sdata, mgmt, elems.preq,
941+
hwmp_preq_frame_process(sdata, mgmt, elems->preq,
940942
path_metric);
941943
}
942-
if (elems.prep) {
943-
if (elems.prep_len != 31)
944+
if (elems->prep) {
945+
if (elems->prep_len != 31)
944946
/* Right now we support no AE */
945-
return;
946-
path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep,
947+
goto free;
948+
path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep,
947949
MPATH_PREP);
948950
if (path_metric)
949-
hwmp_prep_frame_process(sdata, mgmt, elems.prep,
951+
hwmp_prep_frame_process(sdata, mgmt, elems->prep,
950952
path_metric);
951953
}
952-
if (elems.perr) {
953-
if (elems.perr_len != 15)
954+
if (elems->perr) {
955+
if (elems->perr_len != 15)
954956
/* Right now we support only one destination per PERR */
955-
return;
956-
hwmp_perr_frame_process(sdata, mgmt, elems.perr);
957+
goto free;
958+
hwmp_perr_frame_process(sdata, mgmt, elems->perr);
957959
}
958-
if (elems.rann)
959-
hwmp_rann_frame_process(sdata, mgmt, elems.rann);
960+
if (elems->rann)
961+
hwmp_rann_frame_process(sdata, mgmt, elems->rann);
962+
free:
963+
kfree(elems);
960964
}
961965

962966
/**

0 commit comments

Comments
 (0)