Skip to main content

wlan_mlme/
ddk_converter.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::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        //TODO(): Replace with factory_addr when it is added to the FIDL.
81        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        // TODO(https://fxbug.dev/349155104): This seems to only be required for an AP MLME and should not
86        // be enforced for clients.
87        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
102// TODO(b/308634817): Remove this conversion once CSsid is no longer used for
103//                    SSIDs specified for active scan requests.
104pub 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    // Ssid never exceeds fidl_ieee80211::MAX_SSID_BYTE_LEN bytes, so this assignment will never panic
110    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, // HT capability info
186                    0x17, // AMPDU params
187                    0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188                    0x00, // Rx MCS bitmask, Supported MCS values: 0-7
189                    0x01, 0x00, 0x00, 0x00, // Tx parameters
190                    0x00, 0x00, // HT extended capabilities
191                    0x00, 0x00, 0x00, 0x00, // TX beamforming capabilities
192                    0x00, // ASEL capabilities
193                ],
194            }),
195            vht_caps: Some(fidl_ieee80211::VhtCapabilities {
196                bytes: [
197                    0xfe, 0xff, 0xff, 0xff, // VhtCapabilitiesInfo(u32)
198                    0xff, 0xaa, 0x00, 0x00, 0x55, 0xff, 0x00, 0x00, // VhtMcsNssSet(u64)
199                ],
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}