diff options
author | Thomas Pedersen <thomas@adapt-ip.com> | 2020-09-21 19:28:14 -0700 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2020-09-28 14:01:00 +0200 |
commit | 09a740ce352e1a1d16b9984115514ba9a4f4704b (patch) | |
tree | c86fd13c240bd142f73f24bf82b5ce49a04dfd56 /net/mac80211/mlme.c | |
parent | cac8c526ae769d86ec2d785c6f41866f75152784 (diff) |
mac80211: receive and process S1G beacons
S1G beacons are 802.11 Extension Frames, so the fixed
header part differs from regular beacons.
Add a handler to process S1G beacons and abstract out the
fetching of BSSID and element start locations in the
beacon body handler.
Signed-off-by: Thomas Pedersen <thomas@adapt-ip.com>
Link: https://lore.kernel.org/r/20200922022818.15855-14-thomas@adapt-ip.com
[don't rename, small coding style cleanups]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 79 |
1 files changed, 62 insertions, 17 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 70b6f5ee4757..fbe64a72eaff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1602,6 +1602,9 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, int new_ap_level; __le16 capab = mgmt->u.probe_resp.capab_info; + if (ieee80211_is_s1g_beacon(mgmt->frame_control)) + return 0; /* TODO */ + if (country_ie && (capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) || capab & cpu_to_le16(WLAN_CAPABILITY_RADIO_MEASURE))) { @@ -3896,11 +3899,12 @@ static bool ieee80211_rx_our_beacon(const u8 *tx_bssid, } static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_hdr *hdr, size_t len, struct ieee80211_rx_status *rx_status) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_mgmt *mgmt = (void *) hdr; size_t baselen; struct ieee802_11_elems elems; struct ieee80211_local *local = sdata->local; @@ -3910,14 +3914,24 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, u32 changed = 0; bool erp_valid; u8 erp_value = 0; - u32 ncrc; - u8 *bssid; + u32 ncrc = 0; + u8 *bssid, *variable = mgmt->u.beacon.variable; u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; sdata_assert_lock(sdata); /* Process beacon from the current BSS */ - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; + bssid = ieee80211_get_bssid(hdr, len, sdata->vif.type); + if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { + struct ieee80211_ext *ext = (void *) mgmt; + + if (ieee80211_is_s1g_short_beacon(ext->frame_control)) + variable = ext->u.s1g_short_beacon.variable; + else + variable = ext->u.s1g_beacon.variable; + } + + baselen = (u8 *) variable - (u8 *) mgmt; if (baselen > len) return; @@ -3937,10 +3951,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && - ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->assoc_data->bss)) { - ieee802_11_parse_elems(mgmt->u.beacon.variable, + ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) { + ieee802_11_parse_elems(variable, len - baselen, false, &elems, - mgmt->bssid, + bssid, ifmgd->assoc_data->bss->bssid); ieee80211_rx_bss_info(sdata, mgmt, len, rx_status); @@ -3973,7 +3987,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (!ifmgd->associated || - !ieee80211_rx_our_beacon(mgmt->bssid, ifmgd->associated)) + !ieee80211_rx_our_beacon(bssid, ifmgd->associated)) return; bssid = ifmgd->associated->bssid; @@ -3993,8 +4007,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, */ ieee80211_sta_reset_beacon_monitor(sdata); - ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); - ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, + /* TODO: CRC urrently not calculated on S1G Beacon Compatibility + * element (which carries the beacon interval). Don't forget to add a + * bit to care_about_ies[] above if mac80211 is interested in a + * changing S1G element. + */ + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); + ncrc = ieee802_11_parse_elems_crc(variable, len - baselen, false, &elems, care_about_ies, ncrc, mgmt->bssid, bssid); @@ -4028,7 +4048,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, struct ieee80211_p2p_noa_attr noa = {}; int ret; - ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable, + ret = cfg80211_get_p2p_attr(variable, len - baselen, IEEE80211_P2P_ATTR_ABSENCE_NOTICE, (u8 *) &noa, sizeof(noa)); @@ -4064,7 +4084,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, * the driver will use them. The synchronized view is currently * guaranteed only in certain callbacks. */ - if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY) && + !ieee80211_is_s1g_beacon(hdr->frame_control)) { sdata->vif.bss_conf.sync_tsf = le64_to_cpu(mgmt->u.beacon.timestamp); sdata->vif.bss_conf.sync_device_ts = @@ -4072,7 +4093,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count; } - if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) + if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) || + ieee80211_is_s1g_short_beacon(mgmt->frame_control)) return; ifmgd->beacon_crc = ncrc; ifmgd->beacon_crc_valid = true; @@ -4113,9 +4135,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } else { erp_valid = false; } - changed |= ieee80211_handle_bss_capability(sdata, - le16_to_cpu(mgmt->u.beacon.capab_info), - erp_valid, erp_value); + + if (!ieee80211_is_s1g_beacon(hdr->frame_control)) + changed |= ieee80211_handle_bss_capability(sdata, + le16_to_cpu(mgmt->u.beacon.capab_info), + erp_valid, erp_value); mutex_lock(&local->sta_mtx); sta = sta_info_get(sdata, bssid); @@ -4153,6 +4177,26 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, changed); } +void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status; + struct ieee80211_hdr *hdr; + u16 fc; + + rx_status = (struct ieee80211_rx_status *) skb->cb; + hdr = (struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + sdata_lock(sdata); + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_S1G_BEACON: + ieee80211_rx_mgmt_beacon(sdata, hdr, skb->len, rx_status); + break; + } + sdata_unlock(sdata); +} + void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -4170,7 +4214,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_BEACON: - ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); + ieee80211_rx_mgmt_beacon(sdata, (void *)mgmt, + skb->len, rx_status); break; case IEEE80211_STYPE_PROBE_RESP: ieee80211_rx_mgmt_probe_resp(sdata, skb); |