1use crate::layer::field::{FieldError, MacAddress};
8
9#[derive(Debug, Clone)]
18pub struct Dot11Beacon {
19 pub offset: usize,
20}
21
22pub const BEACON_FIXED_LEN: usize = 12;
24
25impl Dot11Beacon {
26 pub fn new(offset: usize) -> Self {
27 Self { offset }
28 }
29
30 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
32 if buf.len() < offset + BEACON_FIXED_LEN {
33 return Err(FieldError::BufferTooShort {
34 offset,
35 need: BEACON_FIXED_LEN,
36 have: buf.len().saturating_sub(offset),
37 });
38 }
39 Ok(())
40 }
41
42 pub fn timestamp(&self, buf: &[u8]) -> Result<u64, FieldError> {
44 let off = self.offset;
45 if buf.len() < off + 8 {
46 return Err(FieldError::BufferTooShort {
47 offset: off,
48 need: 8,
49 have: buf.len(),
50 });
51 }
52 Ok(u64::from_le_bytes([
53 buf[off],
54 buf[off + 1],
55 buf[off + 2],
56 buf[off + 3],
57 buf[off + 4],
58 buf[off + 5],
59 buf[off + 6],
60 buf[off + 7],
61 ]))
62 }
63
64 pub fn beacon_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
66 let off = self.offset + 8;
67 if buf.len() < off + 2 {
68 return Err(FieldError::BufferTooShort {
69 offset: off,
70 need: 2,
71 have: buf.len(),
72 });
73 }
74 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
75 }
76
77 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
79 let off = self.offset + 10;
80 if buf.len() < off + 2 {
81 return Err(FieldError::BufferTooShort {
82 offset: off,
83 need: 2,
84 have: buf.len(),
85 });
86 }
87 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
88 }
89
90 pub fn ie_offset(&self) -> usize {
92 self.offset + BEACON_FIXED_LEN
93 }
94
95 pub fn header_len(&self) -> usize {
97 BEACON_FIXED_LEN
98 }
99
100 pub fn build(timestamp: u64, beacon_interval: u16, capability: u16) -> Vec<u8> {
102 let mut out = Vec::with_capacity(BEACON_FIXED_LEN);
103 out.extend_from_slice(×tamp.to_le_bytes());
104 out.extend_from_slice(&beacon_interval.to_le_bytes());
105 out.extend_from_slice(&capability.to_le_bytes());
106 out
107 }
108}
109
110#[derive(Debug, Clone)]
118pub struct Dot11ProbeReq {
119 pub offset: usize,
120}
121
122impl Dot11ProbeReq {
123 pub fn new(offset: usize) -> Self {
124 Self { offset }
125 }
126
127 pub fn ie_offset(&self) -> usize {
129 self.offset
130 }
131
132 pub fn header_len(&self) -> usize {
134 0
135 }
136}
137
138#[derive(Debug, Clone)]
146pub struct Dot11ProbeResp {
147 pub offset: usize,
148}
149
150impl Dot11ProbeResp {
151 pub fn new(offset: usize) -> Self {
152 Self { offset }
153 }
154
155 pub fn timestamp(&self, buf: &[u8]) -> Result<u64, FieldError> {
157 let off = self.offset;
158 if buf.len() < off + 8 {
159 return Err(FieldError::BufferTooShort {
160 offset: off,
161 need: 8,
162 have: buf.len(),
163 });
164 }
165 Ok(u64::from_le_bytes([
166 buf[off],
167 buf[off + 1],
168 buf[off + 2],
169 buf[off + 3],
170 buf[off + 4],
171 buf[off + 5],
172 buf[off + 6],
173 buf[off + 7],
174 ]))
175 }
176
177 pub fn beacon_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
179 let off = self.offset + 8;
180 if buf.len() < off + 2 {
181 return Err(FieldError::BufferTooShort {
182 offset: off,
183 need: 2,
184 have: buf.len(),
185 });
186 }
187 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
188 }
189
190 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
192 let off = self.offset + 10;
193 if buf.len() < off + 2 {
194 return Err(FieldError::BufferTooShort {
195 offset: off,
196 need: 2,
197 have: buf.len(),
198 });
199 }
200 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
201 }
202
203 pub fn ie_offset(&self) -> usize {
205 self.offset + BEACON_FIXED_LEN
206 }
207
208 pub fn header_len(&self) -> usize {
210 BEACON_FIXED_LEN
211 }
212
213 pub fn build(timestamp: u64, beacon_interval: u16, capability: u16) -> Vec<u8> {
215 Dot11Beacon::build(timestamp, beacon_interval, capability)
216 }
217}
218
219#[derive(Debug, Clone)]
228pub struct Dot11Auth {
229 pub offset: usize,
230}
231
232pub const AUTH_FIXED_LEN: usize = 6;
233
234impl Dot11Auth {
235 pub fn new(offset: usize) -> Self {
236 Self { offset }
237 }
238
239 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
241 if buf.len() < offset + AUTH_FIXED_LEN {
242 return Err(FieldError::BufferTooShort {
243 offset,
244 need: AUTH_FIXED_LEN,
245 have: buf.len().saturating_sub(offset),
246 });
247 }
248 Ok(())
249 }
250
251 pub fn algo(&self, buf: &[u8]) -> Result<u16, FieldError> {
253 let off = self.offset;
254 if buf.len() < off + 2 {
255 return Err(FieldError::BufferTooShort {
256 offset: off,
257 need: 2,
258 have: buf.len(),
259 });
260 }
261 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
262 }
263
264 pub fn seqnum(&self, buf: &[u8]) -> Result<u16, FieldError> {
266 let off = self.offset + 2;
267 if buf.len() < off + 2 {
268 return Err(FieldError::BufferTooShort {
269 offset: off,
270 need: 2,
271 have: buf.len(),
272 });
273 }
274 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
275 }
276
277 pub fn status_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
279 let off = self.offset + 4;
280 if buf.len() < off + 2 {
281 return Err(FieldError::BufferTooShort {
282 offset: off,
283 need: 2,
284 have: buf.len(),
285 });
286 }
287 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
288 }
289
290 pub fn ie_offset(&self) -> usize {
292 self.offset + AUTH_FIXED_LEN
293 }
294
295 pub fn header_len(&self) -> usize {
297 AUTH_FIXED_LEN
298 }
299
300 pub fn answers(&self, buf: &[u8], other: &Dot11Auth, other_buf: &[u8]) -> bool {
302 let self_algo = self.algo(buf).unwrap_or(0);
303 let other_algo = other.algo(other_buf).unwrap_or(0);
304 if self_algo != other_algo {
305 return false;
306 }
307 let self_seq = self.seqnum(buf).unwrap_or(0);
308 let other_seq = other.seqnum(other_buf).unwrap_or(0);
309 self_seq == other_seq + 1 || (self_algo == 3 && self_seq == other_seq)
310 }
311
312 pub fn build(algo: u16, seqnum: u16, status_code: u16) -> Vec<u8> {
314 let mut out = Vec::with_capacity(AUTH_FIXED_LEN);
315 out.extend_from_slice(&algo.to_le_bytes());
316 out.extend_from_slice(&seqnum.to_le_bytes());
317 out.extend_from_slice(&status_code.to_le_bytes());
318 out
319 }
320}
321
322#[derive(Debug, Clone)]
330pub struct Dot11Deauth {
331 pub offset: usize,
332}
333
334pub const DEAUTH_FIXED_LEN: usize = 2;
335
336impl Dot11Deauth {
337 pub fn new(offset: usize) -> Self {
338 Self { offset }
339 }
340
341 pub fn reason_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
343 let off = self.offset;
344 if buf.len() < off + 2 {
345 return Err(FieldError::BufferTooShort {
346 offset: off,
347 need: 2,
348 have: buf.len(),
349 });
350 }
351 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
352 }
353
354 pub fn header_len(&self) -> usize {
356 DEAUTH_FIXED_LEN
357 }
358
359 pub fn build(reason_code: u16) -> Vec<u8> {
361 reason_code.to_le_bytes().to_vec()
362 }
363}
364
365#[derive(Debug, Clone)]
373pub struct Dot11Disas {
374 pub offset: usize,
375}
376
377pub const DISAS_FIXED_LEN: usize = 2;
378
379impl Dot11Disas {
380 pub fn new(offset: usize) -> Self {
381 Self { offset }
382 }
383
384 pub fn reason_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
386 let off = self.offset;
387 if buf.len() < off + 2 {
388 return Err(FieldError::BufferTooShort {
389 offset: off,
390 need: 2,
391 have: buf.len(),
392 });
393 }
394 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
395 }
396
397 pub fn header_len(&self) -> usize {
399 DISAS_FIXED_LEN
400 }
401
402 pub fn build(reason_code: u16) -> Vec<u8> {
404 reason_code.to_le_bytes().to_vec()
405 }
406}
407
408#[derive(Debug, Clone)]
417pub struct Dot11AssocReq {
418 pub offset: usize,
419}
420
421pub const ASSOC_REQ_FIXED_LEN: usize = 4;
422
423impl Dot11AssocReq {
424 pub fn new(offset: usize) -> Self {
425 Self { offset }
426 }
427
428 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
430 let off = self.offset;
431 if buf.len() < off + 2 {
432 return Err(FieldError::BufferTooShort {
433 offset: off,
434 need: 2,
435 have: buf.len(),
436 });
437 }
438 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
439 }
440
441 pub fn listen_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
443 let off = self.offset + 2;
444 if buf.len() < off + 2 {
445 return Err(FieldError::BufferTooShort {
446 offset: off,
447 need: 2,
448 have: buf.len(),
449 });
450 }
451 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
452 }
453
454 pub fn ie_offset(&self) -> usize {
456 self.offset + ASSOC_REQ_FIXED_LEN
457 }
458
459 pub fn header_len(&self) -> usize {
461 ASSOC_REQ_FIXED_LEN
462 }
463
464 pub fn build(capability: u16, listen_interval: u16) -> Vec<u8> {
466 let mut out = Vec::with_capacity(ASSOC_REQ_FIXED_LEN);
467 out.extend_from_slice(&capability.to_le_bytes());
468 out.extend_from_slice(&listen_interval.to_le_bytes());
469 out
470 }
471}
472
473#[derive(Debug, Clone)]
482pub struct Dot11AssocResp {
483 pub offset: usize,
484}
485
486pub const ASSOC_RESP_FIXED_LEN: usize = 6;
487
488impl Dot11AssocResp {
489 pub fn new(offset: usize) -> Self {
490 Self { offset }
491 }
492
493 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
495 let off = self.offset;
496 if buf.len() < off + 2 {
497 return Err(FieldError::BufferTooShort {
498 offset: off,
499 need: 2,
500 have: buf.len(),
501 });
502 }
503 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
504 }
505
506 pub fn status_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
508 let off = self.offset + 2;
509 if buf.len() < off + 2 {
510 return Err(FieldError::BufferTooShort {
511 offset: off,
512 need: 2,
513 have: buf.len(),
514 });
515 }
516 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
517 }
518
519 pub fn aid(&self, buf: &[u8]) -> Result<u16, FieldError> {
521 let off = self.offset + 4;
522 if buf.len() < off + 2 {
523 return Err(FieldError::BufferTooShort {
524 offset: off,
525 need: 2,
526 have: buf.len(),
527 });
528 }
529 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
530 }
531
532 pub fn ie_offset(&self) -> usize {
534 self.offset + ASSOC_RESP_FIXED_LEN
535 }
536
537 pub fn header_len(&self) -> usize {
539 ASSOC_RESP_FIXED_LEN
540 }
541
542 pub fn build(capability: u16, status_code: u16, aid: u16) -> Vec<u8> {
544 let mut out = Vec::with_capacity(ASSOC_RESP_FIXED_LEN);
545 out.extend_from_slice(&capability.to_le_bytes());
546 out.extend_from_slice(&status_code.to_le_bytes());
547 out.extend_from_slice(&aid.to_le_bytes());
548 out
549 }
550}
551
552#[derive(Debug, Clone)]
561pub struct Dot11ReassocReq {
562 pub offset: usize,
563}
564
565pub const REASSOC_REQ_FIXED_LEN: usize = 10;
566
567impl Dot11ReassocReq {
568 pub fn new(offset: usize) -> Self {
569 Self { offset }
570 }
571
572 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
574 let off = self.offset;
575 if buf.len() < off + 2 {
576 return Err(FieldError::BufferTooShort {
577 offset: off,
578 need: 2,
579 have: buf.len(),
580 });
581 }
582 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
583 }
584
585 pub fn listen_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
587 let off = self.offset + 2;
588 if buf.len() < off + 2 {
589 return Err(FieldError::BufferTooShort {
590 offset: off,
591 need: 2,
592 have: buf.len(),
593 });
594 }
595 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
596 }
597
598 pub fn current_ap(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
600 let off = self.offset + 4;
601 if buf.len() < off + 6 {
602 return Err(FieldError::BufferTooShort {
603 offset: off,
604 need: 6,
605 have: buf.len(),
606 });
607 }
608 Ok(MacAddress::new([
609 buf[off],
610 buf[off + 1],
611 buf[off + 2],
612 buf[off + 3],
613 buf[off + 4],
614 buf[off + 5],
615 ]))
616 }
617
618 pub fn ie_offset(&self) -> usize {
620 self.offset + REASSOC_REQ_FIXED_LEN
621 }
622
623 pub fn header_len(&self) -> usize {
625 REASSOC_REQ_FIXED_LEN
626 }
627
628 pub fn build(capability: u16, listen_interval: u16, current_ap: MacAddress) -> Vec<u8> {
630 let mut out = Vec::with_capacity(REASSOC_REQ_FIXED_LEN);
631 out.extend_from_slice(&capability.to_le_bytes());
632 out.extend_from_slice(&listen_interval.to_le_bytes());
633 out.extend_from_slice(current_ap.as_bytes());
634 out
635 }
636}
637
638#[derive(Debug, Clone)]
644pub struct Dot11ReassocResp {
645 pub offset: usize,
646}
647
648impl Dot11ReassocResp {
649 pub fn new(offset: usize) -> Self {
650 Self { offset }
651 }
652
653 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
655 let off = self.offset;
656 if buf.len() < off + 2 {
657 return Err(FieldError::BufferTooShort {
658 offset: off,
659 need: 2,
660 have: buf.len(),
661 });
662 }
663 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
664 }
665
666 pub fn status_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
668 let off = self.offset + 2;
669 if buf.len() < off + 2 {
670 return Err(FieldError::BufferTooShort {
671 offset: off,
672 need: 2,
673 have: buf.len(),
674 });
675 }
676 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
677 }
678
679 pub fn aid(&self, buf: &[u8]) -> Result<u16, FieldError> {
681 let off = self.offset + 4;
682 if buf.len() < off + 2 {
683 return Err(FieldError::BufferTooShort {
684 offset: off,
685 need: 2,
686 have: buf.len(),
687 });
688 }
689 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
690 }
691
692 pub fn ie_offset(&self) -> usize {
694 self.offset + ASSOC_RESP_FIXED_LEN
695 }
696
697 pub fn header_len(&self) -> usize {
699 ASSOC_RESP_FIXED_LEN
700 }
701
702 pub fn build(capability: u16, status_code: u16, aid: u16) -> Vec<u8> {
704 Dot11AssocResp::build(capability, status_code, aid)
705 }
706}
707
708#[derive(Debug, Clone)]
716pub struct Dot11Action {
717 pub offset: usize,
718}
719
720pub const ACTION_MIN_LEN: usize = 1;
721
722impl Dot11Action {
723 pub fn new(offset: usize) -> Self {
724 Self { offset }
725 }
726
727 pub fn category(&self, buf: &[u8]) -> Result<u8, FieldError> {
729 let off = self.offset;
730 if buf.len() <= off {
731 return Err(FieldError::BufferTooShort {
732 offset: off,
733 need: 1,
734 have: buf.len(),
735 });
736 }
737 Ok(buf[off])
738 }
739
740 pub fn action_code(&self, buf: &[u8]) -> Result<u8, FieldError> {
742 let off = self.offset + 1;
743 if buf.len() <= off {
744 return Err(FieldError::BufferTooShort {
745 offset: off,
746 need: 1,
747 have: buf.len(),
748 });
749 }
750 Ok(buf[off])
751 }
752
753 pub fn payload_offset(&self) -> usize {
755 self.offset + ACTION_MIN_LEN
756 }
757
758 pub fn header_len(&self) -> usize {
760 ACTION_MIN_LEN
761 }
762
763 pub fn build(category: u8) -> Vec<u8> {
765 vec![category]
766 }
767}
768
769#[derive(Debug, Clone)]
777pub struct Dot11ATIM {
778 pub offset: usize,
779}
780
781impl Dot11ATIM {
782 pub fn new(offset: usize) -> Self {
783 Self { offset }
784 }
785
786 pub fn header_len(&self) -> usize {
787 0
788 }
789}
790
791#[cfg(test)]
792mod tests {
793 use super::*;
794
795 #[test]
796 fn test_beacon_parse() {
797 let mut buf = vec![0u8; 12];
798 buf[0..8].copy_from_slice(&0x0102030405060708u64.to_le_bytes());
800 buf[8..10].copy_from_slice(&100u16.to_le_bytes());
802 buf[10..12].copy_from_slice(&0x0411u16.to_le_bytes());
804
805 let beacon = Dot11Beacon::new(0);
806 assert_eq!(beacon.timestamp(&buf).unwrap(), 0x0102030405060708);
807 assert_eq!(beacon.beacon_interval(&buf).unwrap(), 100);
808 assert_eq!(beacon.capability(&buf).unwrap(), 0x0411);
809 assert_eq!(beacon.ie_offset(), 12);
810 }
811
812 #[test]
813 fn test_beacon_build_roundtrip() {
814 let data = Dot11Beacon::build(0x1234567890ABCDEF, 100, 0x0411);
815 assert_eq!(data.len(), BEACON_FIXED_LEN);
816
817 let beacon = Dot11Beacon::new(0);
818 assert_eq!(beacon.timestamp(&data).unwrap(), 0x1234567890ABCDEF);
819 assert_eq!(beacon.beacon_interval(&data).unwrap(), 100);
820 assert_eq!(beacon.capability(&data).unwrap(), 0x0411);
821 }
822
823 #[test]
824 fn test_auth_parse() {
825 let mut buf = vec![0u8; 6];
826 buf[0..2].copy_from_slice(&0u16.to_le_bytes());
828 buf[2..4].copy_from_slice(&1u16.to_le_bytes());
830 buf[4..6].copy_from_slice(&0u16.to_le_bytes());
832
833 let auth = Dot11Auth::new(0);
834 assert_eq!(auth.algo(&buf).unwrap(), 0);
835 assert_eq!(auth.seqnum(&buf).unwrap(), 1);
836 assert_eq!(auth.status_code(&buf).unwrap(), 0);
837 }
838
839 #[test]
840 fn test_auth_build_roundtrip() {
841 let data = Dot11Auth::build(0, 1, 0);
842 assert_eq!(data.len(), AUTH_FIXED_LEN);
843
844 let auth = Dot11Auth::new(0);
845 assert_eq!(auth.algo(&data).unwrap(), 0);
846 assert_eq!(auth.seqnum(&data).unwrap(), 1);
847 assert_eq!(auth.status_code(&data).unwrap(), 0);
848 }
849
850 #[test]
851 fn test_auth_answers() {
852 let req = Dot11Auth::build(0, 1, 0);
853 let resp = Dot11Auth::build(0, 2, 0);
854
855 let req_auth = Dot11Auth::new(0);
856 let resp_auth = Dot11Auth::new(0);
857
858 assert!(resp_auth.answers(&resp, &req_auth, &req));
859 assert!(!req_auth.answers(&req, &resp_auth, &resp));
860 }
861
862 #[test]
863 fn test_deauth_parse() {
864 let buf = 1u16.to_le_bytes().to_vec();
865 let deauth = Dot11Deauth::new(0);
866 assert_eq!(deauth.reason_code(&buf).unwrap(), 1);
867 }
868
869 #[test]
870 fn test_deauth_build_roundtrip() {
871 let data = Dot11Deauth::build(4);
872 let deauth = Dot11Deauth::new(0);
873 assert_eq!(deauth.reason_code(&data).unwrap(), 4);
874 }
875
876 #[test]
877 fn test_disas_parse() {
878 let buf = 5u16.to_le_bytes().to_vec();
879 let disas = Dot11Disas::new(0);
880 assert_eq!(disas.reason_code(&buf).unwrap(), 5);
881 }
882
883 #[test]
884 fn test_assoc_req_parse() {
885 let mut buf = vec![0u8; 4];
886 buf[0..2].copy_from_slice(&0x0411u16.to_le_bytes()); buf[2..4].copy_from_slice(&200u16.to_le_bytes()); let assoc = Dot11AssocReq::new(0);
890 assert_eq!(assoc.capability(&buf).unwrap(), 0x0411);
891 assert_eq!(assoc.listen_interval(&buf).unwrap(), 200);
892 }
893
894 #[test]
895 fn test_assoc_req_build_roundtrip() {
896 let data = Dot11AssocReq::build(0x0411, 200);
897 let assoc = Dot11AssocReq::new(0);
898 assert_eq!(assoc.capability(&data).unwrap(), 0x0411);
899 assert_eq!(assoc.listen_interval(&data).unwrap(), 200);
900 }
901
902 #[test]
903 fn test_assoc_resp_parse() {
904 let mut buf = vec![0u8; 6];
905 buf[0..2].copy_from_slice(&0x0411u16.to_le_bytes());
906 buf[2..4].copy_from_slice(&0u16.to_le_bytes());
907 buf[4..6].copy_from_slice(&1u16.to_le_bytes());
908
909 let assoc = Dot11AssocResp::new(0);
910 assert_eq!(assoc.capability(&buf).unwrap(), 0x0411);
911 assert_eq!(assoc.status_code(&buf).unwrap(), 0);
912 assert_eq!(assoc.aid(&buf).unwrap(), 1);
913 }
914
915 #[test]
916 fn test_reassoc_req_parse() {
917 let mut buf = vec![0u8; 10];
918 buf[0..2].copy_from_slice(&0x0411u16.to_le_bytes());
919 buf[2..4].copy_from_slice(&200u16.to_le_bytes());
920 buf[4..10].copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
921
922 let reassoc = Dot11ReassocReq::new(0);
923 assert_eq!(reassoc.capability(&buf).unwrap(), 0x0411);
924 assert_eq!(reassoc.listen_interval(&buf).unwrap(), 200);
925 assert_eq!(
926 reassoc.current_ap(&buf).unwrap(),
927 MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF])
928 );
929 }
930
931 #[test]
932 fn test_reassoc_req_build_roundtrip() {
933 let ap = MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
934 let data = Dot11ReassocReq::build(0x0411, 200, ap);
935 assert_eq!(data.len(), REASSOC_REQ_FIXED_LEN);
936
937 let reassoc = Dot11ReassocReq::new(0);
938 assert_eq!(reassoc.current_ap(&data).unwrap(), ap);
939 }
940
941 #[test]
942 fn test_action_parse() {
943 let buf = vec![0x00u8, 0x04]; let action = Dot11Action::new(0);
945 assert_eq!(action.category(&buf).unwrap(), 0x00);
946 assert_eq!(action.action_code(&buf).unwrap(), 0x04);
947 }
948
949 #[test]
950 fn test_action_build() {
951 let data = Dot11Action::build(0x0A); assert_eq!(data.len(), 1);
953 assert_eq!(data[0], 0x0A);
954 }
955
956 #[test]
957 fn test_probe_req() {
958 let req = Dot11ProbeReq::new(0);
959 assert_eq!(req.header_len(), 0);
960 assert_eq!(req.ie_offset(), 0);
961 }
962
963 #[test]
964 fn test_probe_resp_parse() {
965 let mut buf = vec![0u8; 12];
966 buf[0..8].copy_from_slice(&1000u64.to_le_bytes());
967 buf[8..10].copy_from_slice(&100u16.to_le_bytes());
968 buf[10..12].copy_from_slice(&0x0001u16.to_le_bytes());
969
970 let resp = Dot11ProbeResp::new(0);
971 assert_eq!(resp.timestamp(&buf).unwrap(), 1000);
972 assert_eq!(resp.beacon_interval(&buf).unwrap(), 100);
973 assert_eq!(resp.capability(&buf).unwrap(), 0x0001);
974 }
975
976 #[test]
977 fn test_reassoc_resp() {
978 let data = Dot11ReassocResp::build(0x0411, 0, 1);
979 let resp = Dot11ReassocResp::new(0);
980 assert_eq!(resp.capability(&data).unwrap(), 0x0411);
981 assert_eq!(resp.status_code(&data).unwrap(), 0);
982 assert_eq!(resp.aid(&data).unwrap(), 1);
983 }
984}