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