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::{ie, TimeUnit};
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 lazy_static::lazy_static;
72
73    lazy_static! {
74        static ref BSSID: Bssid = [0x33; 6].into();
75    }
76
77    const BEACON_INTERVAL: u16 = 100;
78    // Capability information: ESS, privacy, spectrum mgmt, radio msmt
79    const CAPABILITY_INFO: CapabilityInfo = CapabilityInfo(0x1111);
80    const RX_INFO: fidl_softmac::WlanRxInfo = fidl_softmac::WlanRxInfo {
81        channel: fidl_common::WlanChannel {
82            primary: 11,
83            cbw: fidl_common::ChannelBandwidth::Cbw20,
84            secondary80: 0,
85        },
86        rssi_dbm: -40,
87        snr_dbh: 35,
88
89        // Unused fields
90        rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
91        valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
92        phy: fidl_common::WlanPhyType::Dsss,
93        data_rate: 0,
94        mcs: 0,
95    };
96
97    fn beacon_frame_ies() -> Vec<u8> {
98        #[rustfmt::skip]
99        let ies = vec![
100            // SSID: "foo-ssid"
101            0x00, 0x08, 0x66, 0x6f, 0x6f, 0x2d, 0x73, 0x73, 0x69, 0x64,
102            // Supported rates: 24(B), 36, 48, 54
103            0x01, 0x04, 0xb0, 0x48, 0x60, 0x6c,
104            // DS parameter set: channel 140
105            0x03, 0x01, 0x8c,
106            // TIM - DTIM count: 0, DTIM period: 1, PVB: 2
107            0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
108            // Country info
109            0x07, 0x10,
110            0x55, 0x53, 0x20, // US, Any environment
111            0x24, 0x04, 0x24, // 1st channel: 36, # channels: 4, maximum tx power: 36 dBm
112            0x34, 0x04, 0x1e, // 1st channel: 52, # channels: 4, maximum tx power: 30 dBm
113            0x64, 0x0c, 0x1e, // 1st channel: 100, # channels: 12, maximum tx power: 30 dBm
114            0x95, 0x05, 0x24, // 1st channel: 149, # channels: 5, maximum tx power: 36 dBm
115            0x00, // padding
116            // Power constraint: 0
117            0x20, 0x01, 0x00,
118            // TPC Report Transmit Power: 9, Link Margin: 0
119            0x23, 0x02, 0x09, 0x00,
120            // RSN Information
121            0x30, 0x14, 0x01, 0x00,
122            0x00, 0x0f, 0xac, 0x04, // Group cipher: AES (CCM)
123            0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, // Pairwise cipher: AES (CCM)
124            0x01, 0x00, 0x00, 0x0f, 0xac, 0x01, // AKM: EAP
125            0x28, 0x00, // RSN capabilities
126            // HT Capabilities
127            0x2d, 0x1a,
128            0xef, 0x09, // HT capabilities info
129            0x17, // A-MPDU parameters
130            0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MCS set
131            0x00, 0x00, // HT extended capabilities
132            0x00, 0x00, 0x00, 0x00, // Transmit beamforming
133            0x00, // Antenna selection capabilities
134            // HT Operation
135            0x3d, 0x16,
136            0x8c, // Primary channel: 140
137            0x0d, // HT info subset - secondary channel above, any channel width, RIFS permitted
138            0x16, 0x00, 0x00, 0x00, // HT info subsets
139            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Basic MCS set
140            // Extended Capabilities: extended channel switching, BSS transition, operating mode notification
141            0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
142            // VHT Capabilities
143            0xbf, 0x0c,
144            0x91, 0x59, 0x82, 0x0f, // VHT capabilities info
145            0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, // VHT supported MCS set
146            // VHT Operation
147            0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
148            // VHT Tx Power Envelope
149            0xc3, 0x03, 0x01, 0x24, 0x24,
150            // Aruba, Hewlett Packard vendor-specific IE
151            0xdd, 0x07, 0x00, 0x0b, 0x86, 0x01, 0x04, 0x08, 0x09,
152            // WMM parameters
153            0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01,
154            0x80, // U-APSD enabled
155            0x00, // reserved
156            0x03, 0xa4, 0x00, 0x00, // AC_BE parameters
157            0x27, 0xa4, 0x00, 0x00, // AC_BK parameters
158            0x42, 0x43, 0x5e, 0x00, // AC_VI parameters
159            0x62, 0x32, 0x2f, 0x00, // AC_VO parameters
160        ];
161        ies
162    }
163
164    #[test]
165    fn test_construct_bss_description() {
166        let ies = beacon_frame_ies();
167        let bss_description = construct_bss_description(
168            *BSSID,
169            TimeUnit(BEACON_INTERVAL),
170            CAPABILITY_INFO,
171            &ies[..],
172            RX_INFO,
173        )
174        .expect("expect convert_beacon to succeed");
175
176        assert_eq!(
177            bss_description,
178            fidl_common::BssDescription {
179                bssid: BSSID.to_array(),
180                bss_type: fidl_common::BssType::Infrastructure,
181                beacon_period: BEACON_INTERVAL,
182                capability_info: CAPABILITY_INFO.0,
183                ies,
184                rssi_dbm: RX_INFO.rssi_dbm,
185                channel: fidl_common::WlanChannel {
186                    primary: 140,
187                    cbw: fidl_common::ChannelBandwidth::Cbw40,
188                    secondary80: 0,
189                },
190                snr_db: 0,
191            }
192        );
193    }
194}