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 pub fn get_band(&self) -> Result<fidl_ieee80211::WlanBand, anyhow::Error> {
125 if self.is_primary_2ghz() {
126 Ok(fidl_ieee80211::WlanBand::TwoGhz)
127 } else if self.is_primary_5ghz() {
128 Ok(fidl_ieee80211::WlanBand::FiveGhz)
129 } else {
130 Err(format_err!("cannot get band for channel {}", self))
131 }
132 }
133
134 fn get_band_start_freq(&self) -> Result<MHz, anyhow::Error> {
135 if self.is_primary_2ghz() {
136 Ok(BASE_FREQ_2GHZ)
137 } else if self.is_primary_5ghz() {
138 Ok(BASE_FREQ_5GHZ)
139 } else {
140 Err(format_err!("cannot get band start freq for channel {}", self))
141 }
142 }
143
144 fn get_center_chan_idx(&self) -> Result<u8, anyhow::Error> {
147 if !(self.is_primary_2ghz() || self.is_primary_5ghz()) {
148 return Err(format_err!(
149 "cannot get center channel index for an invalid primary channel {}",
150 self
151 ));
152 }
153
154 let p = self.primary;
155 match self.cbw {
156 Cbw::Cbw20 => Ok(p),
157 Cbw::Cbw40 => Ok(p + 2),
158 Cbw::Cbw40Below => Ok(p - 2),
159 Cbw::Cbw80 | Cbw::Cbw80P80 { .. } => match p {
160 36..=48 => Ok(42),
161 52..=64 => Ok(58),
162 100..=112 => Ok(106),
163 116..=128 => Ok(122),
164 132..=144 => Ok(138),
165 148..=161_ => Ok(155),
166 _ => {
167 return Err(format_err!(
168 "cannot get center channel index for invalid channel {}",
169 self
170 ));
171 }
172 },
173 Cbw::Cbw160 => {
174 match p {
178 36..=64 => Ok(50),
179 100..=128 => Ok(114),
180 _ => {
181 return Err(format_err!(
182 "cannot get center channel index for invalid channel {}",
183 self
184 ));
185 }
186 }
187 }
188 }
189 }
190
191 pub fn get_center_freq(&self) -> Result<MHz, anyhow::Error> {
194 let start_freq = self.get_band_start_freq()?;
196 let center_chan_idx = self.get_center_chan_idx()?;
197 let spacing: MHz = 5;
198 Ok(start_freq + spacing * center_chan_idx as u16)
199 }
200
201 pub fn is_valid_in_us(&self) -> bool {
205 if self.is_primary_2ghz() {
206 self.is_valid_2ghz_in_us()
207 } else if self.is_primary_5ghz() {
208 self.is_valid_5ghz_in_us()
209 } else {
210 false
211 }
212 }
213
214 fn is_valid_2ghz_in_us(&self) -> bool {
215 if !self.is_primary_2ghz() {
216 return false;
217 }
218 let p = self.primary;
219 match self.cbw {
220 Cbw::Cbw20 => p <= 11,
221 Cbw::Cbw40 => p <= 7,
222 Cbw::Cbw40Below => p >= 5,
223 _ => false,
224 }
225 }
226
227 fn is_valid_5ghz_in_us(&self) -> bool {
228 if !self.is_primary_5ghz() {
229 return false;
230 }
231 let p = self.primary;
232 match self.cbw {
233 Cbw::Cbw20 => true,
234 Cbw::Cbw40 => p != 165 && (p % 8) == (if p <= 144 { 4 } else { 5 }),
235 Cbw::Cbw40Below => p != 165 && (p % 8) == (if p <= 144 { 0 } else { 1 }),
236 Cbw::Cbw80 => p != 165,
237 Cbw::Cbw160 => p < 132,
238 Cbw::Cbw80P80 { secondary80 } => {
239 if p == 165 {
240 return false;
241 }
242 let valid_secondary80: [u8; 6] = [42, 58, 106, 122, 138, 155];
243 if !valid_secondary80.contains(&secondary80) {
244 return false;
245 }
246 let ccfs0 = match self.get_center_chan_idx() {
247 Ok(v) => v,
248 Err(_) => return false,
249 };
250 let ccfs1 = secondary80;
251 let gap = (ccfs0 as i16 - ccfs1 as i16).abs();
252 gap > 16
253 }
254 }
255 }
256
257 pub fn is_2ghz(&self) -> bool {
259 self.is_primary_2ghz()
260 }
261
262 pub fn is_5ghz(&self) -> bool {
264 self.is_primary_5ghz()
265 }
266}
267
268impl From<Channel> for fidl_ieee80211::WlanChannel {
269 fn from(channel: Channel) -> fidl_ieee80211::WlanChannel {
270 fidl_ieee80211::WlanChannel::from(&channel)
271 }
272}
273
274impl From<&Channel> for fidl_ieee80211::WlanChannel {
275 fn from(channel: &Channel) -> fidl_ieee80211::WlanChannel {
276 let (cbw, secondary80) = channel.cbw.to_fidl();
277 fidl_ieee80211::WlanChannel { primary: channel.primary, cbw, secondary80 }
278 }
279}
280
281impl TryFrom<fidl_ieee80211::WlanChannel> for Channel {
282 type Error = anyhow::Error;
283 fn try_from(fidl_channel: fidl_ieee80211::WlanChannel) -> Result<Channel, Self::Error> {
284 Channel::try_from(&fidl_channel)
285 }
286}
287
288impl TryFrom<&fidl_ieee80211::WlanChannel> for Channel {
289 type Error = anyhow::Error;
290
291 fn try_from(fidl_channel: &fidl_ieee80211::WlanChannel) -> Result<Channel, Self::Error> {
292 Ok(Channel {
293 primary: fidl_channel.primary,
294 cbw: Cbw::from_fidl(fidl_channel.cbw, fidl_channel.secondary80)?,
295 })
296 }
297}
298
299pub fn derive_channel(
306 rx_primary_channel: u8,
307 dsss_channel: Option<u8>,
308 ht_op: Option<ie::HtOperation>,
309 vht_op: Option<ie::VhtOperation>,
310) -> fidl_ieee80211::WlanChannel {
311 let primary = ht_op
312 .as_ref()
313 .map(|ht_op| ht_op.primary_channel)
314 .or(dsss_channel)
315 .unwrap_or(rx_primary_channel);
316
317 let ht_op_cbw = ht_op.map(|ht_op| ht_op.ht_op_info.sta_chan_width());
318 let vht_cbw_and_segs =
319 vht_op.map(|vht_op| (vht_op.vht_cbw, vht_op.center_freq_seg0, vht_op.center_freq_seg1));
320
321 let (cbw, secondary80) = match ht_op_cbw {
322 Some(ie::StaChanWidth::ANY) => {
324 let sec_chan_offset = ht_op.unwrap().ht_op_info.secondary_chan_offset();
326 derive_wide_channel_bandwidth(vht_cbw_and_segs, sec_chan_offset)
327 }
328 _ => Cbw::Cbw20,
330 }
331 .to_fidl();
332
333 fidl_ieee80211::WlanChannel { primary, cbw, secondary80 }
334}
335
336pub fn derive_wide_channel_bandwidth(
344 vht_cbw_and_segs: Option<(ie::VhtChannelBandwidth, u8, u8)>,
345 sec_chan_offset: ie::SecChanOffset,
346) -> Cbw {
347 use ie::VhtChannelBandwidth as Vcb;
348 match vht_cbw_and_segs {
349 Some((Vcb::CBW_80_160_80P80, _, 0)) => Cbw::Cbw80,
350 Some((Vcb::CBW_80_160_80P80, seg0, seg1)) if abs_sub(seg0, seg1) == 8 => Cbw::Cbw160,
351 Some((Vcb::CBW_80_160_80P80, seg0, seg1)) if abs_sub(seg0, seg1) > 16 => {
352 Cbw::Cbw80P80 { secondary80: seg1 }
354 }
355 _ => match sec_chan_offset {
360 ie::SecChanOffset::SECONDARY_ABOVE => Cbw::Cbw40,
361 ie::SecChanOffset::SECONDARY_BELOW => Cbw::Cbw40Below,
362 ie::SecChanOffset::SECONDARY_NONE | _ => Cbw::Cbw20,
363 },
364 }
365}
366
367fn abs_sub(v1: u8, v2: u8) -> u8 {
368 if v2 >= v1 { v2 - v1 } else { v1 - v2 }
369}
370
371pub fn primary_channel_from_freq(freq: u32) -> Option<u8> {
375 if (2412..=2472).contains(&freq) && (freq - 2412) % 5 == 0 {
377 Some(((freq - 2407) / 5) as u8)
378 } else if freq == 2484 {
380 Some(14)
381 } else if (5180..=5720).contains(&freq) && (freq - 5180) % 20 == 0 {
383 Some(((freq - 5000) / 5) as u8)
384 } else if (5745..=5865).contains(&freq) && (freq - 5745) % 20 == 0 {
386 Some(((freq - 5000) / 5) as u8)
387 } else {
388 None
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 use super::*;
395
396 #[test]
397 fn fmt_display() {
398 let mut c = Channel::new(100, Cbw::Cbw40);
399 assert_eq!(format!("{}", c), "100+");
400 c.cbw = Cbw::Cbw160;
401 assert_eq!(format!("{}", c), "100W");
402 c.cbw = Cbw::Cbw80P80 { secondary80: 200 };
403 assert_eq!(format!("{}", c), "100+200P");
404 }
405
406 #[test]
407 fn test_is_primary_2ghz_or_5ghz() {
408 assert!(Channel::new(1, Cbw::Cbw160).is_primary_2ghz());
410 assert!(!Channel::new(1, Cbw::Cbw160).is_primary_5ghz());
411
412 assert!(Channel::new(12, Cbw::Cbw160).is_primary_2ghz());
413 assert!(!Channel::new(12, Cbw::Cbw160).is_primary_5ghz());
414
415 assert!(!Channel::new(36, Cbw::Cbw160).is_primary_2ghz());
416 assert!(Channel::new(36, Cbw::Cbw160).is_primary_5ghz());
417
418 assert!(!Channel::new(37, Cbw::Cbw160).is_primary_2ghz());
419 assert!(!Channel::new(37, Cbw::Cbw160).is_primary_5ghz());
420
421 assert!(!Channel::new(165, Cbw::Cbw160).is_primary_2ghz());
422 assert!(Channel::new(165, Cbw::Cbw160).is_primary_5ghz());
423
424 assert!(!Channel::new(166, Cbw::Cbw160).is_primary_2ghz());
425 assert!(!Channel::new(166, Cbw::Cbw160).is_primary_5ghz());
426 }
427
428 #[test]
429 fn test_get_band() {
430 assert_eq!(
431 fidl_ieee80211::WlanBand::TwoGhz,
432 Channel::new(1, Cbw::Cbw20).get_band().unwrap()
433 );
434 assert_eq!(
435 fidl_ieee80211::WlanBand::TwoGhz,
436 Channel::new(14, Cbw::Cbw40).get_band().unwrap()
437 );
438 assert_eq!(
439 fidl_ieee80211::WlanBand::FiveGhz,
440 Channel::new(36, Cbw::Cbw80).get_band().unwrap()
441 );
442 assert_eq!(
443 fidl_ieee80211::WlanBand::FiveGhz,
444 Channel::new(165, Cbw::Cbw160).get_band().unwrap()
445 );
446 }
447
448 #[test]
449 fn test_band_start_freq() {
450 assert_eq!(BASE_FREQ_2GHZ, Channel::new(1, Cbw::Cbw20).get_band_start_freq().unwrap());
451 assert_eq!(BASE_FREQ_5GHZ, Channel::new(100, Cbw::Cbw20).get_band_start_freq().unwrap());
452 assert!(Channel::new(15, Cbw::Cbw20).get_band_start_freq().is_err());
453 assert!(Channel::new(200, Cbw::Cbw20).get_band_start_freq().is_err());
454 }
455
456 #[test]
457 fn test_get_center_chan_idx() {
458 assert!(Channel::new(1, Cbw::Cbw80).get_center_chan_idx().is_err());
459 assert_eq!(9, Channel::new(11, Cbw::Cbw40Below).get_center_chan_idx().unwrap());
460 assert_eq!(8, Channel::new(6, Cbw::Cbw40).get_center_chan_idx().unwrap());
461 assert_eq!(36, Channel::new(36, Cbw::Cbw20).get_center_chan_idx().unwrap());
462 assert_eq!(38, Channel::new(36, Cbw::Cbw40).get_center_chan_idx().unwrap());
463 assert_eq!(42, Channel::new(36, Cbw::Cbw80).get_center_chan_idx().unwrap());
464 assert_eq!(50, Channel::new(36, Cbw::Cbw160).get_center_chan_idx().unwrap());
465 assert_eq!(
466 42,
467 Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).get_center_chan_idx().unwrap()
468 );
469 }
470
471 #[test]
472 fn test_get_center_freq() {
473 assert_eq!(2412 as MHz, Channel::new(1, Cbw::Cbw20).get_center_freq().unwrap());
474 assert_eq!(2437 as MHz, Channel::new(6, Cbw::Cbw20).get_center_freq().unwrap());
475 assert_eq!(2447 as MHz, Channel::new(6, Cbw::Cbw40).get_center_freq().unwrap());
476 assert_eq!(2427 as MHz, Channel::new(6, Cbw::Cbw40Below).get_center_freq().unwrap());
477 assert_eq!(5180 as MHz, Channel::new(36, Cbw::Cbw20).get_center_freq().unwrap());
478 assert_eq!(5190 as MHz, Channel::new(36, Cbw::Cbw40).get_center_freq().unwrap());
479 assert_eq!(5210 as MHz, Channel::new(36, Cbw::Cbw80).get_center_freq().unwrap());
480 assert_eq!(5250 as MHz, Channel::new(36, Cbw::Cbw160).get_center_freq().unwrap());
481 assert_eq!(
482 5210 as MHz,
483 Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).get_center_freq().unwrap()
484 );
485 }
486
487 #[test]
488 fn test_primarychannel_from_freq() {
489 assert_eq!(Some(1), primary_channel_from_freq(2412));
490 assert_eq!(None, primary_channel_from_freq(2413));
492 assert_eq!(Some(6), primary_channel_from_freq(2437));
493 assert_eq!(Some(13), primary_channel_from_freq(2472));
494 assert_eq!(Some(14), primary_channel_from_freq(2484));
495 assert_eq!(None, primary_channel_from_freq(5160));
497 assert_eq!(Some(36), primary_channel_from_freq(5180));
498 assert_eq!(None, primary_channel_from_freq(5190));
500 assert_eq!(Some(165), primary_channel_from_freq(5825));
501 assert_eq!(Some(173), primary_channel_from_freq(5865));
502 assert_eq!(None, primary_channel_from_freq(2400));
504 assert_eq!(None, primary_channel_from_freq(5000));
506 assert_eq!(None, primary_channel_from_freq(5885));
508 }
509
510 #[test]
511 fn test_valid_us_combo() {
512 assert!(Channel::new(1, Cbw::Cbw20).is_valid_in_us());
513 assert!(Channel::new(1, Cbw::Cbw40).is_valid_in_us());
514 assert!(Channel::new(5, Cbw::Cbw40Below).is_valid_in_us());
515 assert!(Channel::new(6, Cbw::Cbw20).is_valid_in_us());
516 assert!(Channel::new(6, Cbw::Cbw40).is_valid_in_us());
517 assert!(Channel::new(6, Cbw::Cbw40Below).is_valid_in_us());
518 assert!(Channel::new(7, Cbw::Cbw40).is_valid_in_us());
519 assert!(Channel::new(11, Cbw::Cbw20).is_valid_in_us());
520 assert!(Channel::new(11, Cbw::Cbw40Below).is_valid_in_us());
521
522 assert!(Channel::new(36, Cbw::Cbw20).is_valid_in_us());
523 assert!(Channel::new(36, Cbw::Cbw40).is_valid_in_us());
524 assert!(Channel::new(36, Cbw::Cbw160).is_valid_in_us());
525 assert!(Channel::new(40, Cbw::Cbw20).is_valid_in_us());
526 assert!(Channel::new(40, Cbw::Cbw40Below).is_valid_in_us());
527 assert!(Channel::new(40, Cbw::Cbw160).is_valid_in_us());
528 assert!(Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).is_valid_in_us());
529 assert!(Channel::new(40, Cbw::Cbw80P80 { secondary80: 155 }).is_valid_in_us());
530 assert!(Channel::new(161, Cbw::Cbw80P80 { secondary80: 42 }).is_valid_in_us());
531 }
532
533 #[test]
534 fn test_invalid_us_combo() {
535 assert!(!Channel::new(1, Cbw::Cbw40Below).is_valid_in_us());
536 assert!(!Channel::new(4, Cbw::Cbw40Below).is_valid_in_us());
537 assert!(!Channel::new(8, Cbw::Cbw40).is_valid_in_us());
538 assert!(!Channel::new(11, Cbw::Cbw40).is_valid_in_us());
539 assert!(!Channel::new(6, Cbw::Cbw80).is_valid_in_us());
540 assert!(!Channel::new(6, Cbw::Cbw160).is_valid_in_us());
541 assert!(!Channel::new(6, Cbw::Cbw80P80 { secondary80: 155 }).is_valid_in_us());
542
543 assert!(!Channel::new(36, Cbw::Cbw40Below).is_valid_in_us());
544 assert!(!Channel::new(36, Cbw::Cbw80P80 { secondary80: 58 }).is_valid_in_us());
545 assert!(!Channel::new(40, Cbw::Cbw40).is_valid_in_us());
546 assert!(!Channel::new(40, Cbw::Cbw80P80 { secondary80: 42 }).is_valid_in_us());
547
548 assert!(!Channel::new(165, Cbw::Cbw80).is_valid_in_us());
549 assert!(!Channel::new(165, Cbw::Cbw80P80 { secondary80: 42 }).is_valid_in_us());
550 }
551
552 #[test]
553 fn test_is_2ghz_or_5ghz() {
554 assert!(Channel::new(1, Cbw::Cbw20).is_2ghz());
555 assert!(!Channel::new(1, Cbw::Cbw20).is_5ghz());
556 assert!(Channel::new(13, Cbw::Cbw20).is_2ghz());
557 assert!(!Channel::new(13, Cbw::Cbw20).is_5ghz());
558 assert!(Channel::new(36, Cbw::Cbw20).is_5ghz());
559 assert!(!Channel::new(36, Cbw::Cbw20).is_2ghz());
560 }
561
562 #[test]
563 fn test_convert_fidl_channel() {
564 let mut f = fidl_ieee80211::WlanChannel::from(Channel::new(1, Cbw::Cbw20));
565 assert!(
566 f.primary == 1
567 && f.cbw == fidl_ieee80211::ChannelBandwidth::Cbw20
568 && f.secondary80 == 0
569 );
570
571 f = Channel::new(36, Cbw::Cbw80P80 { secondary80: 155 }).into();
572 assert!(
573 f.primary == 36
574 && f.cbw == fidl_ieee80211::ChannelBandwidth::Cbw80P80
575 && f.secondary80 == 155
576 );
577
578 let mut c = Channel::try_from(fidl_ieee80211::WlanChannel {
579 primary: 11,
580 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40Below,
581 secondary80: 123,
582 })
583 .unwrap();
584 assert!(c.primary == 11 && c.cbw == Cbw::Cbw40Below);
585 c = fidl_ieee80211::WlanChannel {
586 primary: 149,
587 cbw: fidl_ieee80211::ChannelBandwidth::Cbw80P80,
588 secondary80: 42,
589 }
590 .try_into()
591 .unwrap();
592 assert!(c.primary == 149 && c.cbw == Cbw::Cbw80P80 { secondary80: 42 });
593
594 let r = Channel::try_from(fidl_ieee80211::WlanChannel {
595 primary: 11,
596 cbw: fidl_ieee80211::ChannelBandwidth::unknown(),
597 secondary80: 123,
598 });
599 assert!(r.is_err());
600 }
601
602 const RX_PRIMARY_CHAN: u8 = 11;
603 const HT_PRIMARY_CHAN: u8 = 48;
604
605 #[test]
606 fn test_derive_channel_basic() {
607 let channel = derive_channel(RX_PRIMARY_CHAN, None, None, None);
608 assert_eq!(
609 channel,
610 fidl_ieee80211::WlanChannel {
611 primary: RX_PRIMARY_CHAN,
612 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
613 secondary80: 0,
614 }
615 );
616 }
617
618 #[test]
619 fn test_derive_channel_with_dsss_param() {
620 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), None, None);
621 assert_eq!(
622 channel,
623 fidl_ieee80211::WlanChannel {
624 primary: 6,
625 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
626 secondary80: 0
627 }
628 );
629 }
630
631 #[test]
632 fn test_derive_channel_with_ht_20mhz() {
633 let expected_channel = fidl_ieee80211::WlanChannel {
634 primary: HT_PRIMARY_CHAN,
635 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
636 secondary80: 0,
637 };
638
639 let test_params = [
640 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_NONE),
641 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_ABOVE),
642 (ie::StaChanWidth::TWENTY_MHZ, ie::SecChanOffset::SECONDARY_BELOW),
643 (ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_NONE),
644 ];
645
646 for (ht_width, sec_chan_offset) in test_params.iter() {
647 let ht_op = ht_op(HT_PRIMARY_CHAN, *ht_width, *sec_chan_offset);
648 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), None);
649 assert_eq!(channel, expected_channel);
650 }
651 }
652
653 #[test]
654 fn test_derive_channel_with_ht_40mhz() {
655 let ht_op =
656 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
657 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), None);
658 assert_eq!(
659 channel,
660 fidl_ieee80211::WlanChannel {
661 primary: HT_PRIMARY_CHAN,
662 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40,
663 secondary80: 0,
664 }
665 );
666 }
667
668 #[test]
669 fn test_derive_channel_with_ht_40mhz_below() {
670 let ht_op =
671 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_BELOW);
672 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), None);
673 assert_eq!(
674 channel,
675 fidl_ieee80211::WlanChannel {
676 primary: HT_PRIMARY_CHAN,
677 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40Below,
678 secondary80: 0,
679 }
680 );
681 }
682
683 #[test]
684 fn test_derive_channel_with_vht_80mhz() {
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, 8, 0);
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::Cbw80,
694 secondary80: 0,
695 }
696 );
697 }
698
699 #[test]
700 fn test_derive_channel_with_vht_160mhz() {
701 let ht_op =
702 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
703 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 0, 8);
704 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), Some(vht_op));
705 assert_eq!(
706 channel,
707 fidl_ieee80211::WlanChannel {
708 primary: HT_PRIMARY_CHAN,
709 cbw: fidl_ieee80211::ChannelBandwidth::Cbw160,
710 secondary80: 0,
711 }
712 );
713 }
714
715 #[test]
716 fn test_derive_channel_with_vht_80plus80mhz() {
717 let ht_op =
718 ht_op(HT_PRIMARY_CHAN, ie::StaChanWidth::ANY, ie::SecChanOffset::SECONDARY_ABOVE);
719 let vht_op = vht_op(ie::VhtChannelBandwidth::CBW_80_160_80P80, 18, 1);
720 let channel = derive_channel(RX_PRIMARY_CHAN, Some(6), Some(ht_op), Some(vht_op));
721 assert_eq!(
722 channel,
723 fidl_ieee80211::WlanChannel {
724 primary: HT_PRIMARY_CHAN,
725 cbw: fidl_ieee80211::ChannelBandwidth::Cbw80P80,
726 secondary80: 1,
727 }
728 );
729 }
730
731 #[test]
732 fn test_derive_channel_none() {
733 let channel = derive_channel(8, None, None, None);
734 assert_eq!(
735 channel,
736 fidl_ieee80211::WlanChannel {
737 primary: 8,
738 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
739 secondary80: 0,
740 }
741 );
742 }
743
744 #[test]
745 fn test_derive_channel_no_rx_primary() {
746 let channel = derive_channel(8, Some(6), None, None);
747 assert_eq!(
748 channel,
749 fidl_ieee80211::WlanChannel {
750 primary: 6,
751 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
752 secondary80: 0,
753 }
754 )
755 }
756
757 fn ht_op(
758 primary_channel: u8,
759 chan_width: ie::StaChanWidth,
760 offset: ie::SecChanOffset,
761 ) -> ie::HtOperation {
762 let ht_op_info =
763 ie::HtOpInfo::new().with_sta_chan_width(chan_width).with_secondary_chan_offset(offset);
764 ie::HtOperation { primary_channel, ht_op_info, basic_ht_mcs_set: ie::SupportedMcsSet(0) }
765 }
766
767 fn vht_op(vht_cbw: ie::VhtChannelBandwidth, seg0: u8, seg1: u8) -> ie::VhtOperation {
768 ie::VhtOperation {
769 vht_cbw,
770 center_freq_seg0: seg0,
771 center_freq_seg1: seg1,
772 basic_mcs_nss: ie::VhtMcsNssMap(0),
773 }
774 }
775}