1use alloc::vec::Vec;
7
8use crate::net::MacAddress;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[repr(u8)]
17pub enum FrameType {
18 Management = 0,
20 Control = 1,
22 Data = 2,
24}
25
26impl FrameType {
27 pub fn from_bits(bits: u8) -> Option<Self> {
29 match bits & 0x03 {
30 0 => Some(Self::Management),
31 1 => Some(Self::Control),
32 2 => Some(Self::Data),
33 _ => None,
34 }
35 }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40#[repr(u8)]
41pub enum ManagementSubtype {
42 AssocReq = 0,
43 AssocResp = 1,
44 ProbeReq = 4,
45 ProbeResp = 5,
46 Beacon = 8,
47 Disassoc = 10,
48 Auth = 11,
49 Deauth = 12,
50 Action = 13,
51}
52
53impl ManagementSubtype {
54 pub fn from_bits(bits: u8) -> Option<Self> {
56 match bits & 0x0F {
57 0 => Some(Self::AssocReq),
58 1 => Some(Self::AssocResp),
59 4 => Some(Self::ProbeReq),
60 5 => Some(Self::ProbeResp),
61 8 => Some(Self::Beacon),
62 10 => Some(Self::Disassoc),
63 11 => Some(Self::Auth),
64 12 => Some(Self::Deauth),
65 13 => Some(Self::Action),
66 _ => None,
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub struct FrameControl {
78 pub protocol_version: u8,
80 pub frame_type: FrameType,
82 pub subtype: u8,
84 pub to_ds: bool,
86 pub from_ds: bool,
88 pub more_fragments: bool,
90 pub retry: bool,
92 pub power_mgmt: bool,
94 pub more_data: bool,
96 pub protected_frame: bool,
98 pub order: bool,
100}
101
102impl Default for FrameControl {
103 fn default() -> Self {
104 Self {
105 protocol_version: 0,
106 frame_type: FrameType::Management,
107 subtype: 0,
108 to_ds: false,
109 from_ds: false,
110 more_fragments: false,
111 retry: false,
112 power_mgmt: false,
113 more_data: false,
114 protected_frame: false,
115 order: false,
116 }
117 }
118}
119
120impl FrameControl {
121 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
123 if bytes.len() < 2 {
124 return None;
125 }
126 let b0 = bytes[0];
127 let b1 = bytes[1];
128
129 let protocol_version = b0 & 0x03;
130 let type_bits = (b0 >> 2) & 0x03;
131 let subtype = (b0 >> 4) & 0x0F;
132
133 let frame_type = FrameType::from_bits(type_bits)?;
134
135 Some(Self {
136 protocol_version,
137 frame_type,
138 subtype,
139 to_ds: (b1 & 0x01) != 0,
140 from_ds: (b1 & 0x02) != 0,
141 more_fragments: (b1 & 0x04) != 0,
142 retry: (b1 & 0x08) != 0,
143 power_mgmt: (b1 & 0x10) != 0,
144 more_data: (b1 & 0x20) != 0,
145 protected_frame: (b1 & 0x40) != 0,
146 order: (b1 & 0x80) != 0,
147 })
148 }
149
150 pub fn to_bytes(&self) -> [u8; 2] {
152 let b0 = (self.protocol_version & 0x03)
153 | ((self.frame_type as u8 & 0x03) << 2)
154 | ((self.subtype & 0x0F) << 4);
155 let b1 = (self.to_ds as u8)
156 | ((self.from_ds as u8) << 1)
157 | ((self.more_fragments as u8) << 2)
158 | ((self.retry as u8) << 3)
159 | ((self.power_mgmt as u8) << 4)
160 | ((self.more_data as u8) << 5)
161 | ((self.protected_frame as u8) << 6)
162 | ((self.order as u8) << 7);
163 [b0, b1]
164 }
165}
166
167#[derive(Debug, Clone)]
173pub struct Ieee80211Header {
174 pub frame_control: FrameControl,
176 pub duration_id: u16,
178 pub addr1: MacAddress,
180 pub addr2: MacAddress,
182 pub addr3: MacAddress,
184 pub sequence_control: u16,
186 pub addr4: Option<MacAddress>,
188}
189
190impl Ieee80211Header {
191 pub const MIN_SIZE: usize = 24;
193 pub const WITH_ADDR4_SIZE: usize = 30;
195
196 pub fn from_bytes(data: &[u8]) -> Option<Self> {
198 if data.len() < Self::MIN_SIZE {
199 return None;
200 }
201
202 let frame_control = FrameControl::from_bytes(&data[0..2])?;
203 let duration_id = u16::from_le_bytes([data[2], data[3]]);
204
205 let mut addr1_bytes = [0u8; 6];
206 addr1_bytes.copy_from_slice(&data[4..10]);
207 let mut addr2_bytes = [0u8; 6];
208 addr2_bytes.copy_from_slice(&data[10..16]);
209 let mut addr3_bytes = [0u8; 6];
210 addr3_bytes.copy_from_slice(&data[16..22]);
211
212 let sequence_control = u16::from_le_bytes([data[22], data[23]]);
213
214 let addr4 = if frame_control.to_ds && frame_control.from_ds {
216 if data.len() < Self::WITH_ADDR4_SIZE {
217 return None;
218 }
219 let mut addr4_bytes = [0u8; 6];
220 addr4_bytes.copy_from_slice(&data[24..30]);
221 Some(MacAddress::new(addr4_bytes))
222 } else {
223 None
224 };
225
226 Some(Self {
227 frame_control,
228 duration_id,
229 addr1: MacAddress::new(addr1_bytes),
230 addr2: MacAddress::new(addr2_bytes),
231 addr3: MacAddress::new(addr3_bytes),
232 sequence_control,
233 addr4,
234 })
235 }
236
237 pub fn to_bytes(&self) -> Vec<u8> {
239 let mut buf = Vec::with_capacity(Self::WITH_ADDR4_SIZE);
240 let fc = self.frame_control.to_bytes();
241 buf.extend_from_slice(&fc);
242 buf.extend_from_slice(&self.duration_id.to_le_bytes());
243 buf.extend_from_slice(&self.addr1.0);
244 buf.extend_from_slice(&self.addr2.0);
245 buf.extend_from_slice(&self.addr3.0);
246 buf.extend_from_slice(&self.sequence_control.to_le_bytes());
247 if let Some(ref a4) = self.addr4 {
248 buf.extend_from_slice(&a4.0);
249 }
250 buf
251 }
252
253 pub fn header_len(&self) -> usize {
255 if self.addr4.is_some() {
256 Self::WITH_ADDR4_SIZE
257 } else {
258 Self::MIN_SIZE
259 }
260 }
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq)]
269#[repr(u8)]
270pub enum InformationElementId {
271 Ssid = 0,
273 SupportedRates = 1,
275 DsParameterSet = 3,
277 Rsn = 48,
279}
280
281#[derive(Debug, Clone)]
283pub struct InformationElement {
284 pub id: u8,
286 pub data: Vec<u8>,
288}
289
290pub fn parse_information_elements(data: &[u8]) -> Vec<InformationElement> {
292 let mut elements = Vec::new();
293 let mut offset = 0;
294
295 while offset + 2 <= data.len() {
296 let id = data[offset];
297 let len = data[offset + 1] as usize;
298 offset += 2;
299
300 if offset + len > data.len() {
301 break;
302 }
303
304 elements.push(InformationElement {
305 id,
306 data: data[offset..offset + len].to_vec(),
307 });
308
309 offset += len;
310 }
311
312 elements
313}
314
315pub fn extract_ssid(ies: &[InformationElement]) -> Option<Vec<u8>> {
317 for ie in ies {
318 if ie.id == InformationElementId::Ssid as u8 && ie.data.len() <= 32 {
319 return Some(ie.data.clone());
320 }
321 }
322 None
323}
324
325pub fn extract_channel(ies: &[InformationElement]) -> Option<u8> {
327 for ie in ies {
328 if ie.id == InformationElementId::DsParameterSet as u8 && ie.data.len() == 1 {
329 return Some(ie.data[0]);
330 }
331 }
332 None
333}
334
335pub fn has_rsn(ies: &[InformationElement]) -> bool {
337 ies.iter()
338 .any(|ie| ie.id == InformationElementId::Rsn as u8)
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
347pub enum SecurityType {
348 #[default]
350 Open,
351 Wpa2Psk,
353 Wpa2Enterprise,
355 Wpa3Sae,
357}
358
359#[derive(Debug, Clone)]
365pub struct BssInfo {
366 pub bssid: MacAddress,
368 pub ssid: Vec<u8>,
370 pub channel: u8,
372 pub beacon_interval: u16,
374 pub capability: u16,
376 pub signal_strength: i8,
378 pub security_type: SecurityType,
380}
381
382#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
388pub enum StaState {
389 #[default]
391 Disconnected,
392 Scanning,
394 Authenticating,
396 Associating,
398 Associated,
400 Connected,
402}
403
404#[derive(Debug, Clone)]
406pub struct StaConfig {
407 pub ssid: Vec<u8>,
409 pub password_hash: [u8; 32],
411 pub preferred_bssid: Option<MacAddress>,
413}
414
415pub struct WifiStation {
417 state: StaState,
419 own_addr: MacAddress,
421 current_bss: Option<BssInfo>,
423 scan_results: Vec<BssInfo>,
425 _config: Option<StaConfig>,
427 sequence_number: u16,
429}
430
431impl WifiStation {
432 pub fn new(own_addr: MacAddress) -> Self {
434 Self {
435 state: StaState::Disconnected,
436 own_addr,
437 current_bss: None,
438 scan_results: Vec::new(),
439 _config: None,
440 sequence_number: 0,
441 }
442 }
443
444 pub fn state(&self) -> StaState {
446 self.state
447 }
448
449 pub fn current_bss(&self) -> Option<&BssInfo> {
451 self.current_bss.as_ref()
452 }
453
454 pub fn scan_results(&self) -> &[BssInfo] {
456 &self.scan_results
457 }
458
459 pub fn start_scan(&mut self) -> Vec<u8> {
462 self.state = StaState::Scanning;
463 self.scan_results.clear();
464 self.build_probe_request()
465 }
466
467 pub fn process_beacon(&mut self, frame_data: &[u8]) -> Option<BssInfo> {
470 let header = Ieee80211Header::from_bytes(frame_data)?;
472
473 if header.frame_control.frame_type != FrameType::Management {
474 return None;
475 }
476 if header.frame_control.subtype != ManagementSubtype::Beacon as u8 {
477 return None;
478 }
479
480 let hdr_len = header.header_len();
481 if frame_data.len() < hdr_len + 12 {
483 return None;
484 }
485
486 let fixed_start = hdr_len;
487 let beacon_interval =
489 u16::from_le_bytes([frame_data[fixed_start + 8], frame_data[fixed_start + 9]]);
490 let capability =
491 u16::from_le_bytes([frame_data[fixed_start + 10], frame_data[fixed_start + 11]]);
492
493 let ie_start = fixed_start + 12;
494 let ies = parse_information_elements(&frame_data[ie_start..]);
495
496 let ssid = extract_ssid(&ies).unwrap_or_default();
497 let channel = extract_channel(&ies).unwrap_or(0);
498 let security_type = if has_rsn(&ies) {
499 SecurityType::Wpa2Psk
500 } else if capability & 0x0010 != 0 {
501 SecurityType::Wpa2Psk
503 } else {
504 SecurityType::Open
505 };
506
507 let bss = BssInfo {
508 bssid: header.addr2,
509 ssid,
510 channel,
511 beacon_interval,
512 capability,
513 signal_strength: -50, security_type,
515 };
516
517 if !self.scan_results.iter().any(|b| b.bssid.0 == bss.bssid.0) {
519 self.scan_results.push(bss.clone());
520 }
521
522 Some(bss)
523 }
524
525 pub fn authenticate(&mut self, bss: &BssInfo) -> Option<Vec<u8>> {
528 if self.state != StaState::Scanning && self.state != StaState::Disconnected {
529 return None;
530 }
531
532 self.current_bss = Some(bss.clone());
533 self.state = StaState::Authenticating;
534
535 Some(self.build_auth_frame(&bss.bssid))
536 }
537
538 pub fn process_auth_response(&mut self, frame_data: &[u8]) -> bool {
541 let header = match Ieee80211Header::from_bytes(frame_data) {
542 Some(h) => h,
543 None => return false,
544 };
545
546 if header.frame_control.frame_type != FrameType::Management {
547 return false;
548 }
549 if header.frame_control.subtype != ManagementSubtype::Auth as u8 {
550 return false;
551 }
552
553 let hdr_len = header.header_len();
554 if frame_data.len() < hdr_len + 6 {
556 return false;
557 }
558
559 let status = u16::from_le_bytes([frame_data[hdr_len + 4], frame_data[hdr_len + 5]]);
560
561 if status == 0 {
562 self.state = StaState::Associating;
564 true
565 } else {
566 self.state = StaState::Disconnected;
567 false
568 }
569 }
570
571 pub fn associate(&mut self) -> Option<Vec<u8>> {
574 if self.state != StaState::Associating {
575 return None;
576 }
577
578 let bssid = self.current_bss.as_ref()?.bssid;
579 Some(self.build_assoc_request(&bssid))
580 }
581
582 pub fn process_assoc_response(&mut self, frame_data: &[u8]) -> bool {
585 let header = match Ieee80211Header::from_bytes(frame_data) {
586 Some(h) => h,
587 None => return false,
588 };
589
590 if header.frame_control.frame_type != FrameType::Management {
591 return false;
592 }
593 if header.frame_control.subtype != ManagementSubtype::AssocResp as u8 {
594 return false;
595 }
596
597 let hdr_len = header.header_len();
598 if frame_data.len() < hdr_len + 6 {
600 return false;
601 }
602
603 let status = u16::from_le_bytes([frame_data[hdr_len + 2], frame_data[hdr_len + 3]]);
604
605 if status == 0 {
606 self.state = StaState::Associated;
607 true
608 } else {
609 self.state = StaState::Disconnected;
610 false
611 }
612 }
613
614 pub fn deauthenticate(&mut self, reason: u16) -> Option<Vec<u8>> {
617 let bssid = self.current_bss.as_ref()?.bssid;
618 let frame = self.build_deauth_frame(&bssid, reason);
619 self.state = StaState::Disconnected;
620 self.current_bss = None;
621 Some(frame)
622 }
623
624 pub fn set_connected(&mut self) {
626 if self.state == StaState::Associated {
627 self.state = StaState::Connected;
628 }
629 }
630
631 pub fn parse_frame(data: &[u8]) -> Option<(Ieee80211Header, &[u8])> {
633 let header = Ieee80211Header::from_bytes(data)?;
634 let hdr_len = header.header_len();
635 if data.len() >= hdr_len {
636 Some((header, &data[hdr_len..]))
637 } else {
638 None
639 }
640 }
641
642 fn next_sequence_control(&mut self) -> u16 {
644 let seq = self.sequence_number;
645 self.sequence_number = self.sequence_number.wrapping_add(1) & 0x0FFF;
646 seq << 4 }
648
649 fn build_probe_request(&mut self) -> Vec<u8> {
651 let fc = FrameControl {
652 frame_type: FrameType::Management,
653 subtype: ManagementSubtype::ProbeReq as u8,
654 ..Default::default()
655 };
656 let seq = self.next_sequence_control();
657 let header = Ieee80211Header {
658 frame_control: fc,
659 duration_id: 0,
660 addr1: MacAddress::BROADCAST,
661 addr2: self.own_addr,
662 addr3: MacAddress::BROADCAST,
663 sequence_control: seq,
664 addr4: None,
665 };
666
667 let mut frame = header.to_bytes();
668
669 frame.push(InformationElementId::Ssid as u8);
671 frame.push(0);
672
673 frame.push(InformationElementId::SupportedRates as u8);
675 frame.push(4);
676 frame.extend_from_slice(&[0x82, 0x84, 0x8B, 0x96]); frame
679 }
680
681 fn build_auth_frame(&mut self, bssid: &MacAddress) -> Vec<u8> {
683 let fc = FrameControl {
684 frame_type: FrameType::Management,
685 subtype: ManagementSubtype::Auth as u8,
686 ..Default::default()
687 };
688 let seq = self.next_sequence_control();
689 let header = Ieee80211Header {
690 frame_control: fc,
691 duration_id: 0,
692 addr1: *bssid,
693 addr2: self.own_addr,
694 addr3: *bssid,
695 sequence_control: seq,
696 addr4: None,
697 };
698
699 let mut frame = header.to_bytes();
700
701 frame.extend_from_slice(&0u16.to_le_bytes());
703 frame.extend_from_slice(&1u16.to_le_bytes());
705 frame.extend_from_slice(&0u16.to_le_bytes());
707
708 frame
709 }
710
711 fn build_assoc_request(&mut self, bssid: &MacAddress) -> Vec<u8> {
713 let fc = FrameControl {
714 frame_type: FrameType::Management,
715 subtype: ManagementSubtype::AssocReq as u8,
716 ..Default::default()
717 };
718 let seq = self.next_sequence_control();
719 let header = Ieee80211Header {
720 frame_control: fc,
721 duration_id: 0,
722 addr1: *bssid,
723 addr2: self.own_addr,
724 addr3: *bssid,
725 sequence_control: seq,
726 addr4: None,
727 };
728
729 let mut frame = header.to_bytes();
730
731 let capability: u16 = 0x0021;
733 frame.extend_from_slice(&capability.to_le_bytes());
734 frame.extend_from_slice(&10u16.to_le_bytes());
736
737 if let Some(ref bss) = self.current_bss {
739 frame.push(InformationElementId::Ssid as u8);
740 frame.push(bss.ssid.len() as u8);
741 frame.extend_from_slice(&bss.ssid);
742 }
743
744 frame.push(InformationElementId::SupportedRates as u8);
746 frame.push(4);
747 frame.extend_from_slice(&[0x82, 0x84, 0x8B, 0x96]);
748
749 frame
750 }
751
752 fn build_deauth_frame(&mut self, bssid: &MacAddress, reason: u16) -> Vec<u8> {
754 let fc = FrameControl {
755 frame_type: FrameType::Management,
756 subtype: ManagementSubtype::Deauth as u8,
757 ..Default::default()
758 };
759 let seq = self.next_sequence_control();
760 let header = Ieee80211Header {
761 frame_control: fc,
762 duration_id: 0,
763 addr1: *bssid,
764 addr2: self.own_addr,
765 addr3: *bssid,
766 sequence_control: seq,
767 addr4: None,
768 };
769
770 let mut frame = header.to_bytes();
771 frame.extend_from_slice(&reason.to_le_bytes());
772 frame
773 }
774}
775
776#[cfg(test)]
781mod tests {
782 #[allow(unused_imports)]
783 use alloc::vec;
784
785 use super::*;
786
787 #[test]
788 fn test_frame_type_from_bits() {
789 assert_eq!(FrameType::from_bits(0), Some(FrameType::Management));
790 assert_eq!(FrameType::from_bits(1), Some(FrameType::Control));
791 assert_eq!(FrameType::from_bits(2), Some(FrameType::Data));
792 assert_eq!(FrameType::from_bits(3), None);
793 }
794
795 #[test]
796 fn test_management_subtype_from_bits() {
797 assert_eq!(
798 ManagementSubtype::from_bits(8),
799 Some(ManagementSubtype::Beacon)
800 );
801 assert_eq!(
802 ManagementSubtype::from_bits(11),
803 Some(ManagementSubtype::Auth)
804 );
805 assert_eq!(
806 ManagementSubtype::from_bits(0),
807 Some(ManagementSubtype::AssocReq)
808 );
809 assert_eq!(ManagementSubtype::from_bits(15), None);
810 }
811
812 #[test]
813 fn test_frame_control_roundtrip() {
814 let fc = FrameControl {
815 protocol_version: 0,
816 frame_type: FrameType::Management,
817 subtype: ManagementSubtype::Beacon as u8,
818 to_ds: false,
819 from_ds: false,
820 retry: true,
821 protected_frame: true,
822 ..Default::default()
823 };
824 let bytes = fc.to_bytes();
825 let parsed = FrameControl::from_bytes(&bytes).unwrap();
826 assert_eq!(parsed.frame_type, FrameType::Management);
827 assert_eq!(parsed.subtype, ManagementSubtype::Beacon as u8);
828 assert!(parsed.retry);
829 assert!(parsed.protected_frame);
830 assert!(!parsed.to_ds);
831 }
832
833 #[test]
834 fn test_frame_control_data_frame() {
835 let fc = FrameControl {
836 frame_type: FrameType::Data,
837 subtype: 0,
838 to_ds: true,
839 from_ds: false,
840 ..Default::default()
841 };
842 let bytes = fc.to_bytes();
843 let parsed = FrameControl::from_bytes(&bytes).unwrap();
844 assert_eq!(parsed.frame_type, FrameType::Data);
845 assert!(parsed.to_ds);
846 assert!(!parsed.from_ds);
847 }
848
849 #[test]
850 fn test_frame_control_too_short() {
851 assert!(FrameControl::from_bytes(&[0x80]).is_none());
852 assert!(FrameControl::from_bytes(&[]).is_none());
853 }
854
855 #[test]
856 fn test_header_roundtrip() {
857 let header = Ieee80211Header {
858 frame_control: FrameControl {
859 frame_type: FrameType::Management,
860 subtype: ManagementSubtype::Beacon as u8,
861 ..Default::default()
862 },
863 duration_id: 0x1234,
864 addr1: MacAddress::BROADCAST,
865 addr2: MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]),
866 addr3: MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]),
867 sequence_control: 0x0010,
868 addr4: None,
869 };
870
871 let bytes = header.to_bytes();
872 assert_eq!(bytes.len(), Ieee80211Header::MIN_SIZE);
873
874 let parsed = Ieee80211Header::from_bytes(&bytes).unwrap();
875 assert_eq!(parsed.duration_id, 0x1234);
876 assert_eq!(parsed.addr1.0, MacAddress::BROADCAST.0);
877 assert_eq!(parsed.addr2.0, [0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
878 assert_eq!(parsed.sequence_control, 0x0010);
879 assert!(parsed.addr4.is_none());
880 }
881
882 #[test]
883 fn test_header_with_addr4() {
884 let mut fc = FrameControl::default();
885 fc.to_ds = true;
886 fc.from_ds = true;
887
888 let header = Ieee80211Header {
889 frame_control: fc,
890 duration_id: 0,
891 addr1: MacAddress::BROADCAST,
892 addr2: MacAddress::ZERO,
893 addr3: MacAddress::ZERO,
894 sequence_control: 0,
895 addr4: Some(MacAddress::new([0x01, 0x02, 0x03, 0x04, 0x05, 0x06])),
896 };
897
898 let bytes = header.to_bytes();
899 assert_eq!(bytes.len(), Ieee80211Header::WITH_ADDR4_SIZE);
900
901 let parsed = Ieee80211Header::from_bytes(&bytes).unwrap();
902 assert!(parsed.addr4.is_some());
903 assert_eq!(
904 parsed.addr4.unwrap().0,
905 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]
906 );
907 }
908
909 #[test]
910 fn test_header_too_short() {
911 let data = [0u8; 20];
912 assert!(Ieee80211Header::from_bytes(&data).is_none());
913 }
914
915 #[test]
916 fn test_parse_information_elements() {
917 let data = [0, 4, b'T', b'e', b's', b't', 3, 1, 6];
920 let ies = parse_information_elements(&data);
921 assert_eq!(ies.len(), 2);
922 assert_eq!(ies[0].id, 0);
923 assert_eq!(ies[0].data, b"Test");
924 assert_eq!(ies[1].id, 3);
925 assert_eq!(ies[1].data, &[6]);
926 }
927
928 #[test]
929 fn test_extract_ssid() {
930 let ies = vec![
931 InformationElement {
932 id: 0,
933 data: b"MyNetwork".to_vec(),
934 },
935 InformationElement {
936 id: 3,
937 data: vec![11],
938 },
939 ];
940 let ssid = extract_ssid(&ies);
941 assert_eq!(ssid, Some(b"MyNetwork".to_vec()));
942 }
943
944 #[test]
945 fn test_extract_channel() {
946 let ies = vec![InformationElement {
947 id: 3,
948 data: vec![6],
949 }];
950 assert_eq!(extract_channel(&ies), Some(6));
951 }
952
953 #[test]
954 fn test_has_rsn() {
955 let ies_with_rsn = vec![InformationElement {
956 id: 48,
957 data: vec![1, 0],
958 }];
959 assert!(has_rsn(&ies_with_rsn));
960
961 let ies_without = vec![InformationElement {
962 id: 0,
963 data: vec![],
964 }];
965 assert!(!has_rsn(&ies_without));
966 }
967
968 #[test]
969 fn test_wifi_station_initial_state() {
970 let sta = WifiStation::new(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]));
971 assert_eq!(sta.state(), StaState::Disconnected);
972 assert!(sta.current_bss().is_none());
973 assert!(sta.scan_results().is_empty());
974 }
975
976 #[test]
977 fn test_wifi_station_start_scan() {
978 let mut sta = WifiStation::new(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]));
979 let probe = sta.start_scan();
980 assert_eq!(sta.state(), StaState::Scanning);
981 assert!(probe.len() >= Ieee80211Header::MIN_SIZE + 2 + 6);
983 }
984
985 #[test]
986 fn test_security_type_default() {
987 assert_eq!(SecurityType::default(), SecurityType::Open);
988 }
989}