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