1use 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 softmac_hardware_capability: 0,
31 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 #[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 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 #[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}