cfg80211: convert S1G beacon to scan results
The S1G beacon is an extension frame as opposed to management frame for the regular beacon. This means we may have to occasionally cast the frame buffer to a different header type. Luckily this isn't too bad as scan results mostly only care about the IEs. Signed-off-by: Thomas Pedersen <thomas@adapt-ip.com> Link: https://lore.kernel.org/r/20200922022818.15855-6-thomas@adapt-ip.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
7957c6c814
commit
9eaffe5078
|
@ -151,6 +151,9 @@
|
|||
|
||||
#define IEEE80211_ANO_NETTYPE_WILD 15
|
||||
|
||||
/* bits unique to S1G beacon */
|
||||
#define IEEE80211_S1G_BCN_NEXT_TBTT 0x100
|
||||
|
||||
/* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */
|
||||
#define IEEE80211_CTL_EXT_POLL 0x2000
|
||||
#define IEEE80211_CTL_EXT_SPR 0x3000
|
||||
|
@ -553,6 +556,28 @@ static inline bool ieee80211_is_s1g_beacon(__le16 fc)
|
|||
cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_next_tbtt_present - check if IEEE80211_FTYPE_EXT &&
|
||||
* IEEE80211_STYPE_S1G_BEACON && IEEE80211_S1G_BCN_NEXT_TBTT
|
||||
* @fc: frame control bytes in little-endian byteorder
|
||||
*/
|
||||
static inline bool ieee80211_next_tbtt_present(__le16 fc)
|
||||
{
|
||||
return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
|
||||
cpu_to_le16(IEEE80211_FTYPE_EXT | IEEE80211_STYPE_S1G_BEACON) &&
|
||||
fc & cpu_to_le16(IEEE80211_S1G_BCN_NEXT_TBTT);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_s1g_short_beacon - check if next tbtt present bit is set. Only
|
||||
* true for S1G beacons when they're short.
|
||||
* @fc: frame control bytes in little-endian byteorder
|
||||
*/
|
||||
static inline bool ieee80211_is_s1g_short_beacon(__le16 fc)
|
||||
{
|
||||
return ieee80211_is_s1g_beacon(fc) && ieee80211_next_tbtt_present(fc);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_is_atim - check if IEEE80211_FTYPE_MGMT && IEEE80211_STYPE_ATIM
|
||||
* @fc: frame control bytes in little-endian byteorder
|
||||
|
@ -1034,6 +1059,13 @@ struct ieee80211_ext {
|
|||
u8 change_seq;
|
||||
u8 variable[0];
|
||||
} __packed s1g_beacon;
|
||||
struct {
|
||||
u8 sa[ETH_ALEN];
|
||||
__le32 timestamp;
|
||||
u8 change_seq;
|
||||
u8 next_tbtt[3];
|
||||
u8 variable[0];
|
||||
} __packed s1g_short_beacon;
|
||||
} u;
|
||||
} __packed __aligned(2);
|
||||
|
||||
|
|
|
@ -2294,7 +2294,10 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
|||
struct cfg80211_bss_ies *ies;
|
||||
struct ieee80211_channel *channel;
|
||||
bool signal_valid;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
struct ieee80211_ext *ext = NULL;
|
||||
u8 *bssid, *variable;
|
||||
u16 capability, beacon_int;
|
||||
size_t ielen, min_hdr_len = offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
int bss_type;
|
||||
|
||||
|
@ -2313,21 +2316,57 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
|||
(data->signal < 0 || data->signal > 100)))
|
||||
return NULL;
|
||||
|
||||
if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
|
||||
if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
|
||||
ext = (void *) mgmt;
|
||||
min_hdr_len = offsetof(struct ieee80211_ext, u.s1g_beacon);
|
||||
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
|
||||
min_hdr_len = offsetof(struct ieee80211_ext,
|
||||
u.s1g_short_beacon.variable);
|
||||
}
|
||||
|
||||
if (WARN_ON(len < min_hdr_len))
|
||||
return NULL;
|
||||
|
||||
channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
|
||||
ielen = len - min_hdr_len;
|
||||
variable = mgmt->u.probe_resp.variable;
|
||||
if (ext) {
|
||||
if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
|
||||
variable = ext->u.s1g_short_beacon.variable;
|
||||
else
|
||||
variable = ext->u.s1g_beacon.variable;
|
||||
}
|
||||
|
||||
channel = cfg80211_get_bss_channel(wiphy, variable,
|
||||
ielen, data->chan, data->scan_width);
|
||||
if (!channel)
|
||||
return NULL;
|
||||
|
||||
if (ext) {
|
||||
struct ieee80211_s1g_bcn_compat_ie *compat;
|
||||
u8 *ie;
|
||||
|
||||
ie = (void *)cfg80211_find_ie(WLAN_EID_S1G_BCN_COMPAT,
|
||||
variable, ielen);
|
||||
if (!ie)
|
||||
return NULL;
|
||||
compat = (void *)(ie + 2);
|
||||
bssid = ext->u.s1g_beacon.sa;
|
||||
capability = le16_to_cpu(compat->compat_info);
|
||||
beacon_int = le16_to_cpu(compat->beacon_int);
|
||||
} else {
|
||||
bssid = mgmt->bssid;
|
||||
beacon_int = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
|
||||
}
|
||||
|
||||
ies = kzalloc(sizeof(*ies) + ielen, gfp);
|
||||
if (!ies)
|
||||
return NULL;
|
||||
ies->len = ielen;
|
||||
ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
|
||||
memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
|
||||
ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control) ||
|
||||
ieee80211_is_s1g_beacon(mgmt->frame_control);
|
||||
memcpy(ies->data, variable, ielen);
|
||||
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control))
|
||||
rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
|
||||
|
@ -2335,12 +2374,12 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
|
|||
rcu_assign_pointer(tmp.pub.beacon_ies, ies);
|
||||
rcu_assign_pointer(tmp.pub.ies, ies);
|
||||
|
||||
memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
|
||||
memcpy(tmp.pub.bssid, bssid, ETH_ALEN);
|
||||
tmp.pub.beacon_interval = beacon_int;
|
||||
tmp.pub.capability = capability;
|
||||
tmp.pub.channel = channel;
|
||||
tmp.pub.scan_width = data->scan_width;
|
||||
tmp.pub.signal = data->signal;
|
||||
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
|
||||
tmp.ts_boottime = data->boottime_ns;
|
||||
tmp.parent_tsf = data->parent_tsf;
|
||||
tmp.pub.chains = data->chains;
|
||||
|
|
Loading…
Reference in New Issue