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 crate::WlanSoftmacBandCapabilityExt as _;
6use anyhow::format_err;
7use std::fmt::Display;
8use {
9    fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211, fidl_fuchsia_wlan_mlme as fidl_mlme,
10    fidl_fuchsia_wlan_softmac as fidl_softmac,
11};
12
13#[macro_export]
14macro_rules! zeroed_array_from_prefix {
15    ($slice:expr, $size:expr $(,)?) => {{
16        assert!($slice.len() <= $size);
17        let mut a = [0; $size];
18        a[..$slice.len()].clone_from_slice(&$slice);
19        a
20    }};
21}
22
23pub fn softmac_key_configuration_from_mlme(
24    key_descriptor: fidl_mlme::SetKeyDescriptor,
25) -> fidl_softmac::WlanKeyConfiguration {
26    fidl_softmac::WlanKeyConfiguration {
27        protection: Some(fidl_softmac::WlanProtection::RxTx),
28        cipher_oui: Some(key_descriptor.cipher_suite_oui),
29        cipher_type: Some(fidl_ieee80211::CipherSuiteType::into_primitive(
30            key_descriptor.cipher_suite_type,
31        ) as u8),
32        key_type: Some(match key_descriptor.key_type {
33            fidl_mlme::KeyType::Pairwise => fidl_ieee80211::KeyType::Pairwise,
34            fidl_mlme::KeyType::PeerKey => fidl_ieee80211::KeyType::Peer,
35            fidl_mlme::KeyType::Igtk => fidl_ieee80211::KeyType::Igtk,
36            fidl_mlme::KeyType::Group => fidl_ieee80211::KeyType::Group,
37        }),
38        peer_addr: Some(key_descriptor.address),
39        key_idx: Some(key_descriptor.key_id as u8),
40        key: Some(key_descriptor.key),
41        rsc: Some(key_descriptor.rsc),
42        ..Default::default()
43    }
44}
45
46pub fn mlme_band_cap_from_softmac(
47    band_cap: fidl_softmac::WlanSoftmacBandCapability,
48) -> Result<fidl_mlme::BandCapability, anyhow::Error> {
49    fn required<T>(field: Option<T>, name: impl Display) -> Result<T, anyhow::Error> {
50        field.ok_or_else(|| {
51            format_err!("Required band capability field unset in SoftMAC driver FIDL: `{}`.", name)
52        })
53    }
54
55    // TODO(https://fxbug.dev/42084991): The predicate fields in `WlanSoftmacBandCapability` have been
56    //                         deprecated. As such, this function raises no errors when the
57    //                         predicate is set `true` but the predicated field is unset, because
58    //                         servers working against the deprecated fields are expected to always
59    //                         set them to `true`. Once the predicate fields have been removed,
60    //                         remove this function and map the fields directly below.
61    fn predicated<T>(predicate: Option<bool>, field: Option<T>) -> Option<T> {
62        // Do not read the predicated fields if the predicate is unset or set `false`.
63        predicate.unwrap_or(false).then_some(field).flatten()
64    }
65
66    Ok(fidl_mlme::BandCapability {
67        band: required(band_cap.band, "band")?,
68        basic_rates: required(band_cap.basic_rates(), "basic_rates")?.into(),
69        operating_channels: required(band_cap.operating_channels(), "operating_channels")?.into(),
70        ht_cap: predicated(band_cap.ht_supported, band_cap.ht_caps).map(Box::new),
71        vht_cap: predicated(band_cap.vht_supported, band_cap.vht_caps).map(Box::new),
72    })
73}
74
75pub fn mlme_device_info_from_softmac(
76    query_response: fidl_softmac::WlanSoftmacQueryResponse,
77) -> Result<fidl_mlme::DeviceInfo, anyhow::Error> {
78    fn required<T>(field: Option<T>, name: impl Display) -> Result<T, anyhow::Error> {
79        field.ok_or_else(|| {
80            format_err!("Required query field unset in SoftMAC driver FIDL: `{}`.", name)
81        })
82    }
83
84    let band_caps = query_response
85        .band_caps
86        .as_ref()
87        .map(|band_caps| {
88            band_caps.iter().cloned().map(mlme_band_cap_from_softmac).collect::<Result<Vec<_>, _>>()
89        })
90        .transpose()?;
91    Ok(fidl_mlme::DeviceInfo {
92        sta_addr: required(query_response.sta_addr, "sta_addr")?,
93        role: required(query_response.mac_role, "mac_role")?,
94        bands: required(band_caps, "band_caps")?,
95        qos_capable: false,
96        // TODO(https://fxbug.dev/349155104): This seems to only be required for an AP MLME and should not
97        // be enforced for clients.
98        softmac_hardware_capability: required(
99            query_response.hardware_capability,
100            "hardware_capability",
101        )?,
102    })
103}
104
105pub fn get_rssi_dbm(rx_info: fidl_softmac::WlanRxInfo) -> Option<i8> {
106    if rx_info.valid_fields.contains(fidl_softmac::WlanRxInfoValid::RSSI) && rx_info.rssi_dbm != 0 {
107        Some(rx_info.rssi_dbm)
108    } else {
109        None
110    }
111}
112
113// TODO(b/308634817): Remove this conversion once CSsid is no longer used for
114//                    SSIDs specified for active scan requests.
115pub fn cssid_from_ssid_unchecked(ssid: &Vec<u8>) -> fidl_ieee80211::CSsid {
116    let mut cssid = fidl_ieee80211::CSsid {
117        len: ssid.len() as u8,
118        data: [0; fidl_ieee80211::MAX_SSID_BYTE_LEN as usize],
119    };
120    // Ssid never exceeds fidl_ieee80211::MAX_SSID_BYTE_LEN bytes, so this assignment will never panic
121    cssid.data[..ssid.len()].copy_from_slice(&ssid[..]);
122    cssid
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128    use fidl_fuchsia_wlan_common as fidl_common;
129
130    fn empty_rx_info() -> fidl_softmac::WlanRxInfo {
131        fidl_softmac::WlanRxInfo {
132            rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
133            valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
134            phy: fidl_common::WlanPhyType::Dsss,
135            data_rate: 0,
136            channel: fidl_common::WlanChannel {
137                primary: 0,
138                cbw: fidl_common::ChannelBandwidth::Cbw20,
139                secondary80: 0,
140            },
141            mcs: 0,
142            rssi_dbm: 0,
143            snr_dbh: 0,
144        }
145    }
146
147    #[test]
148    fn test_get_rssi_dbm_field_not_valid() {
149        let rx_info = fidl_softmac::WlanRxInfo {
150            valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
151            rssi_dbm: 20,
152            ..empty_rx_info()
153        };
154        assert_eq!(get_rssi_dbm(rx_info), None);
155    }
156
157    #[test]
158    fn test_get_rssi_dbm_zero_dbm() {
159        let rx_info = fidl_softmac::WlanRxInfo {
160            valid_fields: fidl_softmac::WlanRxInfoValid::RSSI,
161            rssi_dbm: 0,
162            ..empty_rx_info()
163        };
164        assert_eq!(get_rssi_dbm(rx_info), None);
165    }
166
167    #[test]
168    fn test_get_rssi_dbm_all_good() {
169        let rx_info = fidl_softmac::WlanRxInfo {
170            valid_fields: fidl_softmac::WlanRxInfoValid::RSSI,
171            rssi_dbm: 20,
172            ..empty_rx_info()
173        };
174        assert_eq!(get_rssi_dbm(rx_info), Some(20));
175    }
176
177    #[test]
178    fn test_mlme_band_cap_from_softmac() {
179        let softmac_band_cap = fidl_softmac::WlanSoftmacBandCapability {
180            band: Some(fidl_ieee80211::WlanBand::TwoGhz),
181            basic_rates: Some(vec![
182                0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
183            ]),
184            operating_channels: Some(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]),
185            ht_supported: Some(true),
186            ht_caps: Some(fidl_ieee80211::HtCapabilities {
187                bytes: [
188                    0x63, 0x00, // HT capability info
189                    0x17, // AMPDU params
190                    0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191                    0x00, // Rx MCS bitmask, Supported MCS values: 0-7
192                    0x01, 0x00, 0x00, 0x00, // Tx parameters
193                    0x00, 0x00, // HT extended capabilities
194                    0x00, 0x00, 0x00, 0x00, // TX beamforming capabilities
195                    0x00, // ASEL capabilities
196                ],
197            }),
198            vht_supported: Some(false),
199            vht_caps: Some(fidl_ieee80211::VhtCapabilities { bytes: Default::default() }),
200            ..Default::default()
201        };
202        let mlme_band_cap = mlme_band_cap_from_softmac(softmac_band_cap)
203            .expect("failed to convert band capability");
204        assert_eq!(mlme_band_cap.band, fidl_ieee80211::WlanBand::TwoGhz);
205        assert_eq!(
206            mlme_band_cap.basic_rates,
207            vec![0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c]
208        );
209        assert_eq!(
210            mlme_band_cap.operating_channels,
211            vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
212        );
213        assert!(mlme_band_cap.ht_cap.is_some());
214        assert!(mlme_band_cap.vht_cap.is_none());
215    }
216}