1use 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
12pub 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
57fn 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 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 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 0x00, 0x08, 0x66, 0x6f, 0x6f, 0x2d, 0x73, 0x73, 0x69, 0x64,
101 0x01, 0x04, 0xb0, 0x48, 0x60, 0x6c,
103 0x03, 0x01, 0x8c,
105 0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
107 0x07, 0x10,
109 0x55, 0x53, 0x20, 0x24, 0x04, 0x24, 0x34, 0x04, 0x1e, 0x64, 0x0c, 0x1e, 0x95, 0x05, 0x24, 0x00, 0x20, 0x01, 0x00,
117 0x23, 0x02, 0x09, 0x00,
119 0x30, 0x14, 0x01, 0x00,
121 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x01, 0x28, 0x00, 0x2d, 0x1a,
127 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x16,
135 0x8c, 0x0d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x08, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40,
141 0xbf, 0x0c,
143 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, 0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0xc3, 0x03, 0x01, 0x24, 0x24,
149 0xdd, 0x07, 0x00, 0x0b, 0x86, 0x01, 0x04, 0x08, 0x09,
151 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01,
153 0x80, 0x00, 0x03, 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, 0x62, 0x32, 0x2f, 0x00, ];
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}