1use super::management::{
7 Dot11AssocReq, Dot11AssocResp, Dot11Auth, Dot11Beacon, Dot11Deauth, Dot11ProbeResp,
8};
9use super::{DOT11_MGMT_HEADER_LEN, DOT11_WDS_HEADER_LEN, build_frame_control, crc32_ieee, types};
10use crate::layer::dot11::data::Dot11QoS;
11use crate::layer::dot11::ie::Dot11Elt;
12use crate::layer::field::MacAddress;
13
14#[derive(Debug, Clone)]
31pub struct Dot11Builder {
32 pub proto: u8,
34 pub frame_type: u8,
36 pub subtype: u8,
38 pub flags: u8,
40 pub duration: u16,
42 pub addr1: MacAddress,
44 pub addr2: MacAddress,
46 pub addr3: MacAddress,
48 pub addr4: Option<MacAddress>,
50 pub seq_ctrl: u16,
52 pub body: Vec<u8>,
54 pub with_fcs: bool,
56}
57
58impl Default for Dot11Builder {
59 fn default() -> Self {
60 Self {
61 proto: 0,
62 frame_type: types::frame_type::MANAGEMENT,
63 subtype: 0,
64 flags: 0,
65 duration: 0,
66 addr1: MacAddress::BROADCAST,
67 addr2: MacAddress::ZERO,
68 addr3: MacAddress::ZERO,
69 addr4: None,
70 seq_ctrl: 0,
71 body: Vec::new(),
72 with_fcs: false,
73 }
74 }
75}
76
77impl Dot11Builder {
78 #[must_use]
80 pub fn new() -> Self {
81 Self::default()
82 }
83
84 #[must_use]
86 pub fn proto(mut self, proto: u8) -> Self {
87 self.proto = proto;
88 self
89 }
90
91 #[must_use]
93 pub fn frame_type(mut self, ft: u8) -> Self {
94 self.frame_type = ft;
95 self
96 }
97
98 #[must_use]
100 pub fn subtype(mut self, st: u8) -> Self {
101 self.subtype = st;
102 self
103 }
104
105 #[must_use]
107 pub fn flags(mut self, flags: u8) -> Self {
108 self.flags = flags;
109 self
110 }
111
112 #[must_use]
114 pub fn to_ds(mut self, val: bool) -> Self {
115 if val {
116 self.flags |= types::fc_flags::TO_DS;
117 } else {
118 self.flags &= !types::fc_flags::TO_DS;
119 }
120 self
121 }
122
123 #[must_use]
125 pub fn from_ds(mut self, val: bool) -> Self {
126 if val {
127 self.flags |= types::fc_flags::FROM_DS;
128 } else {
129 self.flags &= !types::fc_flags::FROM_DS;
130 }
131 self
132 }
133
134 #[must_use]
136 pub fn retry(mut self, val: bool) -> Self {
137 if val {
138 self.flags |= types::fc_flags::RETRY;
139 } else {
140 self.flags &= !types::fc_flags::RETRY;
141 }
142 self
143 }
144
145 #[must_use]
147 pub fn protected(mut self, val: bool) -> Self {
148 if val {
149 self.flags |= types::fc_flags::PROTECTED;
150 } else {
151 self.flags &= !types::fc_flags::PROTECTED;
152 }
153 self
154 }
155
156 #[must_use]
158 pub fn duration(mut self, dur: u16) -> Self {
159 self.duration = dur;
160 self
161 }
162
163 #[must_use]
165 pub fn addr1(mut self, mac: MacAddress) -> Self {
166 self.addr1 = mac;
167 self
168 }
169
170 #[must_use]
172 pub fn addr2(mut self, mac: MacAddress) -> Self {
173 self.addr2 = mac;
174 self
175 }
176
177 #[must_use]
179 pub fn addr3(mut self, mac: MacAddress) -> Self {
180 self.addr3 = mac;
181 self
182 }
183
184 #[must_use]
186 pub fn addr4(mut self, mac: MacAddress) -> Self {
187 self.addr4 = Some(mac);
188 self
189 }
190
191 #[must_use]
193 pub fn seq_ctrl(mut self, sc: u16) -> Self {
194 self.seq_ctrl = sc;
195 self
196 }
197
198 #[must_use]
200 pub fn seq_num(mut self, seq: u16, frag: u8) -> Self {
201 self.seq_ctrl = ((seq & 0x0FFF) << 4) | u16::from(frag & 0x0F);
202 self
203 }
204
205 #[must_use]
207 pub fn body(mut self, body: Vec<u8>) -> Self {
208 self.body = body;
209 self
210 }
211
212 #[must_use]
214 pub fn with_fcs(mut self, enable: bool) -> Self {
215 self.with_fcs = enable;
216 self
217 }
218
219 #[must_use]
221 pub fn header_size(&self) -> usize {
222 if self.addr4.is_some() {
223 DOT11_WDS_HEADER_LEN
224 } else {
225 match self.frame_type {
226 types::frame_type::CONTROL => match self.subtype {
227 types::ctrl_subtype::ACK | types::ctrl_subtype::CTS => 10,
228 _ => 16,
229 },
230 _ => DOT11_MGMT_HEADER_LEN,
231 }
232 }
233 }
234
235 #[must_use]
237 pub fn build(&self) -> Vec<u8> {
238 let header_len = self.header_size();
239 let total = header_len + self.body.len() + if self.with_fcs { 4 } else { 0 };
240 let mut buf = vec![0u8; total];
241
242 let fc = build_frame_control(self.proto, self.frame_type, self.subtype, self.flags);
244 buf[0..2].copy_from_slice(&fc.to_le_bytes());
245
246 buf[2..4].copy_from_slice(&self.duration.to_le_bytes());
248
249 buf[4..10].copy_from_slice(self.addr1.as_bytes());
251
252 if header_len >= 16 {
254 buf[10..16].copy_from_slice(self.addr2.as_bytes());
255 }
256
257 if header_len >= 24 {
259 buf[16..22].copy_from_slice(self.addr3.as_bytes());
260 buf[22..24].copy_from_slice(&self.seq_ctrl.to_le_bytes());
261 }
262
263 if let Some(ref a4) = self.addr4
265 && header_len >= 30
266 {
267 buf[24..30].copy_from_slice(a4.as_bytes());
268 }
269
270 if !self.body.is_empty() {
272 buf[header_len..header_len + self.body.len()].copy_from_slice(&self.body);
273 }
274
275 if self.with_fcs {
277 let fcs_offset = header_len + self.body.len();
278 let fcs = crc32_ieee(&buf[0..fcs_offset]);
279 buf[fcs_offset..fcs_offset + 4].copy_from_slice(&fcs.to_le_bytes());
280 }
281
282 buf
283 }
284
285 #[must_use]
291 pub fn beacon(bssid: MacAddress) -> Self {
292 Self::new()
293 .frame_type(types::frame_type::MANAGEMENT)
294 .subtype(types::mgmt_subtype::BEACON)
295 .addr1(MacAddress::BROADCAST)
296 .addr2(bssid)
297 .addr3(bssid)
298 }
299
300 #[must_use]
302 pub fn probe_request(src: MacAddress) -> Self {
303 Self::new()
304 .frame_type(types::frame_type::MANAGEMENT)
305 .subtype(types::mgmt_subtype::PROBE_REQ)
306 .addr1(MacAddress::BROADCAST)
307 .addr2(src)
308 .addr3(MacAddress::BROADCAST)
309 }
310
311 #[must_use]
313 pub fn probe_response(dst: MacAddress, bssid: MacAddress) -> Self {
314 Self::new()
315 .frame_type(types::frame_type::MANAGEMENT)
316 .subtype(types::mgmt_subtype::PROBE_RESP)
317 .addr1(dst)
318 .addr2(bssid)
319 .addr3(bssid)
320 }
321
322 #[must_use]
324 pub fn authentication(dst: MacAddress, src: MacAddress, bssid: MacAddress) -> Self {
325 Self::new()
326 .frame_type(types::frame_type::MANAGEMENT)
327 .subtype(types::mgmt_subtype::AUTH)
328 .addr1(dst)
329 .addr2(src)
330 .addr3(bssid)
331 }
332
333 #[must_use]
335 pub fn deauthentication(dst: MacAddress, src: MacAddress, bssid: MacAddress) -> Self {
336 Self::new()
337 .frame_type(types::frame_type::MANAGEMENT)
338 .subtype(types::mgmt_subtype::DEAUTH)
339 .addr1(dst)
340 .addr2(src)
341 .addr3(bssid)
342 }
343
344 #[must_use]
346 pub fn assoc_request(dst: MacAddress, src: MacAddress) -> Self {
347 Self::new()
348 .frame_type(types::frame_type::MANAGEMENT)
349 .subtype(types::mgmt_subtype::ASSOC_REQ)
350 .addr1(dst)
351 .addr2(src)
352 .addr3(dst)
353 }
354
355 #[must_use]
357 pub fn ack(dst: MacAddress) -> Self {
358 Self::new()
359 .frame_type(types::frame_type::CONTROL)
360 .subtype(types::ctrl_subtype::ACK)
361 .addr1(dst)
362 }
363
364 #[must_use]
366 pub fn rts(dst: MacAddress, src: MacAddress) -> Self {
367 Self::new()
368 .frame_type(types::frame_type::CONTROL)
369 .subtype(types::ctrl_subtype::RTS)
370 .addr1(dst)
371 .addr2(src)
372 }
373
374 #[must_use]
376 pub fn cts(dst: MacAddress) -> Self {
377 Self::new()
378 .frame_type(types::frame_type::CONTROL)
379 .subtype(types::ctrl_subtype::CTS)
380 .addr1(dst)
381 }
382
383 #[must_use]
385 pub fn data_to_ap(bssid: MacAddress, src: MacAddress, dst: MacAddress) -> Self {
386 Self::new()
387 .frame_type(types::frame_type::DATA)
388 .subtype(types::data_subtype::DATA)
389 .to_ds(true)
390 .addr1(bssid)
391 .addr2(src)
392 .addr3(dst)
393 }
394
395 #[must_use]
397 pub fn data_from_ap(dst: MacAddress, bssid: MacAddress, src: MacAddress) -> Self {
398 Self::new()
399 .frame_type(types::frame_type::DATA)
400 .subtype(types::data_subtype::DATA)
401 .from_ds(true)
402 .addr1(dst)
403 .addr2(bssid)
404 .addr3(src)
405 }
406
407 #[must_use]
409 pub fn qos_data_to_ap(bssid: MacAddress, src: MacAddress, dst: MacAddress) -> Self {
410 Self::new()
411 .frame_type(types::frame_type::DATA)
412 .subtype(types::data_subtype::QOS_DATA)
413 .to_ds(true)
414 .addr1(bssid)
415 .addr2(src)
416 .addr3(dst)
417 }
418
419 #[must_use]
421 pub fn data_wds(ra: MacAddress, ta: MacAddress, da: MacAddress, sa: MacAddress) -> Self {
422 Self::new()
423 .frame_type(types::frame_type::DATA)
424 .subtype(types::data_subtype::DATA)
425 .to_ds(true)
426 .from_ds(true)
427 .addr1(ra)
428 .addr2(ta)
429 .addr3(da)
430 .addr4(sa)
431 }
432
433 #[must_use]
439 pub fn build_beacon(
440 bssid: MacAddress,
441 timestamp: u64,
442 beacon_interval: u16,
443 capability: u16,
444 ies: &[Dot11Elt],
445 ) -> Vec<u8> {
446 let mut body = Dot11Beacon::build(timestamp, beacon_interval, capability);
447 body.extend(Dot11Elt::build_chain(ies));
448 Self::beacon(bssid).body(body).build()
449 }
450
451 #[must_use]
453 pub fn build_probe_request(src: MacAddress, ies: &[Dot11Elt]) -> Vec<u8> {
454 let body = Dot11Elt::build_chain(ies);
455 Self::probe_request(src).body(body).build()
456 }
457
458 #[must_use]
460 pub fn build_probe_response(
461 dst: MacAddress,
462 bssid: MacAddress,
463 timestamp: u64,
464 beacon_interval: u16,
465 capability: u16,
466 ies: &[Dot11Elt],
467 ) -> Vec<u8> {
468 let mut body = Dot11ProbeResp::build(timestamp, beacon_interval, capability);
469 body.extend(Dot11Elt::build_chain(ies));
470 Self::probe_response(dst, bssid).body(body).build()
471 }
472
473 #[must_use]
475 pub fn build_auth(
476 dst: MacAddress,
477 src: MacAddress,
478 bssid: MacAddress,
479 algo: u16,
480 seqnum: u16,
481 status: u16,
482 ) -> Vec<u8> {
483 let body = Dot11Auth::build(algo, seqnum, status);
484 Self::authentication(dst, src, bssid).body(body).build()
485 }
486
487 #[must_use]
489 pub fn build_deauth(
490 dst: MacAddress,
491 src: MacAddress,
492 bssid: MacAddress,
493 reason: u16,
494 ) -> Vec<u8> {
495 let body = Dot11Deauth::build(reason);
496 Self::deauthentication(dst, src, bssid).body(body).build()
497 }
498
499 #[must_use]
501 pub fn build_assoc_request(
502 dst: MacAddress,
503 src: MacAddress,
504 capability: u16,
505 listen_interval: u16,
506 ies: &[Dot11Elt],
507 ) -> Vec<u8> {
508 let mut body = Dot11AssocReq::build(capability, listen_interval);
509 body.extend(Dot11Elt::build_chain(ies));
510 Self::assoc_request(dst, src).body(body).build()
511 }
512
513 #[must_use]
515 pub fn build_assoc_response(
516 dst: MacAddress,
517 bssid: MacAddress,
518 capability: u16,
519 status: u16,
520 aid: u16,
521 ies: &[Dot11Elt],
522 ) -> Vec<u8> {
523 let mut body = Dot11AssocResp::build(capability, status, aid);
524 body.extend(Dot11Elt::build_chain(ies));
525 Self::new()
526 .frame_type(types::frame_type::MANAGEMENT)
527 .subtype(types::mgmt_subtype::ASSOC_RESP)
528 .addr1(dst)
529 .addr2(bssid)
530 .addr3(bssid)
531 .body(body)
532 .build()
533 }
534
535 #[must_use]
537 pub fn build_qos_data(
538 bssid: MacAddress,
539 src: MacAddress,
540 dst: MacAddress,
541 tid: u8,
542 payload: &[u8],
543 ) -> Vec<u8> {
544 let mut body = Dot11QoS::build(tid, false, 0, false, 0);
545 body.extend_from_slice(payload);
546 Self::qos_data_to_ap(bssid, src, dst).body(body).build()
547 }
548}
549
550#[cfg(test)]
555mod tests {
556 use super::*;
557 use crate::layer::dot11::Dot11Layer;
558
559 #[test]
560 fn test_builder_default() {
561 let builder = Dot11Builder::new();
562 assert_eq!(builder.frame_type, types::frame_type::MANAGEMENT);
563 assert_eq!(builder.subtype, 0);
564 assert_eq!(builder.flags, 0);
565 assert_eq!(builder.duration, 0);
566 assert_eq!(builder.addr1, MacAddress::BROADCAST);
567 assert!(!builder.with_fcs);
568 }
569
570 #[test]
571 fn test_builder_beacon() {
572 let bssid = MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
573 let frame = Dot11Builder::beacon(bssid).build();
574
575 assert_eq!(frame.len(), DOT11_MGMT_HEADER_LEN);
576
577 let layer = Dot11Layer::new(0, frame.len());
578 assert_eq!(
579 layer.frame_type(&frame).unwrap(),
580 types::frame_type::MANAGEMENT
581 );
582 assert_eq!(layer.subtype(&frame).unwrap(), types::mgmt_subtype::BEACON);
583 assert!(layer.addr1(&frame).unwrap().is_broadcast());
584 assert_eq!(layer.addr2(&frame).unwrap(), bssid);
585 assert_eq!(layer.addr3(&frame).unwrap(), bssid);
586 }
587
588 #[test]
589 fn test_builder_ack() {
590 let dst = MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
591 let frame = Dot11Builder::ack(dst).build();
592
593 assert_eq!(frame.len(), 10);
594
595 let layer = Dot11Layer::new(0, frame.len());
596 assert_eq!(
597 layer.frame_type(&frame).unwrap(),
598 types::frame_type::CONTROL
599 );
600 assert_eq!(layer.subtype(&frame).unwrap(), types::ctrl_subtype::ACK);
601 assert_eq!(layer.addr1(&frame).unwrap(), dst);
602 }
603
604 #[test]
605 fn test_builder_rts() {
606 let dst = MacAddress::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
607 let src = MacAddress::new([0x11, 0x22, 0x33, 0x44, 0x55, 0x66]);
608 let frame = Dot11Builder::rts(dst, src).build();
609
610 assert_eq!(frame.len(), 16);
611
612 let layer = Dot11Layer::new(0, frame.len());
613 assert_eq!(
614 layer.frame_type(&frame).unwrap(),
615 types::frame_type::CONTROL
616 );
617 assert_eq!(layer.subtype(&frame).unwrap(), types::ctrl_subtype::RTS);
618 assert_eq!(layer.addr1(&frame).unwrap(), dst);
619 assert_eq!(layer.addr2(&frame).unwrap(), src);
620 }
621
622 #[test]
623 fn test_builder_wds_data() {
624 let ra = MacAddress::new([0x01; 6]);
625 let ta = MacAddress::new([0x02; 6]);
626 let da = MacAddress::new([0x03; 6]);
627 let sa = MacAddress::new([0x04; 6]);
628 let frame = Dot11Builder::data_wds(ra, ta, da, sa).build();
629
630 assert_eq!(frame.len(), DOT11_WDS_HEADER_LEN);
631
632 let layer = Dot11Layer::new(0, frame.len());
633 assert_eq!(layer.frame_type(&frame).unwrap(), types::frame_type::DATA);
634 assert!(layer.to_ds(&frame).unwrap());
635 assert!(layer.from_ds(&frame).unwrap());
636 assert!(layer.has_addr4(&frame));
637 assert_eq!(layer.addr1(&frame).unwrap(), ra);
638 assert_eq!(layer.addr2(&frame).unwrap(), ta);
639 assert_eq!(layer.addr3(&frame).unwrap(), da);
640 assert_eq!(layer.addr4(&frame).unwrap(), sa);
641 }
642
643 #[test]
644 fn test_builder_with_body() {
645 let bssid = MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
646 let body = vec![0xAA, 0xBB, 0xCC];
647 let frame = Dot11Builder::beacon(bssid).body(body.clone()).build();
648
649 assert_eq!(frame.len(), DOT11_MGMT_HEADER_LEN + 3);
650 assert_eq!(&frame[DOT11_MGMT_HEADER_LEN..], &[0xAA, 0xBB, 0xCC]);
651 }
652
653 #[test]
654 fn test_builder_with_fcs() {
655 let bssid = MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
656 let frame = Dot11Builder::beacon(bssid).with_fcs(true).build();
657
658 assert_eq!(frame.len(), DOT11_MGMT_HEADER_LEN + 4); let data = &frame[..DOT11_MGMT_HEADER_LEN];
662 let expected_fcs = crc32_ieee(data);
663 let actual_fcs = u32::from_le_bytes([
664 frame[DOT11_MGMT_HEADER_LEN],
665 frame[DOT11_MGMT_HEADER_LEN + 1],
666 frame[DOT11_MGMT_HEADER_LEN + 2],
667 frame[DOT11_MGMT_HEADER_LEN + 3],
668 ]);
669 assert_eq!(actual_fcs, expected_fcs);
670 }
671
672 #[test]
673 fn test_builder_flags() {
674 let frame = Dot11Builder::new()
675 .frame_type(types::frame_type::DATA)
676 .subtype(0)
677 .to_ds(true)
678 .retry(true)
679 .protected(true)
680 .build();
681
682 let layer = Dot11Layer::new(0, frame.len());
683 assert!(layer.to_ds(&frame).unwrap());
684 assert!(!layer.from_ds(&frame).unwrap());
685 assert!(layer.retry(&frame).unwrap());
686 assert!(layer.protected(&frame).unwrap());
687 }
688
689 #[test]
690 fn test_builder_seq_num() {
691 let frame = Dot11Builder::new().seq_num(100, 3).build();
692
693 let layer = Dot11Layer::new(0, frame.len());
694 assert_eq!(layer.sequence_num(&frame).unwrap(), 100);
695 assert_eq!(layer.fragment_num(&frame).unwrap(), 3);
696 }
697
698 #[test]
699 fn test_build_beacon_convenience() {
700 let bssid = MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
701 let ies = vec![
702 Dot11Elt::ssid("TestNetwork"),
703 Dot11Elt::new(types::ie_id::RATES, vec![0x82, 0x84, 0x8B, 0x96]),
704 Dot11Elt::new(types::ie_id::DS_PARAMETER_SET, vec![6]),
705 ];
706
707 let frame = Dot11Builder::build_beacon(bssid, 0, 100, 0x0431, &ies);
708
709 let layer = Dot11Layer::new(0, frame.len());
710 assert_eq!(
711 layer.frame_type(&frame).unwrap(),
712 types::frame_type::MANAGEMENT
713 );
714 assert_eq!(layer.subtype(&frame).unwrap(), types::mgmt_subtype::BEACON);
715
716 let body_offset = DOT11_MGMT_HEADER_LEN;
718 assert!(frame.len() > body_offset + 12);
720 let bi = u16::from_le_bytes([frame[body_offset + 8], frame[body_offset + 9]]);
722 assert_eq!(bi, 100);
723 }
724
725 #[test]
726 fn test_build_auth_convenience() {
727 let dst = MacAddress::new([0xAA; 6]);
728 let src = MacAddress::new([0xBB; 6]);
729 let bssid = MacAddress::new([0xAA; 6]);
730
731 let frame = Dot11Builder::build_auth(dst, src, bssid, 0, 1, 0);
732
733 let layer = Dot11Layer::new(0, frame.len());
734 assert_eq!(layer.subtype(&frame).unwrap(), types::mgmt_subtype::AUTH);
735
736 let body_offset = DOT11_MGMT_HEADER_LEN;
738 let algo = u16::from_le_bytes([frame[body_offset], frame[body_offset + 1]]);
739 let seqnum = u16::from_le_bytes([frame[body_offset + 2], frame[body_offset + 3]]);
740 let status = u16::from_le_bytes([frame[body_offset + 4], frame[body_offset + 5]]);
741 assert_eq!(algo, 0);
742 assert_eq!(seqnum, 1);
743 assert_eq!(status, 0);
744 }
745
746 #[test]
747 fn test_build_deauth_convenience() {
748 let dst = MacAddress::BROADCAST;
749 let src = MacAddress::new([0xBB; 6]);
750 let bssid = MacAddress::new([0xBB; 6]);
751
752 let frame = Dot11Builder::build_deauth(dst, src, bssid, 7);
753
754 let layer = Dot11Layer::new(0, frame.len());
755 assert_eq!(layer.subtype(&frame).unwrap(), types::mgmt_subtype::DEAUTH);
756
757 let body_offset = DOT11_MGMT_HEADER_LEN;
758 let reason = u16::from_le_bytes([frame[body_offset], frame[body_offset + 1]]);
759 assert_eq!(reason, 7);
760 }
761
762 #[test]
763 fn test_build_probe_request_convenience() {
764 let src = MacAddress::new([0xCC; 6]);
765 let ies = vec![
766 Dot11Elt::ssid(""), Dot11Elt::new(types::ie_id::RATES, vec![0x82, 0x84]),
768 ];
769
770 let frame = Dot11Builder::build_probe_request(src, &ies);
771
772 let layer = Dot11Layer::new(0, frame.len());
773 assert_eq!(
774 layer.subtype(&frame).unwrap(),
775 types::mgmt_subtype::PROBE_REQ
776 );
777 assert!(layer.addr1(&frame).unwrap().is_broadcast());
778 assert_eq!(layer.addr2(&frame).unwrap(), src);
779
780 let ie_data = &frame[DOT11_MGMT_HEADER_LEN..];
782 let ies_parsed = Dot11Elt::parse_all(ie_data, 0);
783 assert_eq!(ies_parsed.len(), 2);
784 assert_eq!(ies_parsed[0].id, 0);
785 }
786
787 #[test]
788 fn test_build_qos_data_convenience() {
789 let bssid = MacAddress::new([0xAA; 6]);
790 let src = MacAddress::new([0xBB; 6]);
791 let dst = MacAddress::new([0xCC; 6]);
792 let payload = b"hello";
793
794 let frame = Dot11Builder::build_qos_data(bssid, src, dst, 3, payload);
795
796 let layer = Dot11Layer::new(0, frame.len());
797 assert_eq!(layer.frame_type(&frame).unwrap(), types::frame_type::DATA);
798 assert_eq!(
799 layer.subtype(&frame).unwrap(),
800 types::data_subtype::QOS_DATA
801 );
802 assert!(layer.to_ds(&frame).unwrap());
803
804 let qos = Dot11QoS::new(DOT11_MGMT_HEADER_LEN);
806 assert_eq!(qos.tid(&frame).unwrap(), 3);
807
808 let payload_offset = DOT11_MGMT_HEADER_LEN + 2;
810 assert_eq!(&frame[payload_offset..payload_offset + 5], b"hello");
811 }
812
813 #[test]
814 fn test_header_size_calculation() {
815 assert_eq!(
816 Dot11Builder::beacon(MacAddress::BROADCAST).header_size(),
817 24
818 );
819 assert_eq!(Dot11Builder::ack(MacAddress::BROADCAST).header_size(), 10);
820 assert_eq!(
821 Dot11Builder::rts(MacAddress::BROADCAST, MacAddress::ZERO).header_size(),
822 16
823 );
824 assert_eq!(
825 Dot11Builder::data_wds(
826 MacAddress::ZERO,
827 MacAddress::ZERO,
828 MacAddress::ZERO,
829 MacAddress::ZERO
830 )
831 .header_size(),
832 30
833 );
834 }
835}