wlan_mlme/client/
convert_beacon.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::Error;
6use ieee80211::{Bssid, MacAddrBytes};
7use wlan_common::channel::derive_channel;
8use wlan_common::mac::CapabilityInfo;
9use wlan_common::{TimeUnit, ie};
10use {fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_softmac as fidl_softmac};
11
12/// Given information from beacon or probe response, convert to BssDescription.
13pub fn construct_bss_description(
14    bssid: Bssid,
15    beacon_interval: TimeUnit,
16    capability_info: CapabilityInfo,
17    ies: &[u8],
18    rx_info: fidl_softmac::WlanRxInfo,
19) -> Result<fidl_common::BssDescription, Error> {
20    let mut dsss_channel = None;
21    let mut parsed_ht_op = None;
22    let mut parsed_vht_op = None;
23
24    for (id, body) in ie::Reader::new(ies) {
25        match id {
26            ie::Id::DSSS_PARAM_SET => {
27                dsss_channel = Some(ie::parse_dsss_param_set(body)?.current_channel)
28            }
29            ie::Id::HT_OPERATION => {
30                let ht_op = ie::parse_ht_operation(body)?;
31                parsed_ht_op = Some(*ht_op);
32            }
33            ie::Id::VHT_OPERATION => {
34                let ht_op = ie::parse_vht_operation(body)?;
35                parsed_vht_op = Some(*ht_op);
36            }
37            _ => (),
38        }
39    }
40
41    let bss_type = get_bss_type(capability_info);
42    let channel =
43        derive_channel(rx_info.channel.primary, dsss_channel, parsed_ht_op, parsed_vht_op);
44
45    Ok(fidl_common::BssDescription {
46        bssid: bssid.to_array(),
47        bss_type,
48        beacon_period: beacon_interval.0,
49        capability_info: capability_info.raw(),
50        ies: ies.to_vec(),
51        channel,
52        rssi_dbm: rx_info.rssi_dbm,
53        snr_db: 0,
54    })
55}
56
57/// Note: This is in Beacon / Probe Response frames context.
58/// IEEE Std 802.11-2016, 9.4.1.4
59fn get_bss_type(capability_info: CapabilityInfo) -> fidl_common::BssType {
60    match (capability_info.ess(), capability_info.ibss()) {
61        (true, false) => fidl_common::BssType::Infrastructure,
62        (false, true) => fidl_common::BssType::Independent,
63        (false, false) => fidl_common::BssType::Mesh,
64        _ => fidl_common::BssType::Unknown,
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
72    use std::sync::LazyLock;
73
74    static BSSID: LazyLock<Bssid> = LazyLock::new(|| [0x33; 6].into());
75
76    const BEACON_INTERVAL: u16 = 100;
77    // Capability information: ESS, privacy, spectrum mgmt, radio msmt
78    const CAPABILITY_INFO: CapabilityInfo = CapabilityInfo(0x1111);
79    const RX_INFO: fidl_softmac::WlanRxInfo = fidl_softmac::WlanRxInfo {
80        channel: fidl_ieee80211::WlanChannel {
81            primary: 11,
82            cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
83            secondary80: 0,
84        },
85        rssi_dbm: -40,
86        snr_dbh: 35,
87
88        // Unused fields
89        rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
90        valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
91        phy: fidl_common::WlanPhyType::Dsss,
92        data_rate: 0,
93        mcs: 0,
94    };
95
96    fn beacon_frame_ies() -> Vec<u8> {
97        #[rustfmt::skip]
98        let ies = vec![
99            // SSID: "foo-ssid"
100            0x00, 0x08, 0x66, 0x6f, 0x6f, 0x2d, 0x73, 0x73, 0x69, 0x64,
101            // Supported rates: 24(B), 36, 48, 54
102            0x01, 0x04, 0xb0, 0x48, 0x60, 0x6c,
103            // DS parameter set: channel 140
104            0x03, 0x01, 0x8c,
105            // TIM - DTIM count: 0, DTIM period: 1, PVB: 2
106            0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
107            // Country info
108            0x07, 0x10,
109            0x55, 0x53, 0x20, // US, Any environment
110            0x24, 0x04, 0x24, // 1st channel: 36, # channels: 4, maximum tx power: 36 dBm
111            0x34, 0x04, 0x1e, // 1st channel: 52, # channels: 4, maximum tx power: 30 dBm
112            0x64, 0x0c, 0x1e, // 1st channel: 100, # channels: 12, maximum tx power: 30 dBm
113            0x95, 0x05, 0x24, // 1st channel: 149, # channels: 5, maximum tx power: 36 dBm
114            0x00, // padding
115            // Power constraint: 0
116            0x20, 0x01, 0x00,
117            // TPC Report Transmit Power: 9, Link Margin: 0
118            0x23, 0x02, 0x09, 0x00,
119            // RSN Information
120            0x30, 0x14, 0x01, 0x00,
121            0x00, 0x0f, 0xac, 0x04, // Group cipher: AES (CCM)
122            0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, // Pairwise cipher: AES (CCM)
123            0x01, 0x00, 0x00, 0x0f, 0xac, 0x01, // AKM: EAP
124            0x28, 0x00, // RSN capabilities
125            // HT Capabilities
126            0x2d, 0x1a,
127            0xef, 0x09, // HT capabilities info
128            0x17, // A-MPDU parameters
129            0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MCS set
130            0x00, 0x00, // HT extended capabilities
131            0x00, 0x00, 0x00, 0x00, // Transmit beamforming
132            0x00, // Antenna selection capabilities
133            // HT Operation
134            0x3d, 0x16,
135            0x8c, // Primary channel: 140
136            0x0d, // HT info subset - secondary channel above, any channel width, RIFS permitted
137            0x16, 0x00, 0x00, 0x00, // HT info subsets
138            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Basic MCS set
139            // Extended Capabilities: extended channel switching, BSS transition, operating mode notification
140            0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
141            // VHT Capabilities
142            0xbf, 0x0c,
143            0x91, 0x59, 0x82, 0x0f, // VHT capabilities info
144            0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, // VHT supported MCS set
145            // VHT Operation
146            0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
147            // VHT Tx Power Envelope
148            0xc3, 0x03, 0x01, 0x24, 0x24,
149            // Aruba, Hewlett Packard vendor-specific IE
150            0xdd, 0x07, 0x00, 0x0b, 0x86, 0x01, 0x04, 0x08, 0x09,
151            // WMM parameters
152            0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01,
153            0x80, // U-APSD enabled
154            0x00, // reserved
155            0x03, 0xa4, 0x00, 0x00, // AC_BE parameters
156            0x27, 0xa4, 0x00, 0x00, // AC_BK parameters
157            0x42, 0x43, 0x5e, 0x00, // AC_VI parameters
158            0x62, 0x32, 0x2f, 0x00, // AC_VO parameters
159        ];
160        ies
161    }
162
163    #[test]
164    fn test_construct_bss_description() {
165        let ies = beacon_frame_ies();
166        let bss_description = construct_bss_description(
167            *BSSID,
168            TimeUnit(BEACON_INTERVAL),
169            CAPABILITY_INFO,
170            &ies[..],
171            RX_INFO,
172        )
173        .expect("expect convert_beacon to succeed");
174
175        assert_eq!(
176            bss_description,
177            fidl_common::BssDescription {
178                bssid: BSSID.to_array(),
179                bss_type: fidl_common::BssType::Infrastructure,
180                beacon_period: BEACON_INTERVAL,
181                capability_info: CAPABILITY_INFO.0,
182                ies,
183                rssi_dbm: RX_INFO.rssi_dbm,
184                channel: fidl_ieee80211::WlanChannel {
185                    primary: 140,
186                    cbw: fidl_ieee80211::ChannelBandwidth::Cbw40,
187                    secondary80: 0,
188                },
189                snr_db: 0,
190            }
191        );
192    }
193}