1use anyhow::format_err;
6use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
7use fidl_fuchsia_wlan_mlme as fidl_mlme;
8use fidl_fuchsia_wlan_softmac as fidl_softmac;
9use std::fmt::Display;
10
11#[macro_export]
12macro_rules! zeroed_array_from_prefix {
13 ($slice:expr, $size:expr $(,)?) => {{
14 assert!($slice.len() <= $size);
15 let mut a = [0; $size];
16 a[..$slice.len()].clone_from_slice(&$slice);
17 a
18 }};
19}
20
21pub fn softmac_key_configuration_from_mlme(
22 key_descriptor: fidl_mlme::SetKeyDescriptor,
23) -> fidl_softmac::WlanKeyConfiguration {
24 fidl_softmac::WlanKeyConfiguration {
25 protection: Some(fidl_softmac::WlanProtection::RxTx),
26 cipher_oui: Some(key_descriptor.cipher_suite_oui),
27 cipher_type: Some(fidl_ieee80211::CipherSuiteType::into_primitive(
28 key_descriptor.cipher_suite_type,
29 ) as u8),
30 key_type: Some(match key_descriptor.key_type {
31 fidl_mlme::KeyType::Pairwise => fidl_ieee80211::KeyType::Pairwise,
32 fidl_mlme::KeyType::PeerKey => fidl_ieee80211::KeyType::Peer,
33 fidl_mlme::KeyType::Igtk => fidl_ieee80211::KeyType::Igtk,
34 fidl_mlme::KeyType::Group => fidl_ieee80211::KeyType::Group,
35 }),
36 peer_addr: Some(key_descriptor.address),
37 key_idx: Some(key_descriptor.key_id as u8),
38 key: Some(key_descriptor.key),
39 rsc: Some(key_descriptor.rsc),
40 ..Default::default()
41 }
42}
43
44pub fn mlme_band_cap_from_softmac(
45 band_cap: fidl_softmac::WlanSoftmacBandCapability,
46) -> Result<fidl_mlme::BandCapability, anyhow::Error> {
47 fn required<T>(field: Option<T>, name: impl Display) -> Result<T, anyhow::Error> {
48 field.ok_or_else(|| {
49 format_err!("Required band capability field unset in SoftMAC driver FIDL: `{}`.", name)
50 })
51 }
52
53 Ok(fidl_mlme::BandCapability {
54 band: required(band_cap.band, "band")?,
55 basic_rates: required(band_cap.basic_rates.clone(), "basic_rates")?.into(),
56 primary_channels: required(band_cap.primary_channels.clone(), "primary_channels")?,
57 ht_cap: band_cap.ht_caps.clone().map(Box::new),
58 vht_cap: band_cap.vht_caps.clone().map(Box::new),
59 })
60}
61
62pub fn mlme_device_info_from_softmac(
63 query_response: fidl_softmac::WlanSoftmacQueryResponse,
64) -> Result<fidl_mlme::DeviceInfo, anyhow::Error> {
65 fn required<T>(field: Option<T>, name: impl Display) -> Result<T, anyhow::Error> {
66 field.ok_or_else(|| {
67 format_err!("Required query field unset in SoftMAC driver FIDL: `{}`.", name)
68 })
69 }
70
71 let band_caps = query_response
72 .band_caps
73 .as_ref()
74 .map(|band_caps| {
75 band_caps.iter().cloned().map(mlme_band_cap_from_softmac).collect::<Result<Vec<_>, _>>()
76 })
77 .transpose()?;
78 Ok(fidl_mlme::DeviceInfo {
79 sta_addr: required(query_response.sta_addr, "sta_addr")?,
80 factory_addr: required(query_response.sta_addr, "sta_addr")?,
82 role: required(query_response.mac_role, "mac_role")?,
83 bands: required(band_caps, "band_caps")?,
84 qos_capable: false,
85 softmac_hardware_capability: required(
88 query_response.hardware_capability,
89 "hardware_capability",
90 )?,
91 })
92}
93
94pub fn get_rssi_dbm(rx_info: fidl_softmac::WlanRxInfo) -> Option<i8> {
95 if rx_info.valid_fields.contains(fidl_softmac::WlanRxInfoValid::RSSI) && rx_info.rssi_dbm != 0 {
96 Some(rx_info.rssi_dbm)
97 } else {
98 None
99 }
100}
101
102pub fn cssid_from_ssid_unchecked(ssid: &Vec<u8>) -> fidl_ieee80211::CSsid {
105 let mut cssid = fidl_ieee80211::CSsid {
106 len: ssid.len() as u8,
107 data: [0; fidl_ieee80211::MAX_SSID_BYTE_LEN as usize],
108 };
109 cssid.data[..ssid.len()].copy_from_slice(&ssid[..]);
111 cssid
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 fn empty_rx_info() -> fidl_softmac::WlanRxInfo {
118 fidl_softmac::WlanRxInfo {
119 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
120 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
121 phy: fidl_ieee80211::WlanPhyType::Dsss,
122 data_rate: 0,
123 primary: fidl_ieee80211::ChannelNumber {
124 band: fidl_ieee80211::WlanBand::TwoGhz,
125 number: 0,
126 },
127 mcs: 0,
128 rssi_dbm: 0,
129 snr_dbh: 0,
130 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
131 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber {
132 band: fidl_ieee80211::WlanBand::TwoGhz,
133 number: 0,
134 },
135 }
136 }
137
138 #[test]
139 fn test_get_rssi_dbm_field_not_valid() {
140 let rx_info = fidl_softmac::WlanRxInfo {
141 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
142 rssi_dbm: 20,
143 ..empty_rx_info()
144 };
145 assert_eq!(get_rssi_dbm(rx_info), None);
146 }
147
148 #[test]
149 fn test_get_rssi_dbm_zero_dbm() {
150 let rx_info = fidl_softmac::WlanRxInfo {
151 valid_fields: fidl_softmac::WlanRxInfoValid::RSSI,
152 rssi_dbm: 0,
153 ..empty_rx_info()
154 };
155 assert_eq!(get_rssi_dbm(rx_info), None);
156 }
157
158 #[test]
159 fn test_get_rssi_dbm_all_good() {
160 let rx_info = fidl_softmac::WlanRxInfo {
161 valid_fields: fidl_softmac::WlanRxInfoValid::RSSI,
162 rssi_dbm: 20,
163 ..empty_rx_info()
164 };
165 assert_eq!(get_rssi_dbm(rx_info), Some(20));
166 }
167
168 #[test]
169 fn test_mlme_band_cap_from_softmac() {
170 let softmac_band_cap = fidl_softmac::WlanSoftmacBandCapability {
171 band: Some(fidl_ieee80211::WlanBand::TwoGhz),
172 basic_rates: Some(vec![
173 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
174 ]),
175 primary_channels: Some(
176 (1..=14)
177 .map(|c| fidl_ieee80211::ChannelNumber {
178 band: fidl_ieee80211::WlanBand::TwoGhz,
179 number: c,
180 })
181 .collect(),
182 ),
183 ht_caps: Some(fidl_ieee80211::HtCapabilities {
184 bytes: [
185 0x63, 0x00, 0x17, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
194 }),
195 vht_caps: Some(fidl_ieee80211::VhtCapabilities {
196 bytes: [
197 0xfe, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x00, 0x00, 0x55, 0xff, 0x00, 0x00, ],
200 }),
201 ..Default::default()
202 };
203 let mlme_band_cap = mlme_band_cap_from_softmac(softmac_band_cap)
204 .expect("failed to convert band capability");
205 assert_eq!(mlme_band_cap.band, fidl_ieee80211::WlanBand::TwoGhz);
206 assert_eq!(
207 mlme_band_cap.basic_rates,
208 vec![0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c]
209 );
210 let expected_channels: Vec<fidl_ieee80211::ChannelNumber> = (1..=14)
211 .map(|c| fidl_ieee80211::ChannelNumber {
212 band: fidl_ieee80211::WlanBand::TwoGhz,
213 number: c,
214 })
215 .collect();
216 assert_eq!(mlme_band_cap.primary_channels, expected_channels);
217 assert!(mlme_band_cap.ht_cap.is_some());
218 assert!(mlme_band_cap.vht_cap.is_some());
219 }
220}