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 #[must_use]
27 pub fn new(offset: usize) -> Self {
28 Self { offset }
29 }
30
31 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
33 if buf.len() < offset + BEACON_FIXED_LEN {
34 return Err(FieldError::BufferTooShort {
35 offset,
36 need: BEACON_FIXED_LEN,
37 have: buf.len().saturating_sub(offset),
38 });
39 }
40 Ok(())
41 }
42
43 pub fn timestamp(&self, buf: &[u8]) -> Result<u64, FieldError> {
45 let off = self.offset;
46 if buf.len() < off + 8 {
47 return Err(FieldError::BufferTooShort {
48 offset: off,
49 need: 8,
50 have: buf.len(),
51 });
52 }
53 Ok(u64::from_le_bytes([
54 buf[off],
55 buf[off + 1],
56 buf[off + 2],
57 buf[off + 3],
58 buf[off + 4],
59 buf[off + 5],
60 buf[off + 6],
61 buf[off + 7],
62 ]))
63 }
64
65 pub fn beacon_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
67 let off = self.offset + 8;
68 if buf.len() < off + 2 {
69 return Err(FieldError::BufferTooShort {
70 offset: off,
71 need: 2,
72 have: buf.len(),
73 });
74 }
75 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
76 }
77
78 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
80 let off = self.offset + 10;
81 if buf.len() < off + 2 {
82 return Err(FieldError::BufferTooShort {
83 offset: off,
84 need: 2,
85 have: buf.len(),
86 });
87 }
88 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
89 }
90
91 #[must_use]
93 pub fn ie_offset(&self) -> usize {
94 self.offset + BEACON_FIXED_LEN
95 }
96
97 #[must_use]
99 pub fn header_len(&self) -> usize {
100 BEACON_FIXED_LEN
101 }
102
103 #[must_use]
105 pub fn build(timestamp: u64, beacon_interval: u16, capability: u16) -> Vec<u8> {
106 let mut out = Vec::with_capacity(BEACON_FIXED_LEN);
107 out.extend_from_slice(×tamp.to_le_bytes());
108 out.extend_from_slice(&beacon_interval.to_le_bytes());
109 out.extend_from_slice(&capability.to_le_bytes());
110 out
111 }
112}
113
114#[derive(Debug, Clone)]
122pub struct Dot11ProbeReq {
123 pub offset: usize,
124}
125
126impl Dot11ProbeReq {
127 #[must_use]
128 pub fn new(offset: usize) -> Self {
129 Self { offset }
130 }
131
132 #[must_use]
134 pub fn ie_offset(&self) -> usize {
135 self.offset
136 }
137
138 #[must_use]
140 pub fn header_len(&self) -> usize {
141 0
142 }
143}
144
145#[derive(Debug, Clone)]
153pub struct Dot11ProbeResp {
154 pub offset: usize,
155}
156
157impl Dot11ProbeResp {
158 #[must_use]
159 pub fn new(offset: usize) -> Self {
160 Self { offset }
161 }
162
163 pub fn timestamp(&self, buf: &[u8]) -> Result<u64, FieldError> {
165 let off = self.offset;
166 if buf.len() < off + 8 {
167 return Err(FieldError::BufferTooShort {
168 offset: off,
169 need: 8,
170 have: buf.len(),
171 });
172 }
173 Ok(u64::from_le_bytes([
174 buf[off],
175 buf[off + 1],
176 buf[off + 2],
177 buf[off + 3],
178 buf[off + 4],
179 buf[off + 5],
180 buf[off + 6],
181 buf[off + 7],
182 ]))
183 }
184
185 pub fn beacon_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
187 let off = self.offset + 8;
188 if buf.len() < off + 2 {
189 return Err(FieldError::BufferTooShort {
190 offset: off,
191 need: 2,
192 have: buf.len(),
193 });
194 }
195 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
196 }
197
198 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
200 let off = self.offset + 10;
201 if buf.len() < off + 2 {
202 return Err(FieldError::BufferTooShort {
203 offset: off,
204 need: 2,
205 have: buf.len(),
206 });
207 }
208 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
209 }
210
211 #[must_use]
213 pub fn ie_offset(&self) -> usize {
214 self.offset + BEACON_FIXED_LEN
215 }
216
217 #[must_use]
219 pub fn header_len(&self) -> usize {
220 BEACON_FIXED_LEN
221 }
222
223 #[must_use]
225 pub fn build(timestamp: u64, beacon_interval: u16, capability: u16) -> Vec<u8> {
226 Dot11Beacon::build(timestamp, beacon_interval, capability)
227 }
228}
229
230#[derive(Debug, Clone)]
239pub struct Dot11Auth {
240 pub offset: usize,
241}
242
243pub const AUTH_FIXED_LEN: usize = 6;
244
245impl Dot11Auth {
246 #[must_use]
247 pub fn new(offset: usize) -> Self {
248 Self { offset }
249 }
250
251 pub fn validate(buf: &[u8], offset: usize) -> Result<(), FieldError> {
253 if buf.len() < offset + AUTH_FIXED_LEN {
254 return Err(FieldError::BufferTooShort {
255 offset,
256 need: AUTH_FIXED_LEN,
257 have: buf.len().saturating_sub(offset),
258 });
259 }
260 Ok(())
261 }
262
263 pub fn algo(&self, buf: &[u8]) -> Result<u16, FieldError> {
265 let off = self.offset;
266 if buf.len() < off + 2 {
267 return Err(FieldError::BufferTooShort {
268 offset: off,
269 need: 2,
270 have: buf.len(),
271 });
272 }
273 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
274 }
275
276 pub fn seqnum(&self, buf: &[u8]) -> Result<u16, FieldError> {
278 let off = self.offset + 2;
279 if buf.len() < off + 2 {
280 return Err(FieldError::BufferTooShort {
281 offset: off,
282 need: 2,
283 have: buf.len(),
284 });
285 }
286 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
287 }
288
289 pub fn status_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
291 let off = self.offset + 4;
292 if buf.len() < off + 2 {
293 return Err(FieldError::BufferTooShort {
294 offset: off,
295 need: 2,
296 have: buf.len(),
297 });
298 }
299 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
300 }
301
302 #[must_use]
304 pub fn ie_offset(&self) -> usize {
305 self.offset + AUTH_FIXED_LEN
306 }
307
308 #[must_use]
310 pub fn header_len(&self) -> usize {
311 AUTH_FIXED_LEN
312 }
313
314 #[must_use]
316 pub fn answers(&self, buf: &[u8], other: &Dot11Auth, other_buf: &[u8]) -> bool {
317 let self_algo = self.algo(buf).unwrap_or(0);
318 let other_algo = other.algo(other_buf).unwrap_or(0);
319 if self_algo != other_algo {
320 return false;
321 }
322 let self_seq = self.seqnum(buf).unwrap_or(0);
323 let other_seq = other.seqnum(other_buf).unwrap_or(0);
324 self_seq == other_seq + 1 || (self_algo == 3 && self_seq == other_seq)
325 }
326
327 #[must_use]
329 pub fn build(algo: u16, seqnum: u16, status_code: u16) -> Vec<u8> {
330 let mut out = Vec::with_capacity(AUTH_FIXED_LEN);
331 out.extend_from_slice(&algo.to_le_bytes());
332 out.extend_from_slice(&seqnum.to_le_bytes());
333 out.extend_from_slice(&status_code.to_le_bytes());
334 out
335 }
336}
337
338#[derive(Debug, Clone)]
346pub struct Dot11Deauth {
347 pub offset: usize,
348}
349
350pub const DEAUTH_FIXED_LEN: usize = 2;
351
352impl Dot11Deauth {
353 #[must_use]
354 pub fn new(offset: usize) -> Self {
355 Self { offset }
356 }
357
358 pub fn reason_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
360 let off = self.offset;
361 if buf.len() < off + 2 {
362 return Err(FieldError::BufferTooShort {
363 offset: off,
364 need: 2,
365 have: buf.len(),
366 });
367 }
368 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
369 }
370
371 #[must_use]
373 pub fn header_len(&self) -> usize {
374 DEAUTH_FIXED_LEN
375 }
376
377 #[must_use]
379 pub fn build(reason_code: u16) -> Vec<u8> {
380 reason_code.to_le_bytes().to_vec()
381 }
382}
383
384#[derive(Debug, Clone)]
392pub struct Dot11Disas {
393 pub offset: usize,
394}
395
396pub const DISAS_FIXED_LEN: usize = 2;
397
398impl Dot11Disas {
399 #[must_use]
400 pub fn new(offset: usize) -> Self {
401 Self { offset }
402 }
403
404 pub fn reason_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
406 let off = self.offset;
407 if buf.len() < off + 2 {
408 return Err(FieldError::BufferTooShort {
409 offset: off,
410 need: 2,
411 have: buf.len(),
412 });
413 }
414 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
415 }
416
417 #[must_use]
419 pub fn header_len(&self) -> usize {
420 DISAS_FIXED_LEN
421 }
422
423 #[must_use]
425 pub fn build(reason_code: u16) -> Vec<u8> {
426 reason_code.to_le_bytes().to_vec()
427 }
428}
429
430#[derive(Debug, Clone)]
439pub struct Dot11AssocReq {
440 pub offset: usize,
441}
442
443pub const ASSOC_REQ_FIXED_LEN: usize = 4;
444
445impl Dot11AssocReq {
446 #[must_use]
447 pub fn new(offset: usize) -> Self {
448 Self { offset }
449 }
450
451 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
453 let off = self.offset;
454 if buf.len() < off + 2 {
455 return Err(FieldError::BufferTooShort {
456 offset: off,
457 need: 2,
458 have: buf.len(),
459 });
460 }
461 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
462 }
463
464 pub fn listen_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
466 let off = self.offset + 2;
467 if buf.len() < off + 2 {
468 return Err(FieldError::BufferTooShort {
469 offset: off,
470 need: 2,
471 have: buf.len(),
472 });
473 }
474 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
475 }
476
477 #[must_use]
479 pub fn ie_offset(&self) -> usize {
480 self.offset + ASSOC_REQ_FIXED_LEN
481 }
482
483 #[must_use]
485 pub fn header_len(&self) -> usize {
486 ASSOC_REQ_FIXED_LEN
487 }
488
489 #[must_use]
491 pub fn build(capability: u16, listen_interval: u16) -> Vec<u8> {
492 let mut out = Vec::with_capacity(ASSOC_REQ_FIXED_LEN);
493 out.extend_from_slice(&capability.to_le_bytes());
494 out.extend_from_slice(&listen_interval.to_le_bytes());
495 out
496 }
497}
498
499#[derive(Debug, Clone)]
508pub struct Dot11AssocResp {
509 pub offset: usize,
510}
511
512pub const ASSOC_RESP_FIXED_LEN: usize = 6;
513
514impl Dot11AssocResp {
515 #[must_use]
516 pub fn new(offset: usize) -> Self {
517 Self { offset }
518 }
519
520 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
522 let off = self.offset;
523 if buf.len() < off + 2 {
524 return Err(FieldError::BufferTooShort {
525 offset: off,
526 need: 2,
527 have: buf.len(),
528 });
529 }
530 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
531 }
532
533 pub fn status_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
535 let off = self.offset + 2;
536 if buf.len() < off + 2 {
537 return Err(FieldError::BufferTooShort {
538 offset: off,
539 need: 2,
540 have: buf.len(),
541 });
542 }
543 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
544 }
545
546 pub fn aid(&self, buf: &[u8]) -> Result<u16, FieldError> {
548 let off = self.offset + 4;
549 if buf.len() < off + 2 {
550 return Err(FieldError::BufferTooShort {
551 offset: off,
552 need: 2,
553 have: buf.len(),
554 });
555 }
556 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
557 }
558
559 #[must_use]
561 pub fn ie_offset(&self) -> usize {
562 self.offset + ASSOC_RESP_FIXED_LEN
563 }
564
565 #[must_use]
567 pub fn header_len(&self) -> usize {
568 ASSOC_RESP_FIXED_LEN
569 }
570
571 #[must_use]
573 pub fn build(capability: u16, status_code: u16, aid: u16) -> Vec<u8> {
574 let mut out = Vec::with_capacity(ASSOC_RESP_FIXED_LEN);
575 out.extend_from_slice(&capability.to_le_bytes());
576 out.extend_from_slice(&status_code.to_le_bytes());
577 out.extend_from_slice(&aid.to_le_bytes());
578 out
579 }
580}
581
582#[derive(Debug, Clone)]
591pub struct Dot11ReassocReq {
592 pub offset: usize,
593}
594
595pub const REASSOC_REQ_FIXED_LEN: usize = 10;
596
597impl Dot11ReassocReq {
598 #[must_use]
599 pub fn new(offset: usize) -> Self {
600 Self { offset }
601 }
602
603 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
605 let off = self.offset;
606 if buf.len() < off + 2 {
607 return Err(FieldError::BufferTooShort {
608 offset: off,
609 need: 2,
610 have: buf.len(),
611 });
612 }
613 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
614 }
615
616 pub fn listen_interval(&self, buf: &[u8]) -> Result<u16, FieldError> {
618 let off = self.offset + 2;
619 if buf.len() < off + 2 {
620 return Err(FieldError::BufferTooShort {
621 offset: off,
622 need: 2,
623 have: buf.len(),
624 });
625 }
626 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
627 }
628
629 pub fn current_ap(&self, buf: &[u8]) -> Result<MacAddress, FieldError> {
631 let off = self.offset + 4;
632 if buf.len() < off + 6 {
633 return Err(FieldError::BufferTooShort {
634 offset: off,
635 need: 6,
636 have: buf.len(),
637 });
638 }
639 Ok(MacAddress::new([
640 buf[off],
641 buf[off + 1],
642 buf[off + 2],
643 buf[off + 3],
644 buf[off + 4],
645 buf[off + 5],
646 ]))
647 }
648
649 #[must_use]
651 pub fn ie_offset(&self) -> usize {
652 self.offset + REASSOC_REQ_FIXED_LEN
653 }
654
655 #[must_use]
657 pub fn header_len(&self) -> usize {
658 REASSOC_REQ_FIXED_LEN
659 }
660
661 #[must_use]
663 pub fn build(capability: u16, listen_interval: u16, current_ap: MacAddress) -> Vec<u8> {
664 let mut out = Vec::with_capacity(REASSOC_REQ_FIXED_LEN);
665 out.extend_from_slice(&capability.to_le_bytes());
666 out.extend_from_slice(&listen_interval.to_le_bytes());
667 out.extend_from_slice(current_ap.as_bytes());
668 out
669 }
670}
671
672#[derive(Debug, Clone)]
678pub struct Dot11ReassocResp {
679 pub offset: usize,
680}
681
682impl Dot11ReassocResp {
683 #[must_use]
684 pub fn new(offset: usize) -> Self {
685 Self { offset }
686 }
687
688 pub fn capability(&self, buf: &[u8]) -> Result<u16, FieldError> {
690 let off = self.offset;
691 if buf.len() < off + 2 {
692 return Err(FieldError::BufferTooShort {
693 offset: off,
694 need: 2,
695 have: buf.len(),
696 });
697 }
698 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
699 }
700
701 pub fn status_code(&self, buf: &[u8]) -> Result<u16, FieldError> {
703 let off = self.offset + 2;
704 if buf.len() < off + 2 {
705 return Err(FieldError::BufferTooShort {
706 offset: off,
707 need: 2,
708 have: buf.len(),
709 });
710 }
711 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
712 }
713
714 pub fn aid(&self, buf: &[u8]) -> Result<u16, FieldError> {
716 let off = self.offset + 4;
717 if buf.len() < off + 2 {
718 return Err(FieldError::BufferTooShort {
719 offset: off,
720 need: 2,
721 have: buf.len(),
722 });
723 }
724 Ok(u16::from_le_bytes([buf[off], buf[off + 1]]))
725 }
726
727 #[must_use]
729 pub fn ie_offset(&self) -> usize {
730 self.offset + ASSOC_RESP_FIXED_LEN
731 }
732
733 #[must_use]
735 pub fn header_len(&self) -> usize {
736 ASSOC_RESP_FIXED_LEN
737 }
738
739 #[must_use]
741 pub fn build(capability: u16, status_code: u16, aid: u16) -> Vec<u8> {
742 Dot11AssocResp::build(capability, status_code, aid)
743 }
744}
745
746#[derive(Debug, Clone)]
754pub struct Dot11Action {
755 pub offset: usize,
756}
757
758pub const ACTION_MIN_LEN: usize = 1;
759
760impl Dot11Action {
761 #[must_use]
762 pub fn new(offset: usize) -> Self {
763 Self { offset }
764 }
765
766 pub fn category(&self, buf: &[u8]) -> Result<u8, FieldError> {
768 let off = self.offset;
769 if buf.len() <= off {
770 return Err(FieldError::BufferTooShort {
771 offset: off,
772 need: 1,
773 have: buf.len(),
774 });
775 }
776 Ok(buf[off])
777 }
778
779 pub fn action_code(&self, buf: &[u8]) -> Result<u8, FieldError> {
781 let off = self.offset + 1;
782 if buf.len() <= off {
783 return Err(FieldError::BufferTooShort {
784 offset: off,
785 need: 1,
786 have: buf.len(),
787 });
788 }
789 Ok(buf[off])
790 }
791
792 #[must_use]
794 pub fn payload_offset(&self) -> usize {
795 self.offset + ACTION_MIN_LEN
796 }
797
798 #[must_use]
800 pub fn header_len(&self) -> usize {
801 ACTION_MIN_LEN
802 }
803
804 #[must_use]
806 pub fn build(category: u8) -> Vec<u8> {
807 vec![category]
808 }
809}
810
811#[derive(Debug, Clone)]
819pub struct Dot11ATIM {
820 pub offset: usize,
821}
822
823impl Dot11ATIM {
824 #[must_use]
825 pub fn new(offset: usize) -> Self {
826 Self { offset }
827 }
828
829 #[must_use]
830 pub fn header_len(&self) -> usize {
831 0
832 }
833}
834
835#[cfg(test)]
836mod tests {
837 use super::*;
838
839 #[test]
840 fn test_beacon_parse() {
841 let mut buf = vec![0u8; 12];
842 buf[0..8].copy_from_slice(&0x0102030405060708u64.to_le_bytes());
844 buf[8..10].copy_from_slice(&100u16.to_le_bytes());
846 buf[10..12].copy_from_slice(&0x0411u16.to_le_bytes());
848
849 let beacon = Dot11Beacon::new(0);
850 assert_eq!(beacon.timestamp(&buf).unwrap(), 0x0102030405060708);
851 assert_eq!(beacon.beacon_interval(&buf).unwrap(), 100);
852 assert_eq!(beacon.capability(&buf).unwrap(), 0x0411);
853 assert_eq!(beacon.ie_offset(), 12);
854 }
855
856 #[test]
857 fn test_beacon_build_roundtrip() {
858 let data = Dot11Beacon::build(0x1234567890ABCDEF, 100, 0x0411);
859 assert_eq!(data.len(), BEACON_FIXED_LEN);
860
861 let beacon = Dot11Beacon::new(0);
862 assert_eq!(beacon.timestamp(&data).unwrap(), 0x1234567890ABCDEF);
863 assert_eq!(beacon.beacon_interval(&data).unwrap(), 100);
864 assert_eq!(beacon.capability(&data).unwrap(), 0x0411);
865 }
866
867 #[test]
868 fn test_auth_parse() {
869 let mut buf = vec![0u8; 6];
870 buf[0..2].copy_from_slice(&0u16.to_le_bytes());
872 buf[2..4].copy_from_slice(&1u16.to_le_bytes());
874 buf[4..6].copy_from_slice(&0u16.to_le_bytes());
876
877 let auth = Dot11Auth::new(0);
878 assert_eq!(auth.algo(&buf).unwrap(), 0);
879 assert_eq!(auth.seqnum(&buf).unwrap(), 1);
880 assert_eq!(auth.status_code(&buf).unwrap(), 0);
881 }
882
883 #[test]
884 fn test_auth_build_roundtrip() {
885 let data = Dot11Auth::build(0, 1, 0);
886 assert_eq!(data.len(), AUTH_FIXED_LEN);
887
888 let auth = Dot11Auth::new(0);
889 assert_eq!(auth.algo(&data).unwrap(), 0);
890 assert_eq!(auth.seqnum(&data).unwrap(), 1);
891 assert_eq!(auth.status_code(&data).unwrap(), 0);
892 }
893
894 #[test]
895 fn test_auth_answers() {
896 let req = Dot11Auth::build(0, 1, 0);
897 let resp = Dot11Auth::build(0, 2, 0);
898
899 let req_auth = Dot11Auth::new(0);
900 let resp_auth = Dot11Auth::new(0);
901
902 assert!(resp_auth.answers(&resp, &req_auth, &req));
903 assert!(!req_auth.answers(&req, &resp_auth, &resp));
904 }
905
906 #[test]
907 fn test_deauth_parse() {
908 let buf = 1u16.to_le_bytes().to_vec();
909 let deauth = Dot11Deauth::new(0);
910 assert_eq!(deauth.reason_code(&buf).unwrap(), 1);
911 }
912
913 #[test]
914 fn test_deauth_build_roundtrip() {
915 let data = Dot11Deauth::build(4);
916 let deauth = Dot11Deauth::new(0);
917 assert_eq!(deauth.reason_code(&data).unwrap(), 4);
918 }
919
920 #[test]
921 fn test_disas_parse() {
922 let buf = 5u16.to_le_bytes().to_vec();
923 let disas = Dot11Disas::new(0);
924 assert_eq!(disas.reason_code(&buf).unwrap(), 5);
925 }
926
927 #[test]
928 fn test_assoc_req_parse() {
929 let mut buf = vec![0u8; 4];
930 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);
934 assert_eq!(assoc.capability(&buf).unwrap(), 0x0411);
935 assert_eq!(assoc.listen_interval(&buf).unwrap(), 200);
936 }
937
938 #[test]
939 fn test_assoc_req_build_roundtrip() {
940 let data = Dot11AssocReq::build(0x0411, 200);
941 let assoc = Dot11AssocReq::new(0);
942 assert_eq!(assoc.capability(&data).unwrap(), 0x0411);
943 assert_eq!(assoc.listen_interval(&data).unwrap(), 200);
944 }
945
946 #[test]
947 fn test_assoc_resp_parse() {
948 let mut buf = vec![0u8; 6];
949 buf[0..2].copy_from_slice(&0x0411u16.to_le_bytes());
950 buf[2..4].copy_from_slice(&0u16.to_le_bytes());
951 buf[4..6].copy_from_slice(&1u16.to_le_bytes());
952
953 let assoc = Dot11AssocResp::new(0);
954 assert_eq!(assoc.capability(&buf).unwrap(), 0x0411);
955 assert_eq!(assoc.status_code(&buf).unwrap(), 0);
956 assert_eq!(assoc.aid(&buf).unwrap(), 1);
957 }
958
959 #[test]
960 fn test_reassoc_req_parse() {
961 let mut buf = vec![0u8; 10];
962 buf[0..2].copy_from_slice(&0x0411u16.to_le_bytes());
963 buf[2..4].copy_from_slice(&200u16.to_le_bytes());
964 buf[4..10].copy_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
965
966 let reassoc = Dot11ReassocReq::new(0);
967 assert_eq!(reassoc.capability(&buf).unwrap(), 0x0411);
968 assert_eq!(reassoc.listen_interval(&buf).unwrap(), 200);
969 assert_eq!(
970 reassoc.current_ap(&buf).unwrap(),
971 MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF])
972 );
973 }
974
975 #[test]
976 fn test_reassoc_req_build_roundtrip() {
977 let ap = MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
978 let data = Dot11ReassocReq::build(0x0411, 200, ap);
979 assert_eq!(data.len(), REASSOC_REQ_FIXED_LEN);
980
981 let reassoc = Dot11ReassocReq::new(0);
982 assert_eq!(reassoc.current_ap(&data).unwrap(), ap);
983 }
984
985 #[test]
986 fn test_action_parse() {
987 let buf = vec![0x00u8, 0x04]; let action = Dot11Action::new(0);
989 assert_eq!(action.category(&buf).unwrap(), 0x00);
990 assert_eq!(action.action_code(&buf).unwrap(), 0x04);
991 }
992
993 #[test]
994 fn test_action_build() {
995 let data = Dot11Action::build(0x0A); assert_eq!(data.len(), 1);
997 assert_eq!(data[0], 0x0A);
998 }
999
1000 #[test]
1001 fn test_probe_req() {
1002 let req = Dot11ProbeReq::new(0);
1003 assert_eq!(req.header_len(), 0);
1004 assert_eq!(req.ie_offset(), 0);
1005 }
1006
1007 #[test]
1008 fn test_probe_resp_parse() {
1009 let mut buf = vec![0u8; 12];
1010 buf[0..8].copy_from_slice(&1000u64.to_le_bytes());
1011 buf[8..10].copy_from_slice(&100u16.to_le_bytes());
1012 buf[10..12].copy_from_slice(&0x0001u16.to_le_bytes());
1013
1014 let resp = Dot11ProbeResp::new(0);
1015 assert_eq!(resp.timestamp(&buf).unwrap(), 1000);
1016 assert_eq!(resp.beacon_interval(&buf).unwrap(), 100);
1017 assert_eq!(resp.capability(&buf).unwrap(), 0x0001);
1018 }
1019
1020 #[test]
1021 fn test_reassoc_resp() {
1022 let data = Dot11ReassocResp::build(0x0411, 0, 1);
1023 let resp = Dot11ReassocResp::new(0);
1024 assert_eq!(resp.capability(&data).unwrap(), 0x0411);
1025 assert_eq!(resp.status_code(&data).unwrap(), 0);
1026 assert_eq!(resp.aid(&data).unwrap(), 1);
1027 }
1028}