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