#define IEEE80211_FCTL_VERS 0x0003
#define IEEE80211_FCTL_FTYPE 0x000c
#define IEEE80211_FCTL_STYPE 0x00f0
+#define IEEE80211_FCTL_TYPE (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)
#define IEEE80211_FCTL_TODS 0x0100
#define IEEE80211_FCTL_FROMDS 0x0200
#define IEEE80211_FCTL_MOREFRAGS 0x0400
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation
* Copyright(c) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2024 Intel Corporation
+ * Copyright (C) 2018-2025 Intel Corporation
*/
/**
if (elem_len <= 0)
return 0;
- elems = ieee802_11_parse_elems(elem_data, elem_len, true, NULL);
+ elems = ieee802_11_parse_elems(elem_data, elem_len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!elems || elems->parse_error || !elems->addba_ext_ie)
goto free;
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
- * Copyright(c) 2018-2024 Intel Corporation
+ * Copyright(c) 2018-2025 Intel Corporation
*/
#include <linux/delay.h>
{
size_t baselen;
struct ieee802_11_elems *elems;
+ u16 type;
BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
offsetof(typeof(mgmt->u.beacon), variable));
if (baselen > len)
return;
+ type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
- len - baselen, false, NULL);
+ len - baselen, type, NULL);
if (elems) {
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
if (ies_len < 0)
break;
- elems = ieee802_11_parse_elems(
- mgmt->u.action.u.chan_switch.variable,
- ies_len, true, NULL);
+ elems = ieee802_11_parse_elems(mgmt->u.action.u.chan_switch.variable,
+ ies_len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (elems && !elems->parse_error)
ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,
* @mode: connection mode for parsing
* @start: pointer to the elements
* @len: length of the elements
- * @action: %true if the elements came from an action frame
+ * @type: type of the frame the elements came from
+ * (action, probe response, beacon, etc.)
* @filter: bitmap of element IDs to filter out while calculating
* the element CRC
* @crc: CRC starting value
enum ieee80211_conn_mode mode;
const u8 *start;
size_t len;
- bool action;
+ u8 type;
u64 filter;
u32 crc;
struct cfg80211_bss *bss;
ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params);
static inline struct ieee802_11_elems *
-ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
- u64 filter, u32 crc,
- struct cfg80211_bss *bss)
+ieee802_11_parse_elems(const u8 *start, size_t len, u8 type,
+ struct cfg80211_bss *bss)
{
struct ieee80211_elems_parse_params params = {
.mode = IEEE80211_CONN_MODE_HIGHEST,
.start = start,
.len = len,
- .action = action,
- .filter = filter,
- .crc = crc,
+ .type = type,
.bss = bss,
.link_id = -1,
};
return ieee802_11_parse_elems_full(¶ms);
}
-static inline struct ieee802_11_elems *
-ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
- struct cfg80211_bss *bss)
-{
- return ieee802_11_parse_elems_crc(start, len, action, 0, 0, bss);
-}
-
extern const int ieee802_1d_to_ac[8];
static inline int ieee80211_ac_from_tid(int tid)
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
- * Copyright (C) 2018 - 2024 Intel Corporation
+ * Copyright (C) 2018 - 2025 Intel Corporation
* Authors: Luis Carlos Cobo <luisca@cozybit.com>
* Javier Cardona <javier@cozybit.com>
*/
if (baselen > len)
return;
- elems = ieee802_11_parse_elems(pos, len - baselen, false, NULL);
+ elems = ieee802_11_parse_elems(pos, len - baselen,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_REQ,
+ NULL);
if (!elems)
return;
}
static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
- u16 stype,
struct ieee80211_mgmt *mgmt,
size_t len,
struct ieee80211_rx_status *rx_status)
{
+ u16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee802_11_elems *elems;
enum nl80211_band band = rx_status->band;
/* ignore ProbeResp to foreign address */
- if (stype == IEEE80211_STYPE_PROBE_RESP &&
+ if (type == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP) &&
!ether_addr_equal(mgmt->da, sdata->vif.addr))
return;
return;
elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
- len - baselen,
- false, NULL);
+ len - baselen, type, NULL);
if (!elems)
return;
}
if (ifmsh->sync_ops)
- ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
+ ifmsh->sync_ops->rx_bcn_presp(sdata,
+ type & IEEE80211_FCTL_STYPE,
+ mgmt, len,
elems->mesh_config, rx_status);
free:
kfree(elems);
pos = mgmt->u.action.u.chan_switch.variable;
baselen = offsetof(struct ieee80211_mgmt,
u.action.u.chan_switch.variable);
- elems = ieee802_11_parse_elems(pos, len - baselen, true, NULL);
+ elems = ieee802_11_parse_elems(pos, len - baselen,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!elems)
return;
switch (stype) {
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
- ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len,
- rx_status);
+ ieee80211_mesh_rx_bcn_presp(sdata, mgmt, skb->len, rx_status);
break;
case IEEE80211_STYPE_PROBE_REQ:
ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len);
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
- * Copyright (C) 2019, 2021-2023 Intel Corporation
+ * Copyright (C) 2019, 2021-2023, 2025 Intel Corporation
* Author: Luis Carlos Cobo <luisca@cozybit.com>
*/
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
- len - baselen, false, NULL);
+ len - baselen,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!elems)
return;
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008, 2009 open80211s Ltd.
- * Copyright (C) 2019, 2021-2024 Intel Corporation
+ * Copyright (C) 2019, 2021-2025 Intel Corporation
* Author: Luis Carlos Cobo <luisca@cozybit.com>
*/
#include <linux/gfp.h>
if (baselen > len)
return;
}
- elems = ieee802_11_parse_elems(baseaddr, len - baselen, true, NULL);
+ elems = ieee802_11_parse_elems(baseaddr, len - baselen,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (elems) {
mesh_process_plink_frame(sdata, mgmt, elems, rx_status);
kfree(elems);
.from_ap = true,
.start = ies->data,
.len = ies->len,
+ .type = ies->from_beacon ?
+ IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON :
+ IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP,
};
struct ieee802_11_elems *elems;
struct ieee80211_supported_band *sband;
continue;
}
- elems = ieee802_11_parse_elems(ies->data, ies->len, false,
+ elems = ieee802_11_parse_elems(ies->data, ies->len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_BEACON,
NULL);
if (!elems) {
rcu_read_unlock();
.len = elem_len,
.link_id = link_id == assoc_data->assoc_link_id ? -1 : link_id,
.from_ap = true,
+ .type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE,
};
bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ;
bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
.bss = NULL,
.link_id = -1,
.from_ap = true,
+ .type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE,
};
struct ieee802_11_elems *elems;
int ac;
(prof->sta_info_len - 1),
len -
(prof->sta_info_len - 1),
- false, NULL);
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_BEACON,
+ NULL);
/* memory allocation failed - let's hope that's transient */
if (!prof_elems)
.mode = link->u.mgd.conn.mode,
.link_id = -1,
.from_ap = true,
+ .type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE,
};
lockdep_assert_wiphy(local->hw.wiphy);
ies_len = len - offsetof(struct ieee80211_mgmt,
u.action.u.ttlm_req.variable);
elems = ieee802_11_parse_elems(mgmt->u.action.u.ttlm_req.variable,
- ies_len, true, NULL);
+ ies_len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!elems) {
ttlm_res = NEG_TTLM_RES_REJECT;
goto out;
break;
/* CSA IE cannot be overridden, no need for BSSID */
- elems = ieee802_11_parse_elems(
- mgmt->u.action.u.chan_switch.variable,
- ies_len, true, NULL);
+ elems = ieee802_11_parse_elems(mgmt->u.action.u.chan_switch.variable,
+ ies_len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (elems && !elems->parse_error) {
enum ieee80211_csa_source src =
* extended CSA IE can't be overridden, no need for
* BSSID
*/
- elems = ieee802_11_parse_elems(
- mgmt->u.action.u.ext_chan_switch.variable,
- ies_len, true, NULL);
+ elems = ieee802_11_parse_elems(mgmt->u.action.u.ext_chan_switch.variable,
+ ies_len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (elems && !elems->parse_error) {
enum ieee80211_csa_source src;
pos = scratch + sizeof(control);
len -= sizeof(control);
- link_elems = ieee802_11_parse_elems(pos, len, false, NULL);
+ link_elems = ieee802_11_parse_elems(pos, len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!link_elems)
continue;
u.action.u.epcs.variable) -
IEEE80211_EPCS_ENA_RESP_BODY_LEN;
- elems = ieee802_11_parse_elems(pos, ies_len, true, NULL);
+ elems = ieee802_11_parse_elems(pos, ies_len,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!elems)
return;
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2024 Intel Corporation
+ * Copyright (C) 2018-2025 Intel Corporation
*
* element parsing for mac80211
*/
bitmap_zero(seen_elems, 256);
+ switch (params->type) {
+ /* we don't need to parse assoc request, luckily (it's value 0) */
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ:
+ default:
+ WARN(1, "invalid frame type 0x%x for element parsing\n",
+ params->type);
+ break;
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_RESP:
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON:
+ case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION:
+ case IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON:
+ break;
+ }
+
for_each_element(elem, params->start, params->len) {
const struct element *subelem;
u8 elem_parse_failed;
if (params->mode < IEEE80211_CONN_MODE_VHT)
break;
- if (!params->action) {
+ if (params->type != (IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_UNEXPECTED_ELEM;
break;
case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
if (params->mode < IEEE80211_CONN_MODE_VHT)
break;
- if (params->action) {
+ if (params->type == (IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION)) {
elem_parse_failed =
IEEE80211_PARSE_ERR_UNEXPECTED_ELEM;
break;
sub->len = end - sub->start;
sub->mode = params->mode;
- sub->action = params->action;
+ sub->type = params->type;
sub->from_ap = params->from_ap;
sub->link_id = -1;
sub.start = elems_parse->scratch_pos;
sub.mode = params->mode;
sub.len = nontx_len;
- sub.action = params->action;
+ sub.type = params->type;
sub.link_id = params->link_id;
/* consume the space used for non-transmitted profile */
if (!update_data)
return;
- elems = ieee802_11_parse_elems(ies->data, ies->len, false, NULL);
+ elems = ieee802_11_parse_elems(ies->data, ies->len,
+ update_data->beacon ?
+ IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON :
+ IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP,
+ NULL);
if (!elems)
return;
* Copyright 2014, Intel Corporation
* Copyright 2014 Intel Mobile Communications GmbH
* Copyright 2015 - 2016 Intel Deutschland GmbH
- * Copyright (C) 2019, 2021-2024 Intel Corporation
+ * Copyright (C) 2019, 2021-2025 Intel Corporation
*/
#include <linux/ieee80211.h>
}
elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
- skb->len - baselen, false, NULL);
+ skb->len - baselen,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!elems) {
ret = -ENOMEM;
goto out;
}
elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
- skb->len - baselen, false, NULL);
+ skb->len - baselen,
+ IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION,
+ NULL);
if (!elems)
return -ENOMEM;
/*
* KUnit tests for element parsing
*
- * Copyright (C) 2023-2024 Intel Corporation
+ * Copyright (C) 2023-2025 Intel Corporation
*/
#include <kunit/test.h>
#include "../ieee80211_i.h"
.link_id = 12,
.from_ap = true,
.mode = IEEE80211_CONN_MODE_EHT,
+ /* type is not really relevant here */
+ .type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON,
};
struct ieee802_11_elems *parsed;
struct sk_buff *skb;