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,
77 pub cbw: Cbw,
78 pub band: fidl_ieee80211::WlanBand,
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, self.band)
98 }
99}
100
101impl Channel {
102 pub const fn new(primary: u8, cbw: Cbw, band: fidl_ieee80211::WlanBand) -> Self {
103 Channel { primary, cbw, band }
104 }
105
106 fn is_primary_2ghz(&self) -> bool {
107 self.band == fidl_ieee80211::WlanBand::TwoGhz
108 }
109
110 fn is_primary_5ghz(&self) -> bool {
111 if self.band != fidl_ieee80211::WlanBand::FiveGhz {
112 return false;
113 }
114
115 let p = self.primary;
116 match p {
117 36..=64 => (p - 36) % 4 == 0,
118 100..=144 => (p - 100) % 4 == 0,
119 149..=165 => (p - 149) % 4 == 0,
120 _ => false,
121 }
122 }
123
124 pub fn get_band(&self) -> Result<fidl_ieee80211::WlanBand, anyhow::Error> {
125 Ok(self.band)
126 }
127
128 fn get_band_start_freq(&self) -> Result<MHz, anyhow::Error> {
129 match self.band {
130 fidl_ieee80211::WlanBand::TwoGhz => Ok(BASE_FREQ_2GHZ),
131 fidl_ieee80211::WlanBand::FiveGhz => Ok(BASE_FREQ_5GHZ),
132 _ => Err(format_err!("cannot get band start freq for channel {}", self)),
133 }
134 }
135
136 fn get_center_chan_idx(&self) -> Result<u8, anyhow::Error> {
137 let is_valid = match self.band {
138 fidl_ieee80211::WlanBand::TwoGhz => self.primary <= 14,
139 fidl_ieee80211::WlanBand::FiveGhz => (36..=165).contains(&self.primary),
140 _ => false,
141 };
142 if !is_valid {
143 return Err(format_err!(
144 "cannot get center channel index for an invalid primary channel {}",
145 self
146 ));
147 }
148
149 let p = self.primary;
150 match self.cbw {
151 Cbw::Cbw20 => Ok(p),
152 Cbw::Cbw40 => Ok(p + 2),
153 Cbw::Cbw40Below => Ok(p - 2),
154 Cbw::Cbw80 | Cbw::Cbw80P80 { .. } => match p {
155 36..=48 => Ok(42),
156 52..=64 => Ok(58),
157 100..=112 => Ok(106),
158 116..=128 => Ok(122),
159 132..=144 => Ok(138),
160 148..=161_ => Ok(155),
161 _ => {
162 return Err(format_err!(
163 "cannot get center channel index for invalid channel {}",
164 self
165 ));
166 }
167 },
168 Cbw::Cbw160 => {
169 match p {
173 36..=64 => Ok(50),
174 100..=128 => Ok(114),
175 _ => {
176 return Err(format_err!(
177 "cannot get center channel index for invalid channel {}",
178 self
179 ));
180 }
181 }
182 }
183 }
184 }
185
186 pub fn get_center_freq(&self) -> Result<MHz, anyhow::Error> {
189 let start_freq = self.get_band_start_freq()?;
191 let center_chan_idx = self.get_center_chan_idx()?;
192 let spacing: MHz = 5;
193 Ok(start_freq + spacing * center_chan_idx as u16)
194 }
195
196 pub fn is_valid_in_us(&self) -> bool {
200 match self.band {
201 fidl_ieee80211::WlanBand::TwoGhz => self.is_valid_2ghz_in_us(),
202 fidl_ieee80211::WlanBand::FiveGhz => self.is_valid_5ghz_in_us(),
203 _ => false,
204 }
205 }
206
207 fn is_valid_2ghz_in_us(&self) -> bool {
208 if !self.is_primary_2ghz() {
209 return false;
210 }
211 let p = self.primary;
212 match self.cbw {
213 Cbw::Cbw20 => p <= 11,
214 Cbw::Cbw40 => p <= 7,
215 Cbw::Cbw40Below => p >= 5,
216 _ => false,
217 }
218 }
219
220 fn is_valid_5ghz_in_us(&self) -> bool {
221 if !self.is_primary_5ghz() {
222 return false;
223 }
224 let p = self.primary;
225 match self.cbw {
226 Cbw::Cbw20 => true,
227 Cbw::Cbw40 => p != 165 && (p % 8) == (if p <= 144 { 4 } else { 5 }),
228 Cbw::Cbw40Below => p != 165 && (p % 8) == (if p <= 144 { 0 } else { 1 }),
229 Cbw::Cbw80 => p != 165,
230 Cbw::Cbw160 => p < 132,
231 Cbw::Cbw80P80 { secondary80 } => {
232 if p == 165 {
233 return false;
234 }
235 let valid_secondary80: [u8; 6] = [42, 58, 106, 122, 138, 155];
236 if !valid_secondary80.contains(&secondary80) {
237 return false;
238 }
239 let ccfs0 = match self.get_center_chan_idx() {
240 Ok(v) => v,
241 Err(_) => return false,
242 };
243 let ccfs1 = secondary80;
244 let gap = (ccfs0 as i16 - ccfs1 as i16).abs();
245 gap > 16
246 }
247 }
248 }
249
250 pub fn is_2ghz(&self) -> bool {
252 self.is_primary_2ghz()
253 }
254
255 pub fn is_5ghz(&self) -> bool {
257 self.is_primary_5ghz()
258 }
259}
260
261impl Into<fidl_ieee80211::ChannelNumber> for Channel {
262 fn into(self) -> fidl_ieee80211::ChannelNumber {
263 fidl_ieee80211::ChannelNumber { band: self.band, number: self.primary }
264 }
265}
266impl Channel {
267 pub fn from_fidl(
268 fidl_channel: fidl_ieee80211::ChannelNumber,
269 fidl_cbw: fidl_ieee80211::ChannelBandwidth,
270 fidl_secondary80: fidl_ieee80211::ChannelNumber,
271 ) -> Result<Self, anyhow::Error> {
272 if fidl_cbw == fidl_ieee80211::ChannelBandwidth::Cbw80P80 {
273 if fidl_secondary80.band != fidl_channel.band {
274 return Err(format_err!(
275 "secondary80 band ({:?}) does not match primary band ({:?})",
276 fidl_secondary80.band,
277 fidl_channel.band
278 ));
279 }
280 }
281 let cbw = Cbw::from_fidl(fidl_cbw, fidl_secondary80.number)?;
282 Ok(Channel::new(fidl_channel.number, cbw, fidl_channel.band))
283 }
284}
285
286pub fn derive_channel(
293 rx_primary_channel: fidl_ieee80211::ChannelNumber,
294 dsss_channel: Option<u8>,
295 ht_op: Option<ie::HtOperation>,
296 vht_op: Option<ie::VhtOperation>,
297) -> Channel {
298 let primary = ht_op
299 .as_ref()
300 .map(|ht_op| ht_op.primary_channel)
301 .or(dsss_channel)
302 .unwrap_or(rx_primary_channel.number);
303
304 let ht_op_cbw = ht_op.map(|ht_op| ht_op.ht_op_info.sta_chan_width());
305 let vht_cbw_and_segs =
306 vht_op.map(|vht_op| (vht_op.vht_cbw, vht_op.center_freq_seg0, vht_op.center_freq_seg1));
307
308 let cbw = match ht_op_cbw {
309 Some(ie::StaChanWidth::ANY) => {
311 let sec_chan_offset = ht_op.unwrap().ht_op_info.secondary_chan_offset();
313 derive_wide_channel_bandwidth(vht_cbw_and_segs, sec_chan_offset)
314 }
315 _ => Cbw::Cbw20,
317 };
318
319 Channel::new(primary, cbw, rx_primary_channel.band)
320}
321
322pub fn derive_wide_channel_bandwidth(
330 vht_cbw_and_segs: Option<(ie::VhtChannelBandwidth, u8, u8)>,
331 sec_chan_offset: ie::SecChanOffset,
332) -> Cbw {
333 use ie::VhtChannelBandwidth as Vcb;
334 match vht_cbw_and_segs {
335 Some((Vcb::CBW_80_160_80P80, _, 0)) => Cbw::Cbw80,
336 Some((Vcb::CBW_80_160_80P80, seg0, seg1)) if abs_sub(seg0, seg1) == 8 => Cbw::Cbw160,
337 Some((Vcb::CBW_80_160_80P80, seg0, seg1)) if abs_sub(seg0, seg1) > 16 => {
338 Cbw::Cbw80P80 { secondary80: seg1 }
340 }
341 _ => match sec_chan_offset {
345 ie::SecChanOffset::SECONDARY_ABOVE => Cbw::Cbw40,
346 ie::SecChanOffset::SECONDARY_BELOW => Cbw::Cbw40Below,
347 ie::SecChanOffset::SECONDARY_NONE | _ => Cbw::Cbw20,
348 },
349 }
350}
351
352fn abs_sub(v1: u8, v2: u8) -> u8 {
353 if v2 >= v1 { v2 - v1 } else { v1 - v2 }
354}
355
356pub fn primary_channel_from_freq(freq: u32) -> Option<u8> {
360 if (2412..=2472).contains(&freq) && (freq - 2412) % 5 == 0 {
362 Some(((freq - 2407) / 5) as u8)
363 } else if freq == 2484 {
365 Some(14)
366 } else if (5180..=5720).contains(&freq) && (freq - 5180) % 20 == 0 {
368 Some(((freq - 5000) / 5) as u8)
369 } else if (5745..=5865).contains(&freq) && (freq - 5745) % 20 == 0 {
371 Some(((freq - 5000) / 5) as u8)
372 } else {
373 None
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use super::*;
380 use fidl_ieee80211::WlanBand::{FiveGhz, TwoGhz};
381
382 fn rx_channel(number: u8, band: fidl_ieee80211::WlanBand) -> fidl_ieee80211::ChannelNumber {
383 fidl_ieee80211::ChannelNumber { band, number }
384 }
385
386 #[test]
387 fn fmt_display() {
388 let mut c = Channel::new(100, Cbw::Cbw40, FiveGhz);
389 assert_eq!(format!("{}", c), "100+ (FiveGhz)");
390 c.cbw = Cbw::Cbw160;
391 assert_eq!(format!("{}", c), "100W (FiveGhz)");
392 c.cbw = Cbw::Cbw80P80 { secondary80: 200 };
393 assert_eq!(format!("{}", c), "100+200P (FiveGhz)");
394 }
395
396 #[test]
397 fn test_is_primary_2ghz_or_5ghz() {
398 assert!(Channel::new(1, Cbw::Cbw160, TwoGhz).is_primary_2ghz());
400 assert!(!Channel::new(1, Cbw::Cbw160, TwoGhz).is_primary_5ghz());
401
402 assert!(Channel::new(12, Cbw::Cbw160, TwoGhz).is_primary_2ghz());
403 assert!(!Channel::new(12, Cbw::Cbw160, TwoGhz).is_primary_5ghz());
404
405 assert!(!Channel::new(36, Cbw::Cbw160, FiveGhz).is_primary_2ghz());
406 assert!(Channel::new(36, Cbw::Cbw160, FiveGhz).is_primary_5ghz());
407
408 assert!(!Channel::new(37, Cbw::Cbw160, FiveGhz).is_primary_2ghz());
409 assert!(!Channel::new(37, Cbw::Cbw160, FiveGhz).is_primary_5ghz());
410
411 assert!(!Channel::new(165, Cbw::Cbw160, FiveGhz).is_primary_2ghz());
412 assert!(Channel::new(165, Cbw::Cbw160, FiveGhz).is_primary_5ghz());
413
414 assert!(!Channel::new(166, Cbw::Cbw160, FiveGhz).is_primary_2ghz());
415 assert!(!Channel::new(166, Cbw::Cbw160, FiveGhz).is_primary_5ghz());
416 }
417
418 #[test]
419 fn test_get_band() {
420 assert_eq!(
421 fidl_ieee80211::WlanBand::TwoGhz,
422 Channel::new(1, Cbw::Cbw20, TwoGhz).get_band().unwrap()
423 );
424 assert_eq!(
425 fidl_ieee80211::WlanBand::TwoGhz,
426 Channel::new(14, Cbw::Cbw40, TwoGhz).get_band().unwrap()
427 );
428 assert_eq!(
429 fidl_ieee80211::WlanBand::FiveGhz,
430 Channel::new(36, Cbw::Cbw80, FiveGhz).get_band().unwrap()
431 );
432 assert_eq!(
433 fidl_ieee80211::WlanBand::FiveGhz,
434 Channel::new(165, Cbw::Cbw160, FiveGhz).get_band().unwrap()
435 );
436 }
437
438 #[test]
439 fn test_band_start_freq() {
440 assert_eq!(
441 BASE_FREQ_2GHZ,
442 Channel::new(1, Cbw::Cbw20, TwoGhz).get_band_start_freq().unwrap()
443 );
444 assert_eq!(
445 BASE_FREQ_5GHZ,
446 Channel::new(100, Cbw::Cbw20, FiveGhz).get_band_start_freq().unwrap()
447 );
448 }
449
450 #[test]
451 fn test_get_center_chan_idx() {
452 assert!(Channel::new(1, Cbw::Cbw80, TwoGhz).get_center_chan_idx().is_err());
453 assert_eq!(9, Channel::new(11, Cbw::Cbw40Below, TwoGhz).get_center_chan_idx().unwrap());
454 assert_eq!(8, Channel::new(6, Cbw::Cbw40, TwoGhz).get_center_chan_idx().unwrap());
455 assert_eq!(36, Channel::new(36, Cbw::Cbw20, FiveGhz).get_center_chan_idx().unwrap());
456 assert_eq!(38, Channel::new(36, Cbw::Cbw40, FiveGhz).get_center_chan_idx().unwrap());
457 assert_eq!(42, Channel::new(36, Cbw::Cbw80, FiveGhz).get_center_chan_idx().unwrap());
458 assert_eq!(50, Channel::new(36, Cbw::Cbw160, FiveGhz).get_center_chan_idx().unwrap());
459 assert_eq!(
460 42,
461 Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }, FiveGhz)
462 .get_center_chan_idx()
463 .unwrap()
464 );
465 }
466
467 #[test]
468 fn test_get_center_freq() {
469 assert_eq!(2412 as MHz, Channel::new(1, Cbw::Cbw20, TwoGhz).get_center_freq().unwrap());
470 assert_eq!(2437 as MHz, Channel::new(6, Cbw::Cbw20, TwoGhz).get_center_freq().unwrap());
471 assert_eq!(2447 as MHz, Channel::new(6, Cbw::Cbw40, TwoGhz).get_center_freq().unwrap());
472 assert_eq!(
473 2427 as MHz,
474 Channel::new(6, Cbw::Cbw40Below, TwoGhz).get_center_freq().unwrap()
475 );
476 assert_eq!(5180 as MHz, Channel::new(36, Cbw::Cbw20, FiveGhz).get_center_freq().unwrap());
477 assert_eq!(5190 as MHz, Channel::new(36, Cbw::Cbw40, FiveGhz).get_center_freq().unwrap());
478 assert_eq!(5210 as MHz, Channel::new(36, Cbw::Cbw80, FiveGhz).get_center_freq().unwrap());
479 assert_eq!(5250 as MHz, Channel::new(36, Cbw::Cbw160, FiveGhz).get_center_freq().unwrap());
480 assert_eq!(
481 5210 as MHz,
482 Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }, FiveGhz)
483 .get_center_freq()
484 .unwrap()
485 );
486 }
487
488 #[test]
489 fn test_primarychannel_from_freq() {
490 assert_eq!(Some(1), primary_channel_from_freq(2412));
491 assert_eq!(None, primary_channel_from_freq(2413));
493 assert_eq!(Some(6), primary_channel_from_freq(2437));
494 assert_eq!(Some(13), primary_channel_from_freq(2472));
495 assert_eq!(Some(14), primary_channel_from_freq(2484));
496 assert_eq!(None, primary_channel_from_freq(5160));
498 assert_eq!(Some(36), primary_channel_from_freq(5180));
499 assert_eq!(None, primary_channel_from_freq(5190));
501 assert_eq!(Some(165), primary_channel_from_freq(5825));
502 assert_eq!(Some(173), primary_channel_from_freq(5865));
503 assert_eq!(None, primary_channel_from_freq(2400));
505 assert_eq!(None, primary_channel_from_freq(5000));
507 assert_eq!(None, primary_channel_from_freq(5885));
509 }
510
511 #[test]
512 fn test_valid_us_combo() {
513 assert!(Channel::new(1, Cbw::Cbw20, TwoGhz).is_valid_in_us());
514 assert!(Channel::new(1, Cbw::Cbw40, TwoGhz).is_valid_in_us());
515 assert!(Channel::new(5, Cbw::Cbw40Below, TwoGhz).is_valid_in_us());
516 assert!(Channel::new(6, Cbw::Cbw20, TwoGhz).is_valid_in_us());
517 assert!(Channel::new(6, Cbw::Cbw40, TwoGhz).is_valid_in_us());
518 assert!(Channel::new(6, Cbw::Cbw40Below, TwoGhz).is_valid_in_us());
519 assert!(Channel::new(7, Cbw::Cbw40, TwoGhz).is_valid_in_us());
520 assert!(Channel::new(11, Cbw::Cbw20, TwoGhz).is_valid_in_us());
521 assert!(Channel::new(11, Cbw::Cbw40Below, TwoGhz).is_valid_in_us());
522
523 assert!(Channel::new(36, Cbw::Cbw20, FiveGhz).is_valid_in_us());
524 assert!(Channel::new(36, Cbw::Cbw40, FiveGhz).is_valid_in_us());
525 assert!(Channel::new(36, Cbw::Cbw160, FiveGhz).is_valid_in_us());
526 assert!(Channel::new(40, Cbw::Cbw20, FiveGhz).is_valid_in_us());
527 assert!(Channel::new(40, Cbw::Cbw40Below, FiveGhz).is_valid_in_us());
528 assert!(Channel::new(40, Cbw::Cbw160, FiveGhz).is_valid_in_us());
529 assert!(Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }, FiveGhz).is_valid_in_us());
530 assert!(Channel::new(40, Cbw::Cbw80P80 { secondary80: 155 }, FiveGhz).is_valid_in_us());
531 assert!(Channel::new(161, Cbw::Cbw80P80 { secondary80: 42 }, FiveGhz).is_valid_in_us());
532 }
533
534 #[test]
535 fn test_invalid_us_combo() {
536 assert!(!Channel::new(1, Cbw::Cbw40Below, TwoGhz).is_valid_in_us());
537 assert!(!Channel::new(4, Cbw::Cbw40Below, TwoGhz).is_valid_in_us());
538 assert!(!Channel::new(8, Cbw::Cbw40, TwoGhz).is_valid_in_us());
539 assert!(!Channel::new(11, Cbw::Cbw40, TwoGhz).is_valid_in_us());
540 assert!(!Channel::new(6, Cbw::Cbw80, TwoGhz).is_valid_in_us());
541 assert!(!Channel::new(6, Cbw::Cbw160, TwoGhz).is_valid_in_us());
542 assert!(!Channel::new(6, Cbw::Cbw80P80 { secondary80: 155 }, TwoGhz).is_valid_in_us());
543
544 assert!(!Channel::new(36, Cbw::Cbw40Below, FiveGhz).is_valid_in_us());
545 assert!(!Channel::new(36, Cbw::Cbw80P80 { secondary80: 58 }, FiveGhz).is_valid_in_us());
546 assert!(!Channel::new(40, Cbw::Cbw40, FiveGhz).is_valid_in_us());
547 assert!(!Channel::new(40, Cbw::Cbw80P80 { secondary80: 42 }, FiveGhz).is_valid_in_us());
548
549 assert!(!Channel::new(165, Cbw::Cbw80, FiveGhz).is_valid_in_us());
550 assert!(!Channel::new(165, Cbw::Cbw80P80 { secondary80: 42 }, FiveGhz).is_valid_in_us());
551 }
552
553 #[test]
554 fn test_is_2ghz_or_5ghz() {
555 assert!(Channel::new(1, Cbw::Cbw20, TwoGhz).is_2ghz());
556 assert!(!Channel::new(1, Cbw::Cbw20, TwoGhz).is_5ghz());
557 assert!(Channel::new(13, Cbw::Cbw20, TwoGhz).is_2ghz());
558 assert!(!Channel::new(13, Cbw::Cbw20, TwoGhz).is_5ghz());
559 assert!(Channel::new(36, Cbw::Cbw20, FiveGhz).is_5ghz());
560 assert!(!Channel::new(36, Cbw::Cbw20, FiveGhz).is_2ghz());
561 }
562
563 const RX_PRIMARY_CHAN: u8 = 11;
564 const RX_PRIMARY_CHAN_5GHZ: u8 = 36;
565 const HT_PRIMARY_CHAN: u8 = 48;
566
567 #[test]
568 fn test_derive_channel_basic() {
569 let channel = derive_channel(
570 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN, band: TwoGhz },
571 None,
572 None,
573 None,
574 );
575 assert_eq!(channel, Channel::new(RX_PRIMARY_CHAN, Cbw::Cbw20, TwoGhz));
576 }
577
578 #[test]
579 fn test_derive_channel_with_dsss_param() {
580 let channel = derive_channel(
581 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN, band: TwoGhz },
582 Some(6),
583 None,
584 None,
585 );
586 assert_eq!(channel, Channel::new(6, Cbw::Cbw20, TwoGhz));
587 }
588
589 #[test]
590 fn test_derive_channel_with_ht_20mhz() {
591 let expected_channel = Channel::new(HT_PRIMARY_CHAN, Cbw::Cbw20, FiveGhz);
592
593 let test_params = [
594 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_NONE),
595 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_ABOVE),
596 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_BELOW),
597 (ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_NONE),
598 ];
599
600 for (ht_width, sec_chan_offset) in test_params.iter() {
601 let ht_op = ht_op(HT_PRIMARY_CHAN, *ht_width, *sec_chan_offset);
602 let channel = derive_channel(
603 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN_5GHZ, band: FiveGhz },
604 Some(RX_PRIMARY_CHAN_5GHZ),
605 Some(ht_op),
606 None,
607 );
608 assert_eq!(channel, expected_channel);
609 }
610 }
611
612 #[test]
613 fn test_derive_channel_with_ht_40mhz() {
614 let ht_op =
615 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
616 let channel = derive_channel(
617 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN_5GHZ, band: FiveGhz },
618 Some(RX_PRIMARY_CHAN_5GHZ),
619 Some(ht_op),
620 None,
621 );
622 assert_eq!(channel, Channel::new(HT_PRIMARY_CHAN, Cbw::Cbw40, FiveGhz));
623 }
624
625 #[test]
626 fn test_derive_channel_with_ht_40mhz_below() {
627 let ht_op =
628 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_BELOW);
629 let channel = derive_channel(
630 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN_5GHZ, band: FiveGhz },
631 Some(RX_PRIMARY_CHAN_5GHZ),
632 Some(ht_op),
633 None,
634 );
635 assert_eq!(channel, Channel::new(HT_PRIMARY_CHAN, Cbw::Cbw40Below, FiveGhz));
636 }
637
638 #[test]
639 fn test_derive_channel_with_vht_80mhz() {
640 let ht_op =
641 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
642 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 8, 0);
643 let channel = derive_channel(
644 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN_5GHZ, band: FiveGhz },
645 Some(RX_PRIMARY_CHAN_5GHZ),
646 Some(ht_op),
647 Some(vht_op),
648 );
649 assert_eq!(channel, Channel::new(HT_PRIMARY_CHAN, Cbw::Cbw80, FiveGhz));
650 }
651
652 #[test]
653 fn test_derive_channel_with_vht_160mhz() {
654 let ht_op =
655 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
656 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 0, 8);
657 let channel = derive_channel(
658 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN_5GHZ, band: FiveGhz },
659 Some(RX_PRIMARY_CHAN_5GHZ),
660 Some(ht_op),
661 Some(vht_op),
662 );
663 assert_eq!(channel, Channel::new(HT_PRIMARY_CHAN, Cbw::Cbw160, FiveGhz));
664 }
665
666 #[test]
667 fn test_derive_channel_with_vht_80plus80mhz() {
668 let ht_op =
669 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
670 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 18, 1);
671 let channel = derive_channel(
672 fidl_ieee80211::ChannelNumber { number: RX_PRIMARY_CHAN_5GHZ, band: FiveGhz },
673 Some(RX_PRIMARY_CHAN_5GHZ),
674 Some(ht_op),
675 Some(vht_op),
676 );
677 assert_eq!(
678 channel,
679 Channel::new(HT_PRIMARY_CHAN, Cbw::Cbw80P80 { secondary80: 1 }, FiveGhz)
680 );
681 }
682
683 #[test]
684 fn test_derive_channel_none() {
685 let channel = derive_channel(rx_channel(8, TwoGhz), None, None, None);
686 assert_eq!(channel, Channel::new(8, Cbw::Cbw20, TwoGhz));
687 }
688
689 #[test]
690 fn test_derive_channel_no_rx_primary() {
691 let channel = derive_channel(rx_channel(8, TwoGhz), Some(6), None, None);
692 assert_eq!(channel, Channel::new(6, Cbw::Cbw20, TwoGhz))
693 }
694
695 fn ht_op(
696 primary_channel: u8,
697 chan_width: ie::StaChanWidth,
698 offset: ie::SecChanOffset,
699 ) -> ie::HtOperation {
700 let ht_op_info =
701 ie::HtOpInfo::new().with_sta_chan_width(chan_width).with_secondary_chan_offset(offset);
702 ie::HtOperation { primary_channel, ht_op_info, basic_ht_mcs_set: ie::SupportedMcsSet(0) }
703 }
704
705 fn vht_op(vht_cbw: ie::VhtChannelBandwidth, seg0: u8, seg1: u8) -> ie::VhtOperation {
706 ie::VhtOperation {
707 vht_cbw,
708 center_freq_seg0: seg0,
709 center_freq_seg1: seg1,
710 basic_mcs_nss: ie::VhtMcsNssMap(0),
711 }
712 }
713}