wlan_fullmac_mlme/convert/
fullmac_to_mlme.rs

1// Copyright 2024 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::{Context, Error, Result, bail};
6use log::warn;
7use {
8    fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_fullmac as fidl_fullmac,
9    fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211, fidl_fuchsia_wlan_internal as fidl_internal,
10    fidl_fuchsia_wlan_mlme as fidl_mlme,
11};
12
13pub fn convert_device_info(
14    info: fidl_fullmac::WlanFullmacImplQueryResponse,
15) -> Result<fidl_mlme::DeviceInfo> {
16    let bands: Vec<fidl_mlme::BandCapability> = info
17        .band_caps
18        .context("missing band_caps")?
19        .into_iter()
20        .map(|band_cap| convert_band_cap(band_cap))
21        .collect::<Result<Vec<fidl_mlme::BandCapability>>>()
22        .context("could not convert band_cap")?;
23    Ok(fidl_mlme::DeviceInfo {
24        sta_addr: info.sta_addr.context("missing sta_addr")?,
25        factory_addr: info.factory_addr.context("missing factory_addr")?,
26        role: info.role.context("missing role")?,
27        bands,
28        // TODO(https://fxbug.dev/42169534): This field will be replaced in the new driver features
29        // framework.
30        softmac_hardware_capability: 0,
31        // TODO(https://fxbug.dev/42120297): This field is stubbed out for future use.
32        qos_capable: false,
33    })
34}
35
36pub fn convert_set_keys_resp(
37    resp: fidl_fullmac::WlanFullmacSetKeysResp,
38    original_set_keys_req: &fidl_mlme::SetKeysRequest,
39) -> Result<fidl_mlme::SetKeysConfirm> {
40    if resp.statuslist.len() != original_set_keys_req.keylist.len() {
41        bail!(
42            "SetKeysReq and SetKeysResp num_keys count differ: {} != {}",
43            original_set_keys_req.keylist.len(),
44            resp.statuslist.len()
45        );
46    }
47    let mut results = vec![];
48    for i in 0..resp.statuslist.len() {
49        // Okay to index because `i` is less than the length of `resp.statuslist`, and we
50        // already checked that `keylist` is the same length as `resp.statuslist`
51        #[expect(clippy::indexing_slicing)]
52        results.push(fidl_mlme::SetKeyResult {
53            key_id: original_set_keys_req.keylist[i].key_id,
54            status: resp.statuslist[i],
55        });
56    }
57    Ok(fidl_mlme::SetKeysConfirm { results })
58}
59
60pub fn convert_scan_result(
61    result: fidl_fullmac::WlanFullmacImplIfcOnScanResultRequest,
62) -> Result<fidl_mlme::ScanResult> {
63    Ok(fidl_mlme::ScanResult {
64        txn_id: result.txn_id.context("missing txn_id")?,
65        timestamp_nanos: result.timestamp_nanos.context("missing timestamp_nanos")?,
66        bss: result.bss.context("missing bss")?,
67    })
68}
69
70pub fn convert_scan_end(
71    end: fidl_fullmac::WlanFullmacImplIfcOnScanEndRequest,
72) -> Result<fidl_mlme::ScanEnd> {
73    use fidl_fullmac::WlanScanResult;
74    let scan_result_code = end.code.context("missing code")?;
75    Ok(fidl_mlme::ScanEnd {
76        txn_id: end.txn_id.context("missing txn_id")?,
77        code: match scan_result_code {
78            WlanScanResult::Success => fidl_mlme::ScanResultCode::Success,
79            WlanScanResult::NotSupported => fidl_mlme::ScanResultCode::NotSupported,
80            WlanScanResult::InvalidArgs => fidl_mlme::ScanResultCode::InvalidArgs,
81            WlanScanResult::InternalError => fidl_mlme::ScanResultCode::InternalError,
82            WlanScanResult::ShouldWait => fidl_mlme::ScanResultCode::ShouldWait,
83            WlanScanResult::CanceledByDriverOrFirmware => {
84                fidl_mlme::ScanResultCode::CanceledByDriverOrFirmware
85            }
86            _ => {
87                warn!(
88                    "Invalid scan result code {}, defaulting to ScanResultCode::NotSupported",
89                    scan_result_code.into_primitive()
90                );
91                fidl_mlme::ScanResultCode::NotSupported
92            }
93        },
94    })
95}
96
97pub fn convert_connect_confirm(
98    conf: fidl_fullmac::WlanFullmacImplIfcConnectConfRequest,
99) -> Result<fidl_mlme::ConnectConfirm> {
100    Ok(fidl_mlme::ConnectConfirm {
101        peer_sta_address: conf.peer_sta_address.context("missing peer_sta_address")?,
102        result_code: conf.result_code.context("missing result_code")?,
103        association_id: if conf.result_code == Some(fidl_ieee80211::StatusCode::Success) {
104            conf.association_id.context("missing association_id")?
105        } else {
106            0
107        },
108        association_ies: if conf.result_code == Some(fidl_ieee80211::StatusCode::Success) {
109            conf.association_ies.context("missing association_ies")?
110        } else {
111            vec![]
112        },
113    })
114}
115
116pub fn convert_roam_confirm(
117    conf: fidl_fullmac::WlanFullmacImplIfcRoamConfRequest,
118) -> Result<fidl_mlme::RoamConfirm> {
119    match conf.status_code {
120        Some(status_code) => match status_code {
121            fidl_ieee80211::StatusCode::Success => Ok(fidl_mlme::RoamConfirm {
122                selected_bssid: conf.selected_bssid.context("missing selected BSSID")?,
123                status_code,
124                original_association_maintained: conf
125                    .original_association_maintained
126                    .context("missing original_association_maintained")?,
127                target_bss_authenticated: conf
128                    .target_bss_authenticated
129                    .context("missing target_bss_authenticated")?,
130                association_id: conf.association_id.context("missing association_id")?,
131                association_ies: conf.association_ies.context("missing association_ies")?,
132            }),
133            _ => Ok(fidl_mlme::RoamConfirm {
134                selected_bssid: conf.selected_bssid.context("missing selected BSSID")?,
135                status_code,
136                original_association_maintained: conf
137                    .original_association_maintained
138                    .context("missing original_association_maintained")?,
139                target_bss_authenticated: conf
140                    .target_bss_authenticated
141                    .context("missing target_bss_authenticated")?,
142                association_id: 0,
143                association_ies: Vec::new(),
144            }),
145        },
146        None => Err(Error::msg("Fullmac RoamConf is missing status_code")),
147    }
148}
149
150pub fn convert_roam_start_indication(
151    ind: fidl_fullmac::WlanFullmacImplIfcRoamStartIndRequest,
152) -> Result<fidl_mlme::RoamStartIndication> {
153    Ok(fidl_mlme::RoamStartIndication {
154        selected_bss: ind.selected_bss.context("missing selected_bss")?,
155        selected_bssid: ind.selected_bssid.context("missing selected bssid")?,
156        original_association_maintained: ind
157            .original_association_maintained
158            .context("missing original_association_maintained")?,
159    })
160}
161
162pub fn convert_roam_result_indication(
163    ind: fidl_fullmac::WlanFullmacImplIfcRoamResultIndRequest,
164) -> Result<fidl_mlme::RoamResultIndication> {
165    Ok(fidl_mlme::RoamResultIndication {
166        selected_bssid: ind.selected_bssid.context("missing selected_bss_id")?,
167        status_code: ind.status_code.context("missing status code")?,
168        original_association_maintained: ind
169            .original_association_maintained
170            .context("missing original_association_maintained")?,
171        target_bss_authenticated: ind
172            .target_bss_authenticated
173            .context("missing target_bss_authenticated")?,
174        association_id: ind.association_id.context("missing association_id")?,
175        association_ies: ind.association_ies.context("missing association_ies")?,
176    })
177}
178
179pub fn convert_authenticate_indication(
180    ind: fidl_fullmac::WlanFullmacImplIfcAuthIndRequest,
181) -> Result<fidl_mlme::AuthenticateIndication> {
182    use fidl_fullmac::WlanAuthType;
183    let auth_type = ind.auth_type.context("missing auth type")?;
184    Ok(fidl_mlme::AuthenticateIndication {
185        peer_sta_address: ind.peer_sta_address.context("missing peer_sta_address")?,
186        auth_type: match auth_type {
187            WlanAuthType::OpenSystem => fidl_mlme::AuthenticationTypes::OpenSystem,
188            WlanAuthType::SharedKey => fidl_mlme::AuthenticationTypes::SharedKey,
189            WlanAuthType::FastBssTransition => fidl_mlme::AuthenticationTypes::FastBssTransition,
190            WlanAuthType::Sae => fidl_mlme::AuthenticationTypes::Sae,
191            _ => {
192                warn!(
193                    "Invalid auth type {}, defaulting to AuthenticationTypes::OpenSystem",
194                    auth_type.into_primitive()
195                );
196                fidl_mlme::AuthenticationTypes::OpenSystem
197            }
198        },
199    })
200}
201
202pub fn convert_deauthenticate_confirm(
203    conf: fidl_fullmac::WlanFullmacImplIfcDeauthConfRequest,
204) -> fidl_mlme::DeauthenticateConfirm {
205    let peer_sta_address = conf.peer_sta_address.unwrap_or_else(|| {
206        warn!("Got None for peer_sta_address when converting DeauthConf. Substituting all zeros.");
207        [0 as u8; fidl_ieee80211::MAC_ADDR_LEN as usize]
208    });
209    fidl_mlme::DeauthenticateConfirm { peer_sta_address }
210}
211
212pub fn convert_deauthenticate_indication(
213    ind: fidl_fullmac::WlanFullmacImplIfcDeauthIndRequest,
214) -> Result<fidl_mlme::DeauthenticateIndication> {
215    Ok(fidl_mlme::DeauthenticateIndication {
216        peer_sta_address: ind.peer_sta_address.context("missing peer sta address")?,
217        reason_code: ind.reason_code.context("missing reason code")?,
218        locally_initiated: ind.locally_initiated.context("missing locally initiated")?,
219    })
220}
221pub fn convert_associate_indication(
222    ind: fidl_fullmac::WlanFullmacImplIfcAssocIndRequest,
223) -> Result<fidl_mlme::AssociateIndication> {
224    let ssid = ind.ssid.context("missing ssid")?;
225    let rsne = ind.rsne.context("missing rsne")?;
226    Ok(fidl_mlme::AssociateIndication {
227        peer_sta_address: ind.peer_sta_address.context("missing peer sta address")?,
228        // TODO(https://fxbug.dev/42068281): Fix the discrepancy between WlanFullmacAssocInd and
229        // fidl_mlme::AssociateIndication
230        capability_info: 0,
231        listen_interval: ind.listen_interval.context("missing listen interval")?,
232        ssid: if ssid.len() > 0 { Some(ssid) } else { None },
233        rates: vec![],
234        rsne: if rsne.len() > 0 { Some(rsne) } else { None },
235    })
236}
237
238pub fn convert_disassociate_confirm(
239    conf: fidl_fullmac::WlanFullmacImplIfcDisassocConfRequest,
240) -> fidl_mlme::DisassociateConfirm {
241    let status = conf.status.unwrap_or_else(|| {
242        warn!("Got None for status when converting DisassocConf. Using error INTERNAL.");
243        zx::Status::INTERNAL.into_raw()
244    });
245    fidl_mlme::DisassociateConfirm { status }
246}
247
248pub fn convert_disassociate_indication(
249    ind: fidl_fullmac::WlanFullmacImplIfcDisassocIndRequest,
250) -> Result<fidl_mlme::DisassociateIndication> {
251    Ok(fidl_mlme::DisassociateIndication {
252        peer_sta_address: ind.peer_sta_address.context("missing peer_sta_address")?,
253        reason_code: ind.reason_code.context("missing reason_code")?,
254        locally_initiated: ind.locally_initiated.context("missing locally_initiated")?,
255    })
256}
257
258pub fn convert_start_confirm(
259    conf: fidl_fullmac::WlanFullmacImplIfcStartConfRequest,
260) -> Result<fidl_mlme::StartConfirm> {
261    use fidl_fullmac::StartResult;
262    let result_code = conf.result_code.context("missing result_code")?;
263    Ok(fidl_mlme::StartConfirm {
264        result_code: match result_code {
265            StartResult::Success => fidl_mlme::StartResultCode::Success,
266            StartResult::BssAlreadyStartedOrJoined => {
267                fidl_mlme::StartResultCode::BssAlreadyStartedOrJoined
268            }
269            StartResult::ResetRequiredBeforeStart => {
270                fidl_mlme::StartResultCode::ResetRequiredBeforeStart
271            }
272            StartResult::NotSupported => fidl_mlme::StartResultCode::NotSupported,
273            _ => {
274                warn!(
275                    "Invalid start result {}, defaulting to StartResultCode::InternalError",
276                    result_code.into_primitive()
277                );
278                fidl_mlme::StartResultCode::InternalError
279            }
280        },
281    })
282}
283pub fn convert_stop_confirm(
284    conf: fidl_fullmac::WlanFullmacImplIfcStopConfRequest,
285) -> Result<fidl_mlme::StopConfirm> {
286    use fidl_fullmac::StopResult;
287    let result_code = conf.result_code.context("missing result_code")?;
288    Ok(fidl_mlme::StopConfirm {
289        result_code: match result_code {
290            StopResult::Success => fidl_mlme::StopResultCode::Success,
291            StopResult::BssAlreadyStopped => fidl_mlme::StopResultCode::BssAlreadyStopped,
292            StopResult::InternalError => fidl_mlme::StopResultCode::InternalError,
293            _ => {
294                warn!(
295                    "Invalid stop result {}, defaulting to StopResultCode::InternalError",
296                    result_code.into_primitive()
297                );
298                fidl_mlme::StopResultCode::InternalError
299            }
300        },
301    })
302}
303pub fn convert_eapol_confirm(
304    conf: fidl_fullmac::WlanFullmacImplIfcEapolConfRequest,
305) -> Result<fidl_mlme::EapolConfirm> {
306    use fidl_fullmac::EapolTxResult;
307    let result_code = conf.result_code.context("missing result_code")?;
308    Ok(fidl_mlme::EapolConfirm {
309        result_code: match result_code {
310            EapolTxResult::Success => fidl_mlme::EapolResultCode::Success,
311            EapolTxResult::TransmissionFailure => fidl_mlme::EapolResultCode::TransmissionFailure,
312            _ => {
313                warn!(
314                    "Invalid eapol result code {}, defaulting to EapolResultCode::TransmissionFailure",
315                    result_code.into_primitive()
316                );
317                fidl_mlme::EapolResultCode::TransmissionFailure
318            }
319        },
320        dst_addr: conf.dst_addr.context("missing dst_addr")?,
321    })
322}
323pub fn convert_channel_switch_info(
324    info: fidl_fullmac::WlanFullmacChannelSwitchInfo,
325) -> fidl_internal::ChannelSwitchInfo {
326    fidl_internal::ChannelSwitchInfo { new_channel: info.new_channel }
327}
328pub fn convert_signal_report_indication(
329    ind: fidl_fullmac::WlanFullmacSignalReportIndication,
330) -> fidl_internal::SignalReportIndication {
331    fidl_internal::SignalReportIndication { rssi_dbm: ind.rssi_dbm, snr_db: ind.snr_db }
332}
333pub fn convert_eapol_indication(
334    ind: fidl_fullmac::WlanFullmacImplIfcEapolIndRequest,
335) -> Result<fidl_mlme::EapolIndication> {
336    Ok(fidl_mlme::EapolIndication {
337        src_addr: ind.src_addr.context("missing src_addr")?,
338        dst_addr: ind.dst_addr.context("missing dst_addr")?,
339        data: ind.data.context("missing data")?,
340    })
341}
342pub fn convert_pmk_info(
343    info: fidl_fullmac::WlanFullmacImplIfcOnPmkAvailableRequest,
344) -> Result<fidl_mlme::PmkInfo> {
345    Ok(fidl_mlme::PmkInfo {
346        pmk: info.pmk.context("missing pmk")?,
347        pmkid: info.pmkid.context("missing pmkid")?,
348    })
349}
350pub fn convert_sae_handshake_indication(
351    ind: fidl_fullmac::WlanFullmacImplIfcSaeHandshakeIndRequest,
352) -> Result<fidl_mlme::SaeHandshakeIndication> {
353    Ok(fidl_mlme::SaeHandshakeIndication {
354        peer_sta_address: ind.peer_sta_address.context("missing peer_sta_address")?,
355    })
356}
357pub fn convert_sae_frame(frame: fidl_fullmac::SaeFrame) -> Result<fidl_mlme::SaeFrame> {
358    Ok(fidl_mlme::SaeFrame {
359        peer_sta_address: frame.peer_sta_address.context("missing peer_sta_address")?,
360        status_code: frame.status_code.context("missing status code")?,
361        seq_num: frame.seq_num.context("missing seq_num")?,
362        sae_fields: frame.sae_fields.context("missing sae_fields")?,
363    })
364}
365pub fn convert_wmm_params(
366    wmm_params: fidl_common::WlanWmmParameters,
367) -> fidl_internal::WmmStatusResponse {
368    fidl_internal::WmmStatusResponse {
369        apsd: wmm_params.apsd,
370        ac_be_params: convert_wmm_ac_params(wmm_params.ac_be_params),
371        ac_bk_params: convert_wmm_ac_params(wmm_params.ac_bk_params),
372        ac_vi_params: convert_wmm_ac_params(wmm_params.ac_vi_params),
373        ac_vo_params: convert_wmm_ac_params(wmm_params.ac_vo_params),
374    }
375}
376fn convert_wmm_ac_params(
377    params: fidl_common::WlanWmmAccessCategoryParameters,
378) -> fidl_internal::WmmAcParams {
379    fidl_internal::WmmAcParams {
380        ecw_min: params.ecw_min,
381        ecw_max: params.ecw_max,
382        aifsn: params.aifsn,
383        txop_limit: params.txop_limit,
384        acm: params.acm,
385    }
386}
387
388fn convert_band_cap(cap: fidl_fullmac::BandCapability) -> Result<fidl_mlme::BandCapability> {
389    Ok(fidl_mlme::BandCapability {
390        band: cap.band.context("missing band")?,
391        basic_rates: cap.basic_rates.context("missing basic_rates")?,
392        ht_cap: cap.ht_caps.map(Box::new),
393        vht_cap: cap.vht_caps.map(Box::new),
394        operating_channels: cap.operating_channels.context("missing operating_channels")?,
395    })
396}
397
398#[cfg(test)]
399mod tests {
400    use super::*;
401
402    fn fake_set_key_descriptor() -> fidl_mlme::SetKeyDescriptor {
403        fidl_mlme::SetKeyDescriptor {
404            key: vec![99, 100, 101, 102, 103, 14],
405            key_id: 23,
406            key_type: fidl_mlme::KeyType::Group,
407            address: [4u8; 6],
408            rsc: 123456,
409            cipher_suite_oui: [77, 88, 99],
410            cipher_suite_type: fidl_ieee80211::CipherSuiteType::Ccmp128,
411        }
412    }
413
414    #[test]
415    fn test_convert_set_keys_resp() {
416        let fullmac_resp =
417            fidl_fullmac::WlanFullmacSetKeysResp { statuslist: vec![zx::sys::ZX_ERR_INTERNAL; 1] };
418        let original_req =
419            fidl_mlme::SetKeysRequest { keylist: vec![fake_set_key_descriptor(); 1] };
420
421        assert_eq!(
422            convert_set_keys_resp(fullmac_resp, &original_req).unwrap(),
423            fidl_mlme::SetKeysConfirm {
424                results: vec![fidl_mlme::SetKeyResult {
425                    key_id: original_req.keylist[0].key_id,
426                    status: zx::sys::ZX_ERR_INTERNAL,
427                }],
428            }
429        );
430    }
431
432    #[test]
433    fn test_convert_set_keys_resp_mismatching_original_req_is_error() {
434        let fullmac_resp =
435            fidl_fullmac::WlanFullmacSetKeysResp { statuslist: vec![zx::sys::ZX_ERR_INTERNAL; 2] };
436        let original_req =
437            fidl_mlme::SetKeysRequest { keylist: vec![fake_set_key_descriptor(); 1] };
438        assert!(convert_set_keys_resp(fullmac_resp, &original_req).is_err());
439    }
440
441    #[test]
442    fn test_convert_authenticate_indication_with_unknown_auth_type_defaults_to_open_system() {
443        let fullmac = fidl_fullmac::WlanFullmacImplIfcAuthIndRequest {
444            peer_sta_address: Some([8; 6]),
445            auth_type: Some(fidl_fullmac::WlanAuthType::from_primitive_allow_unknown(100)),
446            ..Default::default()
447        };
448        assert_eq!(
449            convert_authenticate_indication(fullmac).unwrap(),
450            fidl_mlme::AuthenticateIndication {
451                peer_sta_address: [8; 6],
452                auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
453            }
454        );
455    }
456
457    #[test]
458    fn test_convert_deauthenticate_confirm_missing_address_defaults_to_zeros() {
459        let fullmac = fidl_fullmac::WlanFullmacImplIfcDeauthConfRequest {
460            peer_sta_address: None,
461            ..Default::default()
462        };
463        assert_eq!(
464            convert_deauthenticate_confirm(fullmac),
465            fidl_mlme::DeauthenticateConfirm { peer_sta_address: [0; 6] }
466        );
467    }
468
469    #[test]
470    fn test_convert_associate_indication_empty_vec_and_ssid_are_none() {
471        let fullmac = fidl_fullmac::WlanFullmacImplIfcAssocIndRequest {
472            peer_sta_address: Some([3; 6]),
473            listen_interval: Some(123),
474            ssid: vec![].into(),
475            rsne: vec![].into(),
476            vendor_ie: vec![].into(),
477            ..Default::default()
478        };
479
480        let mlme = convert_associate_indication(fullmac).unwrap();
481        assert!(mlme.ssid.is_none());
482        assert!(mlme.rsne.is_none());
483    }
484
485    #[test]
486    fn test_convert_start_confirm_unknown_result_code_defaults_to_internal_error() {
487        let fullmac = fidl_fullmac::WlanFullmacImplIfcStartConfRequest {
488            result_code: Some(fidl_fullmac::StartResult::from_primitive_allow_unknown(123)),
489            ..Default::default()
490        };
491        assert_eq!(
492            convert_start_confirm(fullmac).unwrap(),
493            fidl_mlme::StartConfirm { result_code: fidl_mlme::StartResultCode::InternalError }
494        );
495    }
496
497    #[test]
498    fn test_convert_stop_confirm_unknown_result_code_defaults_to_internal_error() {
499        let fullmac = fidl_fullmac::WlanFullmacImplIfcStopConfRequest {
500            result_code: Some(fidl_fullmac::StopResult::from_primitive_allow_unknown(123)),
501            ..Default::default()
502        };
503        assert_eq!(
504            convert_stop_confirm(fullmac).unwrap(),
505            fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::InternalError }
506        );
507    }
508
509    #[test]
510    fn test_convert_eapol_confirm_unknown_result_code_defaults_to_transmission_failure() {
511        let fullmac = fidl_fullmac::WlanFullmacImplIfcEapolConfRequest {
512            dst_addr: Some([1; 6]),
513            result_code: Some(fidl_fullmac::EapolTxResult::from_primitive_allow_unknown(123)),
514            ..Default::default()
515        };
516        assert_eq!(
517            convert_eapol_confirm(fullmac).unwrap(),
518            fidl_mlme::EapolConfirm {
519                dst_addr: [1; 6],
520                result_code: fidl_mlme::EapolResultCode::TransmissionFailure,
521            }
522        );
523    }
524
525    //
526    // Tests for helper functions
527    //
528    #[test]
529    fn test_convert_band_cap() {
530        let fullmac = fidl_fullmac::BandCapability {
531            band: Some(fidl_ieee80211::WlanBand::FiveGhz),
532            basic_rates: Some(vec![123; 3]),
533            ht_caps: Some(fidl_ieee80211::HtCapabilities { bytes: [8; 26] }),
534            vht_caps: Some(fidl_ieee80211::VhtCapabilities { bytes: [9; 12] }),
535            operating_channels: Some(vec![21; 45]),
536            ..Default::default()
537        };
538
539        assert_eq!(
540            convert_band_cap(fullmac).unwrap(),
541            fidl_mlme::BandCapability {
542                band: fidl_ieee80211::WlanBand::FiveGhz,
543                basic_rates: vec![123; 3],
544                ht_cap: Some(Box::new(fidl_ieee80211::HtCapabilities { bytes: [8; 26] })),
545                vht_cap: Some(Box::new(fidl_ieee80211::VhtCapabilities { bytes: [9; 12] })),
546                operating_channels: vec![21; 45],
547            }
548        );
549    }
550
551    #[test]
552    fn test_convert_band_cap_no_ht_vht_become_none() {
553        let fullmac = fidl_fullmac::BandCapability {
554            band: Some(fidl_ieee80211::WlanBand::FiveGhz),
555            basic_rates: Some(vec![123; 3]),
556            ht_caps: None,
557            vht_caps: None,
558            operating_channels: Some(vec![21; 45]),
559            ..Default::default()
560        };
561
562        let mlme = convert_band_cap(fullmac).unwrap();
563        assert!(mlme.ht_cap.is_none());
564        assert!(mlme.vht_cap.is_none());
565    }
566}