1use crate::channel::{Cbw, Channel};
12use crate::ie::intersect::*;
13use crate::ie::{
14 self, parse_ht_capabilities, parse_vht_capabilities, HtCapabilities, SupportedRate,
15 VhtCapabilities,
16};
17use crate::mac::CapabilityInfo;
18use anyhow::{format_err, Context as _, Error};
19use {fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211, fidl_fuchsia_wlan_mlme as fidl_mlme};
20
21const OVERRIDE_CAP_INFO_ESS: bool = true;
25const OVERRIDE_CAP_INFO_IBSS: bool = false;
26
27const OVERRIDE_CAP_INFO_CF_POLLABLE: bool = false;
30const OVERRIDE_CAP_INFO_CF_POLL_REQUEST: bool = false;
31
32const OVERRIDE_CAP_INFO_PRIVACY: bool = false;
35
36const OVERRIDE_CAP_INFO_SPECTRUM_MGMT: bool = false;
38
39const OVERRIDE_HT_CAP_INFO_TX_STBC: bool = false;
41
42const OVERRIDE_VHT_CAP_INFO_SUPPORTED_CBW_SET: u32 = 0;
47
48fn override_capability_info(capability_info: CapabilityInfo) -> CapabilityInfo {
51 capability_info
52 .with_ess(OVERRIDE_CAP_INFO_ESS)
53 .with_ibss(OVERRIDE_CAP_INFO_IBSS)
54 .with_cf_pollable(OVERRIDE_CAP_INFO_CF_POLLABLE)
55 .with_cf_poll_req(OVERRIDE_CAP_INFO_CF_POLL_REQUEST)
56 .with_privacy(OVERRIDE_CAP_INFO_PRIVACY)
57 .with_spectrum_mgmt(OVERRIDE_CAP_INFO_SPECTRUM_MGMT)
58}
59
60pub fn derive_join_capabilities(
65 bss_channel: Channel,
66 bss_rates: &[SupportedRate],
67 device_info: &fidl_mlme::DeviceInfo,
68) -> Result<ClientCapabilities, Error> {
69 let band_cap = get_device_band_cap(&device_info, bss_channel.primary)
71 .ok_or_else(|| format_err!("iface does not support BSS channel {}", bss_channel.primary))?;
72
73 let capability_info =
77 override_capability_info(CapabilityInfo(device_info.softmac_hardware_capability as u16));
78
79 let client_rates = band_cap.basic_rates.iter().map(|&r| SupportedRate(r)).collect::<Vec<_>>();
82 let rates = intersect_rates(ApRates(bss_rates), ClientRates(&client_rates))
83 .map_err(|error| format_err!("could not intersect rates: {:?}", error))
84 .context(format!("deriving rates: {:?} + {:?}", band_cap.basic_rates, bss_rates))?;
85
86 let (ht_cap, vht_cap) =
89 override_ht_vht(band_cap.ht_cap.as_ref(), band_cap.vht_cap.as_ref(), bss_channel.cbw)?;
90
91 Ok(ClientCapabilities(StaCapabilities { capability_info, rates, ht_cap, vht_cap }))
92}
93
94fn override_ht_vht(
97 fidl_ht_cap: Option<&Box<fidl_ieee80211::HtCapabilities>>,
98 fidl_vht_cap: Option<&Box<fidl_ieee80211::VhtCapabilities>>,
99 cbw: Cbw,
100) -> Result<(Option<HtCapabilities>, Option<VhtCapabilities>), Error> {
101 if fidl_ht_cap.is_none() && fidl_vht_cap.is_some() {
102 return Err(format_err!("VHT Cap without HT Cap is invalid."));
103 }
104
105 let ht_cap = match fidl_ht_cap {
106 Some(h) => {
107 let ht_cap = *parse_ht_capabilities(&h.bytes[..]).context("verifying HT Cap")?;
108 Some(override_ht_capabilities(ht_cap, cbw))
109 }
110 None => None,
111 };
112
113 let vht_cap = match fidl_vht_cap {
114 Some(v) => {
115 let vht_cap = *parse_vht_capabilities(&v.bytes[..]).context("verifying VHT Cap")?;
116 Some(override_vht_capabilities(vht_cap, cbw))
117 }
118 None => None,
119 };
120 Ok((ht_cap, vht_cap))
121}
122
123fn override_ht_capabilities(mut ht_cap: HtCapabilities, cbw: Cbw) -> HtCapabilities {
126 let mut ht_cap_info = ht_cap.ht_cap_info.with_tx_stbc(OVERRIDE_HT_CAP_INFO_TX_STBC);
127 match cbw {
128 Cbw::Cbw20 => ht_cap_info.set_chan_width_set(ie::ChanWidthSet::TWENTY_ONLY),
129 _ => (),
130 }
131 ht_cap.ht_cap_info = ht_cap_info;
132 ht_cap
133}
134
135fn override_vht_capabilities(mut vht_cap: VhtCapabilities, cbw: Cbw) -> VhtCapabilities {
138 let mut vht_cap_info = vht_cap.vht_cap_info;
139 if vht_cap_info.supported_cbw_set() != OVERRIDE_VHT_CAP_INFO_SUPPORTED_CBW_SET {
140 match cbw {
145 Cbw::Cbw160 | Cbw::Cbw80P80 { secondary80: _ } => (),
146 _ => vht_cap_info.set_supported_cbw_set(OVERRIDE_VHT_CAP_INFO_SUPPORTED_CBW_SET),
147 }
148 }
149 vht_cap.vht_cap_info = vht_cap_info;
150 vht_cap
151}
152
153fn get_band(primary_channel: u8) -> fidl_ieee80211::WlanBand {
155 if primary_channel <= 14 {
156 fidl_ieee80211::WlanBand::TwoGhz
157 } else {
158 fidl_ieee80211::WlanBand::FiveGhz
159 }
160}
161
162pub fn get_device_band_cap(
163 device_info: &fidl_mlme::DeviceInfo,
164 channel: u8,
165) -> Option<&fidl_mlme::BandCapability> {
166 let target = get_band(channel);
167 device_info.bands.iter().find(|b| b.band == target)
168}
169
170#[derive(Debug, PartialEq)]
176pub struct StaCapabilities {
177 pub capability_info: CapabilityInfo,
178 pub rates: Vec<SupportedRate>,
179 pub ht_cap: Option<HtCapabilities>,
180 pub vht_cap: Option<VhtCapabilities>,
181}
182
183#[derive(Debug, PartialEq)]
184pub struct ClientCapabilities(pub StaCapabilities);
185#[derive(Debug, PartialEq)]
186pub struct ApCapabilities(pub StaCapabilities);
187
188pub fn intersect_with_ap_as_client(
190 client: &ClientCapabilities,
191 ap: &ApCapabilities,
192) -> Result<StaCapabilities, Error> {
193 let rates = intersect_rates(ApRates(&ap.0.rates[..]), ClientRates(&client.0.rates[..]))
194 .map_err(|e| format_err!("could not intersect rates: {:?}", e))?;
195 let (capability_info, ht_cap, vht_cap) = intersect(&client.0, &ap.0);
196 Ok(StaCapabilities { rates, capability_info, ht_cap, vht_cap })
197}
198
199pub fn intersect_with_remote_client_as_ap(
201 ap: &ApCapabilities,
202 remote_client: &ClientCapabilities,
203) -> StaCapabilities {
204 let rates = intersect_rates(ApRates(&ap.0.rates[..]), ClientRates(&remote_client.0.rates[..]))
206 .unwrap_or(vec![]);
207 let (capability_info, ht_cap, vht_cap) = intersect(&ap.0, &remote_client.0);
208 StaCapabilities { rates, capability_info, ht_cap, vht_cap }
209}
210
211fn intersect(
212 ours: &StaCapabilities,
213 theirs: &StaCapabilities,
214) -> (CapabilityInfo, Option<HtCapabilities>, Option<VhtCapabilities>) {
215 let capability_info = CapabilityInfo(ours.capability_info.raw() & theirs.capability_info.raw());
217 let ht_cap = match (ours.ht_cap, theirs.ht_cap) {
218 (Some(ours), Some(theirs)) => Some(ours.intersect(&theirs)),
220 _ => None,
221 };
222 let vht_cap = match (ours.vht_cap, theirs.vht_cap) {
223 (Some(ours), Some(theirs)) => Some(ours.intersect(&theirs)),
225 _ => None,
226 };
227 (capability_info, ht_cap, vht_cap)
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233 use crate::test_utils::fake_capabilities::fake_5ghz_band_capability_ht_cbw;
234 use crate::{assert_variant, mac};
235 use fidl_fuchsia_wlan_common as fidl_common;
236
237 #[test]
238 fn test_build_cap_info() {
239 let capability_info = CapabilityInfo(0)
240 .with_ess(!OVERRIDE_CAP_INFO_ESS)
241 .with_ibss(!OVERRIDE_CAP_INFO_IBSS)
242 .with_cf_pollable(!OVERRIDE_CAP_INFO_CF_POLLABLE)
243 .with_cf_poll_req(!OVERRIDE_CAP_INFO_CF_POLL_REQUEST)
244 .with_privacy(!OVERRIDE_CAP_INFO_PRIVACY)
245 .with_spectrum_mgmt(!OVERRIDE_CAP_INFO_SPECTRUM_MGMT);
246 let capability_info = override_capability_info(capability_info);
247 assert_eq!(capability_info.ess(), OVERRIDE_CAP_INFO_ESS);
248 assert_eq!(capability_info.ibss(), OVERRIDE_CAP_INFO_IBSS);
249 assert_eq!(capability_info.cf_pollable(), OVERRIDE_CAP_INFO_CF_POLLABLE);
250 assert_eq!(capability_info.cf_poll_req(), OVERRIDE_CAP_INFO_CF_POLL_REQUEST);
251 assert_eq!(capability_info.privacy(), OVERRIDE_CAP_INFO_PRIVACY);
252 assert_eq!(capability_info.spectrum_mgmt(), OVERRIDE_CAP_INFO_SPECTRUM_MGMT);
253 }
254
255 #[test]
256 fn test_override_ht_cap() {
257 let mut ht_cap = ie::fake_ht_capabilities();
258 let ht_cap_info = ht_cap
259 .ht_cap_info
260 .with_tx_stbc(!OVERRIDE_HT_CAP_INFO_TX_STBC)
261 .with_chan_width_set(ie::ChanWidthSet::TWENTY_FORTY);
262 ht_cap.ht_cap_info = ht_cap_info;
263 let mut channel = Channel { primary: 153, cbw: Cbw::Cbw20 };
264
265 let ht_cap_info = override_ht_capabilities(ht_cap, channel.cbw).ht_cap_info;
266 assert_eq!(ht_cap_info.tx_stbc(), OVERRIDE_HT_CAP_INFO_TX_STBC);
267 assert_eq!(ht_cap_info.chan_width_set(), ie::ChanWidthSet::TWENTY_ONLY);
268
269 channel.cbw = Cbw::Cbw40;
270 let ht_cap_info = override_ht_capabilities(ht_cap, channel.cbw).ht_cap_info;
271 assert_eq!(ht_cap_info.chan_width_set(), ie::ChanWidthSet::TWENTY_FORTY);
272 }
273
274 #[test]
275 fn test_override_vht_cap() {
276 let mut vht_cap = ie::fake_vht_capabilities();
277 let vht_cap_info = vht_cap.vht_cap_info.with_supported_cbw_set(2);
278 vht_cap.vht_cap_info = vht_cap_info;
279 let mut channel = Channel { primary: 153, cbw: Cbw::Cbw20 };
280
281 let vht_cap_info = override_vht_capabilities(vht_cap, channel.cbw).vht_cap_info;
284 assert_eq!(vht_cap_info.supported_cbw_set(), OVERRIDE_VHT_CAP_INFO_SUPPORTED_CBW_SET);
285
286 channel.cbw = Cbw::Cbw40;
287 let vht_cap_info = override_vht_capabilities(vht_cap, channel.cbw).vht_cap_info;
288 assert_eq!(vht_cap_info.supported_cbw_set(), OVERRIDE_VHT_CAP_INFO_SUPPORTED_CBW_SET);
289
290 channel.cbw = Cbw::Cbw80;
291 let vht_cap_info = override_vht_capabilities(vht_cap, channel.cbw).vht_cap_info;
292 assert_eq!(vht_cap_info.supported_cbw_set(), OVERRIDE_VHT_CAP_INFO_SUPPORTED_CBW_SET);
293
294 channel.cbw = Cbw::Cbw160;
297 let vht_cap_info = override_vht_capabilities(vht_cap, channel.cbw).vht_cap_info;
298 assert_eq!(vht_cap_info.supported_cbw_set(), 2);
299
300 channel.cbw = Cbw::Cbw80P80 { secondary80: 42 };
301 let vht_cap_info = override_vht_capabilities(vht_cap, channel.cbw).vht_cap_info;
302 assert_eq!(vht_cap_info.supported_cbw_set(), 2);
303 }
304
305 #[test]
306 fn band_id() {
307 assert_eq!(fidl_ieee80211::WlanBand::TwoGhz, get_band(1));
308 assert_eq!(fidl_ieee80211::WlanBand::TwoGhz, get_band(14));
309 assert_eq!(fidl_ieee80211::WlanBand::FiveGhz, get_band(36));
310 assert_eq!(fidl_ieee80211::WlanBand::FiveGhz, get_band(165));
311 }
312
313 #[test]
314 fn test_get_band() {
315 assert_eq!(fidl_ieee80211::WlanBand::TwoGhz, get_band(14));
316 assert_eq!(fidl_ieee80211::WlanBand::FiveGhz, get_band(36));
317 }
318
319 #[test]
320 fn test_get_device_band_cap() {
321 let device_info = fidl_mlme::DeviceInfo {
322 sta_addr: [0; 6],
323 role: fidl_common::WlanMacRole::Client,
324 bands: vec![fake_5ghz_band_capability_ht_cbw(ie::ChanWidthSet::TWENTY_FORTY)],
325 softmac_hardware_capability: 0,
326 qos_capable: true,
327 };
328 assert_eq!(
329 fidl_ieee80211::WlanBand::FiveGhz,
330 get_device_band_cap(&device_info, 36).unwrap().band
331 );
332 }
333
334 fn fake_client_join_cap() -> ClientCapabilities {
335 ClientCapabilities(StaCapabilities {
336 capability_info: mac::CapabilityInfo(0x1234),
337 rates: [101, 102, 103, 104].iter().cloned().map(SupportedRate).collect(),
338 ht_cap: Some(HtCapabilities {
339 ht_cap_info: ie::HtCapabilityInfo(0).with_rx_stbc(2).with_tx_stbc(false),
340 ..ie::fake_ht_capabilities()
341 }),
342 vht_cap: Some(ie::fake_vht_capabilities()),
343 })
344 }
345
346 fn fake_ap_join_cap() -> ApCapabilities {
347 ApCapabilities(StaCapabilities {
348 capability_info: mac::CapabilityInfo(0x4321),
349 rates: [101 + 128, 102, 9].iter().cloned().map(SupportedRate).collect(),
351 ht_cap: Some(HtCapabilities {
352 ht_cap_info: ie::HtCapabilityInfo(0).with_rx_stbc(1).with_tx_stbc(true),
353 ..ie::fake_ht_capabilities()
354 }),
355 vht_cap: Some(ie::fake_vht_capabilities()),
356 })
357 }
358
359 #[test]
360 fn client_intersect_with_ap() {
361 let caps = assert_variant!(
362 intersect_with_ap_as_client(&fake_client_join_cap(), &fake_ap_join_cap()),
363 Ok(caps) => caps
364 );
365 assert_eq!(
366 caps,
367 StaCapabilities {
368 capability_info: mac::CapabilityInfo(0x0220),
369 rates: [229, 102].iter().cloned().map(SupportedRate).collect(),
370 ht_cap: Some(HtCapabilities {
371 ht_cap_info: ie::HtCapabilityInfo(0).with_rx_stbc(2).with_tx_stbc(false),
372 ..ie::fake_ht_capabilities()
373 }),
374 ..fake_client_join_cap().0
375 }
376 )
377 }
378
379 #[test]
380 fn ap_intersect_with_remote_client() {
381 assert_eq!(
382 intersect_with_remote_client_as_ap(&fake_ap_join_cap(), &fake_client_join_cap()),
383 StaCapabilities {
384 capability_info: mac::CapabilityInfo(0x0220),
385 rates: [229, 102].iter().cloned().map(SupportedRate).collect(),
386 ht_cap: Some(HtCapabilities {
387 ht_cap_info: ie::HtCapabilityInfo(0).with_rx_stbc(0).with_tx_stbc(true),
388 ..ie::fake_ht_capabilities()
389 }),
390 ..fake_ap_join_cap().0
391 }
392 );
393 }
394}