1use 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
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 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 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 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 0x00, 0x08, 0x66, 0x6f, 0x6f, 0x2d, 0x73, 0x73, 0x69, 0x64,
102 0x01, 0x04, 0xb0, 0x48, 0x60, 0x6c,
104 0x03, 0x01, 0x8c,
106 0x05, 0x04, 0x00, 0x01, 0x00, 0x02,
108 0x07, 0x10,
110 0x55, 0x53, 0x20, 0x24, 0x04, 0x24, 0x34, 0x04, 0x1e, 0x64, 0x0c, 0x1e, 0x95, 0x05, 0x24, 0x00, 0x20, 0x01, 0x00,
118 0x23, 0x02, 0x09, 0x00,
120 0x30, 0x14, 0x01, 0x00,
122 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x01, 0x28, 0x00, 0x2d, 0x1a,
128 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,
136 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,
142 0xbf, 0x0c,
144 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, 0xc0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0xc3, 0x03, 0x01, 0x24, 0x24,
150 0xdd, 0x07, 0x00, 0x0b, 0x86, 0x01, 0x04, 0x08, 0x09,
152 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01,
154 0x80, 0x00, 0x03, 0xa4, 0x00, 0x00, 0x27, 0xa4, 0x00, 0x00, 0x42, 0x43, 0x5e, 0x00, 0x62, 0x32, 0x2f, 0x00, ];
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}