wlan_mlme/client/
convert_beacon.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use anyhow::Error;
use ieee80211::{Bssid, MacAddrBytes};
use wlan_common::channel::derive_channel;
use wlan_common::mac::CapabilityInfo;
use wlan_common::{ie, TimeUnit};
use {fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_softmac as fidl_softmac};

/// Given information from beacon or probe response, convert to BssDescription.
pub fn construct_bss_description(
    bssid: Bssid,
    beacon_interval: TimeUnit,
    capability_info: CapabilityInfo,
    ies: &[u8],
    rx_info: fidl_softmac::WlanRxInfo,
) -> Result<fidl_common::BssDescription, Error> {
    let mut dsss_channel = None;
    let mut parsed_ht_op = None;
    let mut parsed_vht_op = None;

    for (id, body) in ie::Reader::new(ies) {
        match id {
            ie::Id::DSSS_PARAM_SET => {
                dsss_channel = Some(ie::parse_dsss_param_set(body)?.current_channel)
            }
            ie::Id::HT_OPERATION => {
                let ht_op = ie::parse_ht_operation(body)?;
                parsed_ht_op = Some(*ht_op);
            }
            ie::Id::VHT_OPERATION => {
                let ht_op = ie::parse_vht_operation(body)?;
                parsed_vht_op = Some(*ht_op);
            }
            _ => (),
        }
    }

    let bss_type = get_bss_type(capability_info);
    let channel =
        derive_channel(rx_info.channel.primary, dsss_channel, parsed_ht_op, parsed_vht_op);

    Ok(fidl_common::BssDescription {
        bssid: bssid.to_array(),
        bss_type,
        beacon_period: beacon_interval.0,
        capability_info: capability_info.raw(),
        ies: ies.to_vec(),
        channel,
        rssi_dbm: rx_info.rssi_dbm,
        snr_db: 0,
    })
}

/// Note: This is in Beacon / Probe Response frames context.
/// IEEE Std 802.11-2016, 9.4.1.4
fn get_bss_type(capability_info: CapabilityInfo) -> fidl_common::BssType {
    match (capability_info.ess(), capability_info.ibss()) {
        (true, false) => fidl_common::BssType::Infrastructure,
        (false, true) => fidl_common::BssType::Independent,
        (false, false) => fidl_common::BssType::Mesh,
        _ => fidl_common::BssType::Unknown,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lazy_static::lazy_static;

    lazy_static! {
        static ref BSSID: Bssid = [0x33; 6].into();
    }

    const BEACON_INTERVAL: u16 = 100;
    // Capability information: ESS, privacy, spectrum mgmt, radio msmt
    const CAPABILITY_INFO: CapabilityInfo = CapabilityInfo(0x1111);
    const RX_INFO: fidl_softmac::WlanRxInfo = fidl_softmac::WlanRxInfo {
        channel: fidl_common::WlanChannel {
            primary: 11,
            cbw: fidl_common::ChannelBandwidth::Cbw20,
            secondary80: 0,
        },
        rssi_dbm: -40,
        snr_dbh: 35,

        // Unused fields
        rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
        valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
        phy: fidl_common::WlanPhyType::Dsss,
        data_rate: 0,
        mcs: 0,
    };

    fn beacon_frame_ies() -> Vec<u8> {
        #[rustfmt::skip]
        let ies = vec![
            // SSID: "foo-ssid"
            0x00, 0x08, 0x66, 0x6f, 0x6f, 0x2d, 0x73, 0x73, 0x69, 0x64,
            // Supported rates: 24(B), 36, 48, 54
            0x01, 0x04, 0xb0, 0x48, 0x60, 0x6c,
            // DS parameter set: channel 140
            0x03, 0x01, 0x8c,
            // TIM - DTIM count: 0, DTIM period: 1, PVB: 2
            0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
            // Country info
            0x07, 0x10,
            0x55, 0x53, 0x20, // US, Any environment
            0x24, 0x04, 0x24, // 1st channel: 36, # channels: 4, maximum tx power: 36 dBm
            0x34, 0x04, 0x1e, // 1st channel: 52, # channels: 4, maximum tx power: 30 dBm
            0x64, 0x0c, 0x1e, // 1st channel: 100, # channels: 12, maximum tx power: 30 dBm
            0x95, 0x05, 0x24, // 1st channel: 149, # channels: 5, maximum tx power: 36 dBm
            0x00, // padding
            // Power constraint: 0
            0x20, 0x01, 0x00,
            // TPC Report Transmit Power: 9, Link Margin: 0
            0x23, 0x02, 0x09, 0x00,
            // RSN Information
            0x30, 0x14, 0x01, 0x00,
            0x00, 0x0f, 0xac, 0x04, // Group cipher: AES (CCM)
            0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, // Pairwise cipher: AES (CCM)
            0x01, 0x00, 0x00, 0x0f, 0xac, 0x01, // AKM: EAP
            0x28, 0x00, // RSN capabilities
            // HT Capabilities
            0x2d, 0x1a,
            0xef, 0x09, // HT capabilities info
            0x17, // A-MPDU parameters
            0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // MCS set
            0x00, 0x00, // HT extended capabilities
            0x00, 0x00, 0x00, 0x00, // Transmit beamforming
            0x00, // Antenna selection capabilities
            // HT Operation
            0x3d, 0x16,
            0x8c, // Primary channel: 140
            0x0d, // HT info subset - secondary channel above, any channel width, RIFS permitted
            0x16, 0x00, 0x00, 0x00, // HT info subsets
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Basic MCS set
            // Extended Capabilities: extended channel switching, BSS transition, operating mode notification
            0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
            // VHT Capabilities
            0xbf, 0x0c,
            0x91, 0x59, 0x82, 0x0f, // VHT capabilities info
            0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, // VHT supported MCS set
            // VHT Operation
            0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
            // VHT Tx Power Envelope
            0xc3, 0x03, 0x01, 0x24, 0x24,
            // Aruba, Hewlett Packard vendor-specific IE
            0xdd, 0x07, 0x00, 0x0b, 0x86, 0x01, 0x04, 0x08, 0x09,
            // WMM parameters
            0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01,
            0x80, // U-APSD enabled
            0x00, // reserved
            0x03, 0xa4, 0x00, 0x00, // AC_BE parameters
            0x27, 0xa4, 0x00, 0x00, // AC_BK parameters
            0x42, 0x43, 0x5e, 0x00, // AC_VI parameters
            0x62, 0x32, 0x2f, 0x00, // AC_VO parameters
        ];
        ies
    }

    #[test]
    fn test_construct_bss_description() {
        let ies = beacon_frame_ies();
        let bss_description = construct_bss_description(
            *BSSID,
            TimeUnit(BEACON_INTERVAL),
            CAPABILITY_INFO,
            &ies[..],
            RX_INFO,
        )
        .expect("expect convert_beacon to succeed");

        assert_eq!(
            bss_description,
            fidl_common::BssDescription {
                bssid: BSSID.to_array(),
                bss_type: fidl_common::BssType::Infrastructure,
                beacon_period: BEACON_INTERVAL,
                capability_info: CAPABILITY_INFO.0,
                ies,
                rssi_dbm: RX_INFO.rssi_dbm,
                channel: fidl_common::WlanChannel {
                    primary: 140,
                    cbw: fidl_common::ChannelBandwidth::Cbw40,
                    secondary80: 0,
                },
                snr_db: 0,
            }
        );
    }
}