1use crate::ie;
6use anyhow::format_err;
7use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
8use std::fmt;
9
10pub type MHz = u16;
17pub const BASE_FREQ_2GHZ: MHz = 2407;
18pub const BASE_FREQ_5GHZ: MHz = 5000;
19
20pub const INVALID_CHAN_IDX: u8 = 0;
21
22#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq)]
26pub enum Cbw {
27 Cbw20,
28 Cbw40, Cbw40Below,
30 Cbw80,
31 Cbw160,
32 Cbw80P80 { secondary80: u8 },
33}
34
35impl Cbw {
36 pub fn to_fidl(&self) -> (fidl_ieee80211::ChannelBandwidth, u8) {
38 match self {
39 Cbw::Cbw20 => (fidl_ieee80211::ChannelBandwidth::Cbw20, 0),
40 Cbw::Cbw40 => (fidl_ieee80211::ChannelBandwidth::Cbw40, 0),
41 Cbw::Cbw40Below => (fidl_ieee80211::ChannelBandwidth::Cbw40Below, 0),
42 Cbw::Cbw80 => (fidl_ieee80211::ChannelBandwidth::Cbw80, 0),
43 Cbw::Cbw160 => (fidl_ieee80211::ChannelBandwidth::Cbw160, 0),
44 Cbw::Cbw80P80 { secondary80 } => {
45 (fidl_ieee80211::ChannelBandwidth::Cbw80P80, *secondary80)
46 }
47 }
48 }
49
50 pub fn from_fidl(
51 fidl_cbw: fidl_ieee80211::ChannelBandwidth,
52 fidl_secondary80: u8,
53 ) -> Result<Self, anyhow::Error> {
54 match fidl_cbw {
55 fidl_ieee80211::ChannelBandwidth::Cbw20 => Ok(Cbw::Cbw20),
56 fidl_ieee80211::ChannelBandwidth::Cbw40 => Ok(Cbw::Cbw40),
57 fidl_ieee80211::ChannelBandwidth::Cbw40Below => Ok(Cbw::Cbw40Below),
58 fidl_ieee80211::ChannelBandwidth::Cbw80 => Ok(Cbw::Cbw80),
59 fidl_ieee80211::ChannelBandwidth::Cbw160 => Ok(Cbw::Cbw160),
60 fidl_ieee80211::ChannelBandwidth::Cbw80P80 => {
61 Ok(Cbw::Cbw80P80 { secondary80: fidl_secondary80 })
62 }
63 fidl_ieee80211::ChannelBandwidthUnknown!() => {
64 Err(format_err!("Unknown channel bandwidth from fidl: {:?}", fidl_cbw))
65 }
66 }
67 }
68}
69
70#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq)]
75pub struct Channel {
76 pub primary: u8,
78 pub cbw: Cbw,
79}
80
81impl fmt::Display for Cbw {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 match self {
85 Cbw::Cbw20 => write!(f, ""), Cbw::Cbw40 => write!(f, "+"), Cbw::Cbw40Below => write!(f, "-"), Cbw::Cbw80 => write!(f, "V"), Cbw::Cbw160 => write!(f, "W"), Cbw::Cbw80P80 { secondary80 } => write!(f, "+{}P", secondary80), }
92 }
93}
94
95impl fmt::Display for Channel {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 write!(f, "{}{}", self.primary, self.cbw)
98 }
99}
100
101impl Channel {
102 pub fn new(primary: u8, cbw: Cbw) -> Self {
103 Channel { primary, cbw }
104 }
105
106 fn is_primary_2ghz(&self) -> bool {
108 let p = self.primary;
109 p >= 1 && p <= 14
110 }
111
112 fn is_primary_5ghz(&self) -> bool {
114 let p = self.primary;
115 match p {
116 36..=64 => (p - 36) % 4 == 0,
117 100..=144 => (p - 100) % 4 == 0,
118 149..=165 => (p - 149) % 4 == 0,
119 _ => false,
120 }
121 }
122
123 fn get_band_start_freq(&self) -> Result<MHz, anyhow::Error> {
124 if self.is_primary_2ghz() {
125 Ok(BASE_FREQ_2GHZ)
126 } else if self.is_primary_5ghz() {
127 Ok(BASE_FREQ_5GHZ)
128 } else {
129 return Err(format_err!("cannot get band start freq for channel {}", self));
130 }
131 }
132
133 fn get_center_chan_idx(&self) -> Result<u8, anyhow::Error> {
136 if !(self.is_primary_2ghz() || self.is_primary_5ghz()) {
137 return Err(format_err!(
138 "cannot get center channel index for an invalid primary channel {}",
139 self
140 ));
141 }
142
143 let p = self.primary;
144 match self.cbw {
145 Cbw::Cbw20 => Ok(p),
146 Cbw::Cbw40 => Ok(p + 2),
147 Cbw::Cbw40Below => Ok(p - 2),
148 Cbw::Cbw80 | Cbw::Cbw80P80 { .. } => match p {
149 36..=48 => Ok(42),
150 52..=64 => Ok(58),
151 100..=112 => Ok(106),
152 116..=128 => Ok(122),
153 132..=144 => Ok(138),
154 148..=161_ => Ok(155),
155 _ => {
156 return Err(format_err!(
157 "cannot get center channel index for invalid channel {}",
158 self
159 ))
160 }
161 },
162 Cbw::Cbw160 => {
163 match p {
167 36..=64 => Ok(50),
168 100..=128 => Ok(114),
169 _ => {
170 return Err(format_err!(
171 "cannot get center channel index for invalid channel {}",
172 self
173 ))
174 }
175 }
176 }
177 }
178 }
179
180 pub fn get_center_freq(&self) -> Result<MHz, anyhow::Error> {
183 let start_freq = self.get_band_start_freq()?;
185 let center_chan_idx = self.get_center_chan_idx()?;
186 let spacing: MHz = 5;
187 Ok(start_freq + spacing * center_chan_idx as u16)
188 }
189
190 pub fn is_valid_in_us(&self) -> bool {
194 if self.is_primary_2ghz() {
195 self.is_valid_2ghz_in_us()
196 } else if self.is_primary_5ghz() {
197 self.is_valid_5ghz_in_us()
198 } else {
199 false
200 }
201 }
202
203 fn is_valid_2ghz_in_us(&self) -> bool {
204 if !self.is_primary_2ghz() {
205 return false;
206 }
207 let p = self.primary;
208 match self.cbw {
209 Cbw::Cbw20 => p <= 11,
210 Cbw::Cbw40 => p <= 7,
211 Cbw::Cbw40Below => p >= 5,
212 _ => false,
213 }
214 }
215
216 fn is_valid_5ghz_in_us(&self) -> bool {
217 if !self.is_primary_5ghz() {
218 return false;
219 }
220 let p = self.primary;
221 match self.cbw {
222 Cbw::Cbw20 => true,
223 Cbw::Cbw40 => p != 165 && (p % 8) == (if p <= 144 { 4 } else { 5 }),
224 Cbw::Cbw40Below => p != 165 && (p % 8) == (if p <= 144 { 0 } else { 1 }),
225 Cbw::Cbw80 => p != 165,
226 Cbw::Cbw160 => p < 132,
227 Cbw::Cbw80P80 { secondary80 } => {
228 if p == 165 {
229 return false;
230 }
231 let valid_secondary80: [u8; 6] = [42, 58, 106, 122, 138, 155];
232 if !valid_secondary80.contains(&secondary80) {
233 return false;
234 }
235 let ccfs0 = match self.get_center_chan_idx() {
236 Ok(v) => v,
237 Err(_) => return false,
238 };
239 let ccfs1 = secondary80;
240 let gap = (ccfs0 as i16 - ccfs1 as i16).abs();
241 gap > 16
242 }
243 }
244 }
245
246 pub fn is_2ghz(&self) -> bool {
248 self.is_primary_2ghz()
249 }
250
251 pub fn is_5ghz(&self) -> bool {
253 self.is_primary_5ghz()
254 }
255
256 #[allow(dead_code)]
258 fn is_unii1(&self) -> bool {
259 let p = self.primary;
260 p >= 32 && p <= 50
261 }
262
263 fn is_unii2a(&self) -> bool {
264 let p = self.primary;
265 p >= 50 && p <= 68
267 }
268
269 fn is_unii2c(&self) -> bool {
270 let p = self.primary;
271 p >= 96 && p <= 144
272 }
273
274 #[allow(dead_code)]
276 fn is_unii3(&self) -> bool {
277 let p = self.primary;
278 p >= 138 && p <= 165
280 }
281
282 pub fn is_dfs(&self) -> bool {
283 self.is_unii2a() || self.is_unii2c()
284 }
285}
286
287impl From<Channel> for fidl_ieee80211::WlanChannel {
288 fn from(channel: Channel) -> fidl_ieee80211::WlanChannel {
289 fidl_ieee80211::WlanChannel::from(&channel)
290 }
291}
292
293impl From<&Channel> for fidl_ieee80211::WlanChannel {
294 fn from(channel: &Channel) -> fidl_ieee80211::WlanChannel {
295 let (cbw, secondary80) = channel.cbw.to_fidl();
296 fidl_ieee80211::WlanChannel { primary: channel.primary, cbw, secondary80 }
297 }
298}
299
300impl TryFrom<fidl_ieee80211::WlanChannel> for Channel {
301 type Error = anyhow::Error;
302 fn try_from(fidl_channel: fidl_ieee80211::WlanChannel) -> Result<Channel, Self::Error> {
303 Channel::try_from(&fidl_channel)
304 }
305}
306
307impl TryFrom<&fidl_ieee80211::WlanChannel> for Channel {
308 type Error = anyhow::Error;
309
310 fn try_from(fidl_channel: &fidl_ieee80211::WlanChannel) -> Result<Channel, Self::Error> {
311 Ok(Channel {
312 primary: fidl_channel.primary,
313 cbw: Cbw::from_fidl(fidl_channel.cbw, fidl_channel.secondary80)?,
314 })
315 }
316}
317
318pub fn derive_channel(
325 rx_primary_channel: u8,
326 dsss_channel: Option<u8>,
327 ht_op: Option<ie::HtOperation>,
328 vht_op: Option<ie::VhtOperation>,
329) -> fidl_ieee80211::WlanChannel {
330 let primary = ht_op
331 .as_ref()
332 .map(|ht_op| ht_op.primary_channel)
333 .or(dsss_channel)
334 .unwrap_or(rx_primary_channel);
335
336 let ht_op_cbw = ht_op.map(|ht_op| ht_op.ht_op_info.sta_chan_width());
337 let vht_cbw_and_segs =
338 vht_op.map(|vht_op| (vht_op.vht_cbw, vht_op.center_freq_seg0, vht_op.center_freq_seg1));
339
340 let (cbw, secondary80) = match ht_op_cbw {
341 Some(ie::StaChanWidth::ANY) => {
343 let sec_chan_offset = ht_op.unwrap().ht_op_info.secondary_chan_offset();
345 derive_wide_channel_bandwidth(vht_cbw_and_segs, sec_chan_offset)
346 }
347 _ => Cbw::Cbw20,
349 }
350 .to_fidl();
351
352 fidl_ieee80211::WlanChannel { primary, cbw, secondary80 }
353}
354
355pub fn derive_wide_channel_bandwidth(
363 vht_cbw_and_segs: Option<(ie::VhtChannelBandwidth, u8, u8)>,
364 sec_chan_offset: ie::SecChanOffset,
365) -> Cbw {
366 use ie::VhtChannelBandwidth as Vcb;
367 match vht_cbw_and_segs {
368 Some((Vcb::CBW_80_160_80P80, _, 0)) => Cbw::Cbw80,
369 Some((Vcb::CBW_80_160_80P80, seg0, seg1)) if abs_sub(seg0, seg1) == 8 => Cbw::Cbw160,
370 Some((Vcb::CBW_80_160_80P80, seg0, seg1)) if abs_sub(seg0, seg1) > 16 => {
371 Cbw::Cbw80P80 { secondary80: seg1 }
373 }
374 _ => match sec_chan_offset {
379 ie::SecChanOffset::SECONDARY_ABOVE => Cbw::Cbw40,
380 ie::SecChanOffset::SECONDARY_BELOW => Cbw::Cbw40Below,
381 ie::SecChanOffset::SECONDARY_NONE | _ => Cbw::Cbw20,
382 },
383 }
384}
385
386fn abs_sub(v1: u8, v2: u8) -> u8 {
387 if v2 >= v1 {
388 v2 - v1
389 } else {
390 v1 - v2
391 }
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn fmt_display() {
400 let mut c = Channel::new(100, Cbw::Cbw40);
401 assert_eq!(format!("{}", c), "100+");
402 c.cbw = Cbw::Cbw160;
403 assert_eq!(format!("{}", c), "100W");
404 c.cbw = Cbw::Cbw80P80 { secondary80: 200 };
405 assert_eq!(format!("{}", c), "100+200P");
406 }
407
408 #[test]
409 fn test_is_primary_2ghz_or_5ghz() {
410 assert!(Channel::new(1, Cbw::Cbw160).is_primary_2ghz());
412 assert!(!Channel::new(1, Cbw::Cbw160).is_primary_5ghz());
413
414 assert!(Channel::new(12, Cbw::Cbw160).is_primary_2ghz());
415 assert!(!Channel::new(12, Cbw::Cbw160).is_primary_5ghz());
416
417 assert!(!Channel::new(36, Cbw::Cbw160).is_primary_2ghz());
418 assert!(Channel::new(36, Cbw::Cbw160).is_primary_5ghz());
419
420 assert!(!Channel::new(37, Cbw::Cbw160).is_primary_2ghz());
421 assert!(!Channel::new(37, Cbw::Cbw160).is_primary_5ghz());
422
423 assert!(!Channel::new(165, Cbw::Cbw160).is_primary_2ghz());
424 assert!(Channel::new(165, Cbw::Cbw160).is_primary_5ghz());
425
426 assert!(!Channel::new(166, Cbw::Cbw160).is_primary_2ghz());
427 assert!(!Channel::new(166, Cbw::Cbw160).is_primary_5ghz());
428 }
429
430 #[test]
431 fn test_band_start_freq() {
432 assert_eq!(BASE_FREQ_2GHZ, Channel::new(1, Cbw::Cbw20).get_band_start_freq().unwrap());
433 assert_eq!(BASE_FREQ_5GHZ, Channel::new(100, Cbw::Cbw20).get_band_start_freq().unwrap());
434 assert!(Channel::new(15, Cbw::Cbw20).get_band_start_freq().is_err());
435 assert!(Channel::new(200, Cbw::Cbw20).get_band_start_freq().is_err());
436 }
437
438 #[test]
439 fn test_get_center_chan_idx() {
440 assert!(Channel::new(1, Cbw::Cbw80).get_center_chan_idx().is_err());
441 assert_eq!(9, Channel::new(11, Cbw::Cbw40Below).get_center_chan_idx().unwrap());
442 assert_eq!(8, Channel::new(6, Cbw::Cbw40).get_center_chan_idx().unwrap());
443 assert_eq!(36, Channel::new(36, Cbw::Cbw20).get_center_chan_idx().unwrap());
444 assert_eq!(38, Channel::new(36, Cbw::Cbw40).get_center_chan_idx().unwrap());
445 assert_eq!(42, Channel::new(36, Cbw::Cbw80).get_center_chan_idx().unwrap());
446 assert_eq!(50, Channel::new(36, Cbw::Cbw160).get_center_chan_idx().unwrap());
447 assert_eq!(
448 42,
449 Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).get_center_chan_idx().unwrap()
450 );
451 }
452
453 #[test]
454 fn test_get_center_freq() {
455 assert_eq!(2412 as MHz, Channel::new(1, Cbw::Cbw20).get_center_freq().unwrap());
456 assert_eq!(2437 as MHz, Channel::new(6, Cbw::Cbw20).get_center_freq().unwrap());
457 assert_eq!(2447 as MHz, Channel::new(6, Cbw::Cbw40).get_center_freq().unwrap());
458 assert_eq!(2427 as MHz, Channel::new(6, Cbw::Cbw40Below).get_center_freq().unwrap());
459 assert_eq!(5180 as MHz, Channel::new(36, Cbw::Cbw20).get_center_freq().unwrap());
460 assert_eq!(5190 as MHz, Channel::new(36, Cbw::Cbw40).get_center_freq().unwrap());
461 assert_eq!(5210 as MHz, Channel::new(36, Cbw::Cbw80).get_center_freq().unwrap());
462 assert_eq!(5250 as MHz, Channel::new(36, Cbw::Cbw160).get_center_freq().unwrap());
463 assert_eq!(
464 5210 as MHz,
465 Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).get_center_freq().unwrap()
466 );
467 }
468
469 #[test]
470 fn test_valid_us_combo() {
471 assert!(Channel::new(1, Cbw::Cbw20).is_valid_in_us());
472 assert!(Channel::new(1, Cbw::Cbw40).is_valid_in_us());
473 assert!(Channel::new(5, Cbw::Cbw40Below).is_valid_in_us());
474 assert!(Channel::new(6, Cbw::Cbw20).is_valid_in_us());
475 assert!(Channel::new(6, Cbw::Cbw40).is_valid_in_us());
476 assert!(Channel::new(6, Cbw::Cbw40Below).is_valid_in_us());
477 assert!(Channel::new(7, Cbw::Cbw40).is_valid_in_us());
478 assert!(Channel::new(11, Cbw::Cbw20).is_valid_in_us());
479 assert!(Channel::new(11, Cbw::Cbw40Below).is_valid_in_us());
480
481 assert!(Channel::new(36, Cbw::Cbw20).is_valid_in_us());
482 assert!(Channel::new(36, Cbw::Cbw40).is_valid_in_us());
483 assert!(Channel::new(36, Cbw::Cbw160).is_valid_in_us());
484 assert!(Channel::new(40, Cbw::Cbw20).is_valid_in_us());
485 assert!(Channel::new(40, Cbw::Cbw40Below).is_valid_in_us());
486 assert!(Channel::new(40, Cbw::Cbw160).is_valid_in_us());
487 assert!(Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).is_valid_in_us());
488 assert!(Channel::new(40, Cbw::Cbw80P80 { secondary80: 155 }).is_valid_in_us());
489 assert!(Channel::new(161, Cbw::Cbw80P80 { secondary80: 42 }).is_valid_in_us());
490 }
491
492 #[test]
493 fn test_invalid_us_combo() {
494 assert!(!Channel::new(1, Cbw::Cbw40Below).is_valid_in_us());
495 assert!(!Channel::new(4, Cbw::Cbw40Below).is_valid_in_us());
496 assert!(!Channel::new(8, Cbw::Cbw40).is_valid_in_us());
497 assert!(!Channel::new(11, Cbw::Cbw40).is_valid_in_us());
498 assert!(!Channel::new(6, Cbw::Cbw80).is_valid_in_us());
499 assert!(!Channel::new(6, Cbw::Cbw160).is_valid_in_us());
500 assert!(!Channel::new(6, Cbw::Cbw80P80 { secondary80: 155 }).is_valid_in_us());
501
502 assert!(!Channel::new(36, Cbw::Cbw40Below).is_valid_in_us());
503 assert!(!Channel::new(36, Cbw::Cbw80P80 { secondary80: 58 }).is_valid_in_us());
504 assert!(!Channel::new(40, Cbw::Cbw40).is_valid_in_us());
505 assert!(!Channel::new(40, Cbw::Cbw80P80 { secondary80: 42 }).is_valid_in_us());
506
507 assert!(!Channel::new(165, Cbw::Cbw80).is_valid_in_us());
508 assert!(!Channel::new(165, Cbw::Cbw80P80 { secondary80: 42 }).is_valid_in_us());
509 }
510
511 #[test]
512 fn test_is_2ghz_or_5ghz() {
513 assert!(Channel::new(1, Cbw::Cbw20).is_2ghz());
514 assert!(!Channel::new(1, Cbw::Cbw20).is_5ghz());
515 assert!(Channel::new(13, Cbw::Cbw20).is_2ghz());
516 assert!(!Channel::new(13, Cbw::Cbw20).is_5ghz());
517 assert!(Channel::new(36, Cbw::Cbw20).is_5ghz());
518 assert!(!Channel::new(36, Cbw::Cbw20).is_2ghz());
519 }
520
521 #[test]
522 fn test_is_dfs() {
523 assert!(!Channel::new(1, Cbw::Cbw20).is_dfs());
524 assert!(!Channel::new(36, Cbw::Cbw20).is_dfs());
525 assert!(Channel::new(50, Cbw::Cbw20).is_dfs());
526 assert!(Channel::new(144, Cbw::Cbw20).is_dfs());
527 assert!(!Channel::new(149, Cbw::Cbw20).is_dfs());
528 }
529
530 #[test]
531 fn test_convert_fidl_channel() {
532 let mut f = fidl_ieee80211::WlanChannel::from(Channel::new(1, Cbw::Cbw20));
533 assert!(
534 f.primary == 1
535 && f.cbw == fidl_ieee80211::ChannelBandwidth::Cbw20
536 && f.secondary80 == 0
537 );
538
539 f = Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).into();
540 assert!(
541 f.primary == 36
542 && f.cbw == fidl_ieee80211::ChannelBandwidth::Cbw80P80
543 && f.secondary80 == 155
544 );
545
546 let mut c = Channel::try_from(fidl_ieee80211::WlanChannel {
547 primary: 11,
548 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40Below,
549 secondary80: 123,
550 })
551 .unwrap();
552 assert!(c.primary == 11 && c.cbw == Cbw::Cbw40Below);
553 c = fidl_ieee80211::WlanChannel {
554 primary: 149,
555 cbw: fidl_ieee80211::ChannelBandwidth::Cbw80P80,
556 secondary80: 42,
557 }
558 .try_into()
559 .unwrap();
560 assert!(c.primary == 149 && c.cbw == Cbw::Cbw80P80 { secondary80: 42 });
561
562 let r = Channel::try_from(fidl_ieee80211::WlanChannel {
563 primary: 11,
564 cbw: fidl_ieee80211::ChannelBandwidth::unknown(),
565 secondary80: 123,
566 });
567 assert!(r.is_err());
568 }
569
570 const RX_PRIMARY_CHAN: u8 = 11;
571 const HT_PRIMARY_CHAN: u8 = 48;
572
573 #[test]
574 fn test_derive_channel_basic() {
575 let channel = derive_channel(RX_PRIMARY_CHAN, None, None, None);
576 assert_eq!(
577 channel,
578 fidl_ieee80211::WlanChannel {
579 primary: RX_PRIMARY_CHAN,
580 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
581 secondary80: 0,
582 }
583 );
584 }
585
586 #[test]
587 fn test_derive_channel_with_dsss_param() {
588 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), None, None);
589 assert_eq!(
590 channel,
591 fidl_ieee80211::WlanChannel {
592 primary: 6,
593 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
594 secondary80: 0
595 }
596 );
597 }
598
599 #[test]
600 fn test_derive_channel_with_ht_20mhz() {
601 let expected_channel = fidl_ieee80211::WlanChannel {
602 primary: HT_PRIMARY_CHAN,
603 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
604 secondary80: 0,
605 };
606
607 let test_params = [
608 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_NONE),
609 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_ABOVE),
610 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_BELOW),
611 (ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_NONE),
612 ];
613
614 for (ht_width, sec_chan_offset) in test_params.iter() {
615 let ht_op = ht_op(HT_PRIMARY_CHAN, *ht_width, *sec_chan_offset);
616 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), None);
617 assert_eq!(channel, expected_channel);
618 }
619 }
620
621 #[test]
622 fn test_derive_channel_with_ht_40mhz() {
623 let ht_op =
624 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
625 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), None);
626 assert_eq!(
627 channel,
628 fidl_ieee80211::WlanChannel {
629 primary: HT_PRIMARY_CHAN,
630 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40,
631 secondary80: 0,
632 }
633 );
634 }
635
636 #[test]
637 fn test_derive_channel_with_ht_40mhz_below() {
638 let ht_op =
639 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_BELOW);
640 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), None);
641 assert_eq!(
642 channel,
643 fidl_ieee80211::WlanChannel {
644 primary: HT_PRIMARY_CHAN,
645 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40Below,
646 secondary80: 0,
647 }
648 );
649 }
650
651 #[test]
652 fn test_derive_channel_with_vht_80mhz() {
653 let ht_op =
654 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
655 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 8, 0);
656 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), Some(vht_op));
657 assert_eq!(
658 channel,
659 fidl_ieee80211::WlanChannel {
660 primary: HT_PRIMARY_CHAN,
661 cbw: fidl_ieee80211::ChannelBandwidth::Cbw80,
662 secondary80: 0,
663 }
664 );
665 }
666
667 #[test]
668 fn test_derive_channel_with_vht_160mhz() {
669 let ht_op =
670 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
671 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 0, 8);
672 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), Some(vht_op));
673 assert_eq!(
674 channel,
675 fidl_ieee80211::WlanChannel {
676 primary: HT_PRIMARY_CHAN,
677 cbw: fidl_ieee80211::ChannelBandwidth::Cbw160,
678 secondary80: 0,
679 }
680 );
681 }
682
683 #[test]
684 fn test_derive_channel_with_vht_80plus80mhz() {
685 let ht_op =
686 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
687 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 18, 1);
688 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), Some(vht_op));
689 assert_eq!(
690 channel,
691 fidl_ieee80211::WlanChannel {
692 primary: HT_PRIMARY_CHAN,
693 cbw: fidl_ieee80211::ChannelBandwidth::Cbw80P80,
694 secondary80: 1,
695 }
696 );
697 }
698
699 #[test]
700 fn test_derive_channel_none() {
701 let channel = derive_channel(8, None, None, None);
702 assert_eq!(
703 channel,
704 fidl_ieee80211::WlanChannel {
705 primary: 8,
706 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
707 secondary80: 0,
708 }
709 );
710 }
711
712 #[test]
713 fn test_derive_channel_no_rx_primary() {
714 let channel = derive_channel(8, Some(6), None, None);
715 assert_eq!(
716 channel,
717 fidl_ieee80211::WlanChannel {
718 primary: 6,
719 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
720 secondary80: 0,
721 }
722 )
723 }
724
725 fn ht_op(
726 primary_channel: u8,
727 chan_width: ie::StaChanWidth,
728 offset: ie::SecChanOffset,
729 ) -> ie::HtOperation {
730 let ht_op_info =
731 ie::HtOpInfo::new().with_sta_chan_width(chan_width).with_secondary_chan_offset(offset);
732 ie::HtOperation { primary_channel, ht_op_info, basic_ht_mcs_set: ie::SupportedMcsSet(0) }
733 }
734
735 fn vht_op(vht_cbw: ie::VhtChannelBandwidth, seg0: u8, seg1: u8) -> ie::VhtOperation {
736 ie::VhtOperation {
737 vht_cbw,
738 center_freq_seg0: seg0,
739 center_freq_seg1: seg1,
740 basic_mcs_nss: ie::VhtMcsNssMap(0),
741 }
742 }
743}