1use crate::layer::dot11::types;
11use crate::layer::field::FieldError;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct Dot11Elt {
25 pub id: u8,
27 pub len: u8,
29 pub info: Vec<u8>,
31}
32
33impl Dot11Elt {
34 pub fn new(id: u8, info: Vec<u8>) -> Self {
36 Self {
37 id,
38 len: info.len() as u8,
39 info,
40 }
41 }
42
43 pub fn parse(buf: &[u8], offset: usize) -> Result<(Self, usize), FieldError> {
46 if buf.len() < offset + 2 {
47 return Err(FieldError::BufferTooShort {
48 offset,
49 need: 2,
50 have: buf.len().saturating_sub(offset),
51 });
52 }
53 let id = buf[offset];
54 let len = buf[offset + 1] as usize;
55 if buf.len() < offset + 2 + len {
56 return Err(FieldError::BufferTooShort {
57 offset: offset + 2,
58 need: len,
59 have: buf.len().saturating_sub(offset + 2),
60 });
61 }
62 let info = buf[offset + 2..offset + 2 + len].to_vec();
63 Ok((
64 Self {
65 id,
66 len: len as u8,
67 info,
68 },
69 2 + len,
70 ))
71 }
72
73 pub fn parse_all(buf: &[u8], mut offset: usize) -> Vec<Self> {
76 let mut elements = Vec::new();
77 while offset < buf.len() {
78 match Self::parse(buf, offset) {
79 Ok((elt, consumed)) => {
80 offset += consumed;
81 elements.push(elt);
82 }
83 Err(_) => break,
84 }
85 }
86 elements
87 }
88
89 pub fn build(&self) -> Vec<u8> {
91 let mut buf = Vec::with_capacity(2 + self.info.len());
92 buf.push(self.id);
93 buf.push(self.len);
94 buf.extend_from_slice(&self.info);
95 buf
96 }
97
98 pub fn build_chain(elements: &[Dot11Elt]) -> Vec<u8> {
100 let total: usize = elements.iter().map(|e| 2 + e.info.len()).sum();
101 let mut buf = Vec::with_capacity(total);
102 for elt in elements {
103 buf.extend(elt.build());
104 }
105 buf
106 }
107
108 pub fn ssid(name: &str) -> Self {
110 Self::new(types::ie_id::SSID, name.as_bytes().to_vec())
111 }
112
113 pub fn ssid_hidden() -> Self {
115 Self::new(types::ie_id::SSID, Vec::new())
116 }
117
118 pub fn is_ssid(&self) -> bool {
120 self.id == types::ie_id::SSID
121 }
122
123 pub fn ssid_str(&self) -> Option<String> {
125 if self.id == types::ie_id::SSID {
126 Some(String::from_utf8_lossy(&self.info).into_owned())
127 } else {
128 None
129 }
130 }
131
132 pub fn name(&self) -> &'static str {
134 types::ie_id::name(self.id)
135 }
136
137 pub fn wire_len(&self) -> usize {
139 2 + self.info.len()
140 }
141}
142
143#[derive(Debug, Clone, PartialEq, Eq)]
149pub struct Dot11EltSSID {
150 pub ssid: String,
152}
153
154impl Dot11EltSSID {
155 pub fn new(ssid: &str) -> Self {
157 Self {
158 ssid: ssid.to_string(),
159 }
160 }
161
162 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
164 if elt.id != types::ie_id::SSID {
165 return None;
166 }
167 Some(Self {
168 ssid: String::from_utf8_lossy(&elt.info).into_owned(),
169 })
170 }
171
172 pub fn build(&self) -> Dot11Elt {
174 Dot11Elt::new(types::ie_id::SSID, self.ssid.as_bytes().to_vec())
175 }
176
177 pub fn is_hidden(&self) -> bool {
179 self.ssid.is_empty()
180 }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq)]
191pub struct Dot11EltRates {
192 pub rates: Vec<u8>,
194}
195
196impl Dot11EltRates {
197 pub fn new(rates: Vec<u8>) -> Self {
199 Self { rates }
200 }
201
202 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
204 if elt.id != types::ie_id::RATES {
205 return None;
206 }
207 Some(Self {
208 rates: elt.info.clone(),
209 })
210 }
211
212 pub fn build(&self) -> Dot11Elt {
214 Dot11Elt::new(types::ie_id::RATES, self.rates.clone())
215 }
216
217 pub fn rate_mbps(rate_byte: u8) -> f32 {
219 (rate_byte & 0x7F) as f32 * 0.5
220 }
221
222 pub fn is_basic(rate_byte: u8) -> bool {
224 rate_byte & 0x80 != 0
225 }
226
227 pub fn rates_mbps(&self) -> Vec<f32> {
229 self.rates.iter().map(|&r| Self::rate_mbps(r)).collect()
230 }
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
241pub struct Dot11EltDSSSet {
242 pub channel: u8,
244}
245
246impl Dot11EltDSSSet {
247 pub fn new(channel: u8) -> Self {
249 Self { channel }
250 }
251
252 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
254 if elt.id != types::ie_id::DS_PARAMETER_SET || elt.info.is_empty() {
255 return None;
256 }
257 Some(Self {
258 channel: elt.info[0],
259 })
260 }
261
262 pub fn build(&self) -> Dot11Elt {
264 Dot11Elt::new(types::ie_id::DS_PARAMETER_SET, vec![self.channel])
265 }
266}
267
268#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct Dot11EltTIM {
275 pub dtim_count: u8,
277 pub dtim_period: u8,
279 pub bitmap_control: u8,
281 pub bitmap: Vec<u8>,
283}
284
285impl Dot11EltTIM {
286 pub fn new(dtim_count: u8, dtim_period: u8, bitmap_control: u8, bitmap: Vec<u8>) -> Self {
288 Self {
289 dtim_count,
290 dtim_period,
291 bitmap_control,
292 bitmap,
293 }
294 }
295
296 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
298 if elt.id != types::ie_id::TIM || elt.info.len() < 3 {
299 return None;
300 }
301 Some(Self {
302 dtim_count: elt.info[0],
303 dtim_period: elt.info[1],
304 bitmap_control: elt.info[2],
305 bitmap: elt.info[3..].to_vec(),
306 })
307 }
308
309 pub fn build(&self) -> Dot11Elt {
311 let mut info = Vec::with_capacity(3 + self.bitmap.len());
312 info.push(self.dtim_count);
313 info.push(self.dtim_period);
314 info.push(self.bitmap_control);
315 info.extend_from_slice(&self.bitmap);
316 Dot11Elt::new(types::ie_id::TIM, info)
317 }
318}
319
320#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct CountryTriplet {
327 pub first_channel: u8,
329 pub num_channels: u8,
331 pub max_power: u8,
333}
334
335#[derive(Debug, Clone, PartialEq, Eq)]
337pub struct Dot11EltCountry {
338 pub country: [u8; 3],
340 pub triplets: Vec<CountryTriplet>,
342}
343
344impl Dot11EltCountry {
345 pub fn new(country: [u8; 3], triplets: Vec<CountryTriplet>) -> Self {
347 Self { country, triplets }
348 }
349
350 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
352 if elt.id != types::ie_id::COUNTRY || elt.info.len() < 3 {
353 return None;
354 }
355 let mut country = [0u8; 3];
356 country.copy_from_slice(&elt.info[0..3]);
357
358 let mut triplets = Vec::new();
359 let mut pos = 3;
360 while pos + 3 <= elt.info.len() {
361 triplets.push(CountryTriplet {
362 first_channel: elt.info[pos],
363 num_channels: elt.info[pos + 1],
364 max_power: elt.info[pos + 2],
365 });
366 pos += 3;
367 }
368
369 Some(Self { country, triplets })
370 }
371
372 pub fn build(&self) -> Dot11Elt {
374 let mut info = Vec::with_capacity(3 + self.triplets.len() * 3);
375 info.extend_from_slice(&self.country);
376 for t in &self.triplets {
377 info.push(t.first_channel);
378 info.push(t.num_channels);
379 info.push(t.max_power);
380 }
381 Dot11Elt::new(types::ie_id::COUNTRY, info)
382 }
383
384 pub fn country_str(&self) -> String {
386 String::from_utf8_lossy(&self.country).into_owned()
387 }
388}
389
390#[derive(Debug, Clone, PartialEq, Eq)]
396pub struct Dot11EltCSA {
397 pub mode: u8,
399 pub new_channel: u8,
401 pub count: u8,
403}
404
405impl Dot11EltCSA {
406 pub fn new(mode: u8, new_channel: u8, count: u8) -> Self {
408 Self {
409 mode,
410 new_channel,
411 count,
412 }
413 }
414
415 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
417 if elt.id != types::ie_id::CHANNEL_SWITCH_ANNOUNCEMENT || elt.info.len() < 3 {
418 return None;
419 }
420 Some(Self {
421 mode: elt.info[0],
422 new_channel: elt.info[1],
423 count: elt.info[2],
424 })
425 }
426
427 pub fn build(&self) -> Dot11Elt {
429 Dot11Elt::new(
430 types::ie_id::CHANNEL_SWITCH_ANNOUNCEMENT,
431 vec![self.mode, self.new_channel, self.count],
432 )
433 }
434}
435
436#[derive(Debug, Clone, PartialEq, Eq)]
444pub struct Dot11EltHTCapabilities {
445 pub ht_cap_info: u16,
447 pub ampdu_params: u8,
449 pub mcs_set: [u8; 16],
451 pub ht_ext_cap: u16,
453 pub txbf_cap: u32,
455 pub asel_cap: u8,
457}
458
459pub const HT_CAP_LEN: usize = 26;
461
462impl Dot11EltHTCapabilities {
463 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
465 if elt.id != types::ie_id::HT_CAPABILITIES || elt.info.len() < HT_CAP_LEN {
466 return None;
467 }
468 let d = &elt.info;
469 let ht_cap_info = u16::from_le_bytes([d[0], d[1]]);
470 let ampdu_params = d[2];
471 let mut mcs_set = [0u8; 16];
472 mcs_set.copy_from_slice(&d[3..19]);
473 let ht_ext_cap = u16::from_le_bytes([d[19], d[20]]);
474 let txbf_cap = u32::from_le_bytes([d[21], d[22], d[23], d[24]]);
475 let asel_cap = d[25];
476
477 Some(Self {
478 ht_cap_info,
479 ampdu_params,
480 mcs_set,
481 ht_ext_cap,
482 txbf_cap,
483 asel_cap,
484 })
485 }
486
487 pub fn build(&self) -> Dot11Elt {
489 let mut info = Vec::with_capacity(HT_CAP_LEN);
490 info.extend_from_slice(&self.ht_cap_info.to_le_bytes());
491 info.push(self.ampdu_params);
492 info.extend_from_slice(&self.mcs_set);
493 info.extend_from_slice(&self.ht_ext_cap.to_le_bytes());
494 info.extend_from_slice(&self.txbf_cap.to_le_bytes());
495 info.push(self.asel_cap);
496 Dot11Elt::new(types::ie_id::HT_CAPABILITIES, info)
497 }
498
499 pub fn ldpc(&self) -> bool {
501 self.ht_cap_info & 0x0001 != 0
502 }
503
504 pub fn channel_width_set(&self) -> bool {
506 self.ht_cap_info & 0x0002 != 0
507 }
508
509 pub fn short_gi_20(&self) -> bool {
511 self.ht_cap_info & 0x0020 != 0
512 }
513
514 pub fn short_gi_40(&self) -> bool {
516 self.ht_cap_info & 0x0040 != 0
517 }
518}
519
520#[derive(Debug, Clone, PartialEq, Eq)]
526pub struct Dot11EltHTInfo {
527 pub primary_channel: u8,
529 pub ht_info: [u8; 5],
531 pub basic_mcs_set: [u8; 16],
533}
534
535pub const HT_INFO_LEN: usize = 22;
537
538impl Dot11EltHTInfo {
539 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
541 if elt.id != types::ie_id::HT_INFORMATION || elt.info.len() < HT_INFO_LEN {
542 return None;
543 }
544 let d = &elt.info;
545 let primary_channel = d[0];
546 let mut ht_info = [0u8; 5];
547 ht_info.copy_from_slice(&d[1..6]);
548 let mut basic_mcs_set = [0u8; 16];
549 basic_mcs_set.copy_from_slice(&d[6..22]);
550
551 Some(Self {
552 primary_channel,
553 ht_info,
554 basic_mcs_set,
555 })
556 }
557
558 pub fn build(&self) -> Dot11Elt {
560 let mut info = Vec::with_capacity(HT_INFO_LEN);
561 info.push(self.primary_channel);
562 info.extend_from_slice(&self.ht_info);
563 info.extend_from_slice(&self.basic_mcs_set);
564 Dot11Elt::new(types::ie_id::HT_INFORMATION, info)
565 }
566
567 pub fn secondary_channel_offset(&self) -> u8 {
570 self.ht_info[0] & 0x03
571 }
572
573 pub fn sta_channel_width(&self) -> bool {
575 self.ht_info[0] & 0x04 != 0
576 }
577}
578
579#[derive(Debug, Clone, PartialEq, Eq)]
587pub struct Dot11EltVHTCapabilities {
588 pub vht_cap_info: u32,
590 pub mcs_nss_set: [u8; 8],
592}
593
594pub const VHT_CAP_LEN: usize = 12;
596
597impl Dot11EltVHTCapabilities {
598 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
600 if elt.id != types::ie_id::VHT_CAPABILITIES || elt.info.len() < VHT_CAP_LEN {
601 return None;
602 }
603 let d = &elt.info;
604 let vht_cap_info = u32::from_le_bytes([d[0], d[1], d[2], d[3]]);
605 let mut mcs_nss_set = [0u8; 8];
606 mcs_nss_set.copy_from_slice(&d[4..12]);
607
608 Some(Self {
609 vht_cap_info,
610 mcs_nss_set,
611 })
612 }
613
614 pub fn build(&self) -> Dot11Elt {
616 let mut info = Vec::with_capacity(VHT_CAP_LEN);
617 info.extend_from_slice(&self.vht_cap_info.to_le_bytes());
618 info.extend_from_slice(&self.mcs_nss_set);
619 Dot11Elt::new(types::ie_id::VHT_CAPABILITIES, info)
620 }
621
622 pub fn max_mpdu_length(&self) -> u8 {
625 (self.vht_cap_info & 0x03) as u8
626 }
627
628 pub fn supported_channel_width(&self) -> u8 {
630 ((self.vht_cap_info >> 2) & 0x03) as u8
631 }
632
633 pub fn short_gi_80(&self) -> bool {
635 self.vht_cap_info & 0x0020 != 0
636 }
637
638 pub fn short_gi_160(&self) -> bool {
640 self.vht_cap_info & 0x0040 != 0
641 }
642}
643
644#[derive(Debug, Clone, PartialEq, Eq)]
650pub struct Dot11EltVHTOperation {
651 pub channel_width: u8,
653 pub center_freq_seg0: u8,
655 pub center_freq_seg1: u8,
657 pub basic_mcs_nss: u16,
659}
660
661pub const VHT_OP_LEN: usize = 5;
663
664impl Dot11EltVHTOperation {
665 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
667 if elt.id != types::ie_id::VHT_OPERATION || elt.info.len() < VHT_OP_LEN {
668 return None;
669 }
670 let d = &elt.info;
671 Some(Self {
672 channel_width: d[0],
673 center_freq_seg0: d[1],
674 center_freq_seg1: d[2],
675 basic_mcs_nss: u16::from_le_bytes([d[3], d[4]]),
676 })
677 }
678
679 pub fn build(&self) -> Dot11Elt {
681 let mut info = Vec::with_capacity(VHT_OP_LEN);
682 info.push(self.channel_width);
683 info.push(self.center_freq_seg0);
684 info.push(self.center_freq_seg1);
685 info.extend_from_slice(&self.basic_mcs_nss.to_le_bytes());
686 Dot11Elt::new(types::ie_id::VHT_OPERATION, info)
687 }
688}
689
690#[derive(Debug, Clone, PartialEq, Eq)]
696pub struct CipherSuite {
697 pub oui: [u8; 3],
699 pub suite_type: u8,
701}
702
703impl CipherSuite {
704 pub fn from_bytes(data: &[u8; 4]) -> Self {
706 Self {
707 oui: [data[0], data[1], data[2]],
708 suite_type: data[3],
709 }
710 }
711
712 pub fn to_bytes(&self) -> [u8; 4] {
714 [self.oui[0], self.oui[1], self.oui[2], self.suite_type]
715 }
716
717 pub fn name(&self) -> &'static str {
719 if self.oui == [0x00, 0x0F, 0xAC] {
720 types::cipher_suite::name(self.suite_type)
721 } else {
722 "Vendor-Specific"
723 }
724 }
725}
726
727#[derive(Debug, Clone, PartialEq, Eq)]
729pub struct AkmSuite {
730 pub oui: [u8; 3],
732 pub suite_type: u8,
734}
735
736impl AkmSuite {
737 pub fn from_bytes(data: &[u8; 4]) -> Self {
739 Self {
740 oui: [data[0], data[1], data[2]],
741 suite_type: data[3],
742 }
743 }
744
745 pub fn to_bytes(&self) -> [u8; 4] {
747 [self.oui[0], self.oui[1], self.oui[2], self.suite_type]
748 }
749
750 pub fn name(&self) -> &'static str {
752 if self.oui == [0x00, 0x0F, 0xAC] {
753 types::akm_suite::name(self.suite_type)
754 } else {
755 "Vendor-Specific"
756 }
757 }
758}
759
760#[derive(Debug, Clone, PartialEq, Eq)]
762pub struct RsnInfo {
763 pub version: u16,
765 pub group_cipher: CipherSuite,
767 pub pairwise_ciphers: Vec<CipherSuite>,
769 pub akm_suites: Vec<AkmSuite>,
771 pub rsn_capabilities: u16,
773 pub pmkid_count: u16,
775 pub pmkids: Vec<[u8; 16]>,
777 pub group_mgmt_cipher: Option<CipherSuite>,
779}
780
781#[derive(Debug, Clone, PartialEq, Eq)]
783pub struct Dot11EltRSN {
784 pub info: RsnInfo,
786}
787
788impl Dot11EltRSN {
789 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
791 if elt.id != types::ie_id::RSN || elt.info.len() < 2 {
792 return None;
793 }
794 let data = &elt.info;
795 let mut offset = 0;
796
797 if offset + 2 > data.len() {
799 return None;
800 }
801 let version = u16::from_le_bytes([data[offset], data[offset + 1]]);
802 offset += 2;
803
804 if offset + 4 > data.len() {
806 return None;
807 }
808 let mut gc = [0u8; 4];
809 gc.copy_from_slice(&data[offset..offset + 4]);
810 let group_cipher = CipherSuite::from_bytes(&gc);
811 offset += 4;
812
813 let pairwise_count = if offset + 2 <= data.len() {
815 let c = u16::from_le_bytes([data[offset], data[offset + 1]]) as usize;
816 offset += 2;
817 c
818 } else {
819 0
820 };
821
822 let mut pairwise_ciphers = Vec::with_capacity(pairwise_count);
824 for _ in 0..pairwise_count {
825 if offset + 4 > data.len() {
826 break;
827 }
828 let mut suite = [0u8; 4];
829 suite.copy_from_slice(&data[offset..offset + 4]);
830 pairwise_ciphers.push(CipherSuite::from_bytes(&suite));
831 offset += 4;
832 }
833
834 let akm_count = if offset + 2 <= data.len() {
836 let c = u16::from_le_bytes([data[offset], data[offset + 1]]) as usize;
837 offset += 2;
838 c
839 } else {
840 0
841 };
842
843 let mut akm_suites = Vec::with_capacity(akm_count);
845 for _ in 0..akm_count {
846 if offset + 4 > data.len() {
847 break;
848 }
849 let mut suite = [0u8; 4];
850 suite.copy_from_slice(&data[offset..offset + 4]);
851 akm_suites.push(AkmSuite::from_bytes(&suite));
852 offset += 4;
853 }
854
855 let rsn_capabilities = if offset + 2 <= data.len() {
857 let c = u16::from_le_bytes([data[offset], data[offset + 1]]);
858 offset += 2;
859 c
860 } else {
861 0
862 };
863
864 let pmkid_count = if offset + 2 <= data.len() {
866 let c = u16::from_le_bytes([data[offset], data[offset + 1]]);
867 offset += 2;
868 c
869 } else {
870 0
871 };
872
873 let mut pmkids = Vec::new();
875 for _ in 0..pmkid_count {
876 if offset + 16 > data.len() {
877 break;
878 }
879 let mut pmkid = [0u8; 16];
880 pmkid.copy_from_slice(&data[offset..offset + 16]);
881 pmkids.push(pmkid);
882 offset += 16;
883 }
884
885 let group_mgmt_cipher = if offset + 4 <= data.len() {
887 let mut suite = [0u8; 4];
888 suite.copy_from_slice(&data[offset..offset + 4]);
889 Some(CipherSuite::from_bytes(&suite))
890 } else {
891 None
892 };
893
894 Some(Self {
895 info: RsnInfo {
896 version,
897 group_cipher,
898 pairwise_ciphers,
899 akm_suites,
900 rsn_capabilities,
901 pmkid_count,
902 pmkids,
903 group_mgmt_cipher,
904 },
905 })
906 }
907
908 pub fn build(&self) -> Dot11Elt {
910 let rsn = &self.info;
911 let mut data = Vec::new();
912
913 data.extend_from_slice(&rsn.version.to_le_bytes());
915
916 data.extend_from_slice(&rsn.group_cipher.to_bytes());
918
919 data.extend_from_slice(&(rsn.pairwise_ciphers.len() as u16).to_le_bytes());
921 for cs in &rsn.pairwise_ciphers {
922 data.extend_from_slice(&cs.to_bytes());
923 }
924
925 data.extend_from_slice(&(rsn.akm_suites.len() as u16).to_le_bytes());
927 for akm in &rsn.akm_suites {
928 data.extend_from_slice(&akm.to_bytes());
929 }
930
931 data.extend_from_slice(&rsn.rsn_capabilities.to_le_bytes());
933
934 if !rsn.pmkids.is_empty() {
936 data.extend_from_slice(&(rsn.pmkids.len() as u16).to_le_bytes());
937 for pmkid in &rsn.pmkids {
938 data.extend_from_slice(pmkid);
939 }
940 }
941
942 if let Some(ref gmc) = rsn.group_mgmt_cipher {
944 if rsn.pmkids.is_empty() {
946 data.extend_from_slice(&0u16.to_le_bytes());
947 }
948 data.extend_from_slice(&gmc.to_bytes());
949 }
950
951 Dot11Elt::new(types::ie_id::RSN, data)
952 }
953
954 pub fn pre_auth(&self) -> bool {
956 self.info.rsn_capabilities & 0x0001 != 0
957 }
958
959 pub fn no_pairwise(&self) -> bool {
961 self.info.rsn_capabilities & 0x0002 != 0
962 }
963
964 pub fn ptksa_replay_counter(&self) -> u8 {
966 ((self.info.rsn_capabilities >> 2) & 0x03) as u8
967 }
968
969 pub fn gtksa_replay_counter(&self) -> u8 {
971 ((self.info.rsn_capabilities >> 4) & 0x03) as u8
972 }
973
974 pub fn mfp_required(&self) -> bool {
976 self.info.rsn_capabilities & 0x0040 != 0
977 }
978
979 pub fn mfp_capable(&self) -> bool {
981 self.info.rsn_capabilities & 0x0080 != 0
982 }
983}
984
985#[derive(Debug, Clone, PartialEq, Eq)]
991pub struct Dot11EltVendorSpecific {
992 pub oui: [u8; 3],
994 pub data: Vec<u8>,
996}
997
998impl Dot11EltVendorSpecific {
999 pub fn new(oui: [u8; 3], data: Vec<u8>) -> Self {
1001 Self { oui, data }
1002 }
1003
1004 pub fn parse(elt: &Dot11Elt) -> Option<Self> {
1006 if elt.id != types::ie_id::VENDOR_SPECIFIC || elt.info.len() < 3 {
1007 return None;
1008 }
1009 let mut oui = [0u8; 3];
1010 oui.copy_from_slice(&elt.info[0..3]);
1011 Some(Self {
1012 oui,
1013 data: elt.info[3..].to_vec(),
1014 })
1015 }
1016
1017 pub fn build(&self) -> Dot11Elt {
1019 let mut info = Vec::with_capacity(3 + self.data.len());
1020 info.extend_from_slice(&self.oui);
1021 info.extend_from_slice(&self.data);
1022 Dot11Elt::new(types::ie_id::VENDOR_SPECIFIC, info)
1023 }
1024
1025 pub fn is_wpa(&self) -> bool {
1027 self.oui == types::MICROSOFT_WPA_OUI
1028 && !self.data.is_empty()
1029 && self.data[0] == types::MICROSOFT_WPA_TYPE
1030 }
1031
1032 pub fn is_wmm(&self) -> bool {
1034 self.oui == types::MICROSOFT_WPA_OUI && !self.data.is_empty() && self.data[0] == 0x02
1035 }
1036}
1037
1038#[derive(Debug, Clone, PartialEq, Eq)]
1047pub struct Dot11EltMicrosoftWPA {
1048 pub version: u16,
1050 pub group_cipher: CipherSuite,
1052 pub pairwise_ciphers: Vec<CipherSuite>,
1054 pub akm_suites: Vec<AkmSuite>,
1056}
1057
1058impl Dot11EltMicrosoftWPA {
1059 pub fn parse(vs: &Dot11EltVendorSpecific) -> Option<Self> {
1061 if !vs.is_wpa() {
1062 return None;
1063 }
1064 let data = &vs.data;
1066 if data.len() < 7 {
1067 return None;
1069 }
1070 let mut offset = 1; let version = u16::from_le_bytes([data[offset], data[offset + 1]]);
1073 offset += 2;
1074
1075 if offset + 4 > data.len() {
1076 return None;
1077 }
1078 let mut gc = [0u8; 4];
1079 gc.copy_from_slice(&data[offset..offset + 4]);
1080 let group_cipher = CipherSuite::from_bytes(&gc);
1081 offset += 4;
1082
1083 let pw_count = if offset + 2 <= data.len() {
1085 let c = u16::from_le_bytes([data[offset], data[offset + 1]]) as usize;
1086 offset += 2;
1087 c
1088 } else {
1089 0
1090 };
1091
1092 let mut pairwise_ciphers = Vec::with_capacity(pw_count);
1093 for _ in 0..pw_count {
1094 if offset + 4 > data.len() {
1095 break;
1096 }
1097 let mut suite = [0u8; 4];
1098 suite.copy_from_slice(&data[offset..offset + 4]);
1099 pairwise_ciphers.push(CipherSuite::from_bytes(&suite));
1100 offset += 4;
1101 }
1102
1103 let akm_count = if offset + 2 <= data.len() {
1105 let c = u16::from_le_bytes([data[offset], data[offset + 1]]) as usize;
1106 offset += 2;
1107 c
1108 } else {
1109 0
1110 };
1111
1112 let mut akm_suites = Vec::with_capacity(akm_count);
1113 for _ in 0..akm_count {
1114 if offset + 4 > data.len() {
1115 break;
1116 }
1117 let mut suite = [0u8; 4];
1118 suite.copy_from_slice(&data[offset..offset + 4]);
1119 akm_suites.push(AkmSuite::from_bytes(&suite));
1120 offset += 4;
1121 }
1122
1123 Some(Self {
1124 version,
1125 group_cipher,
1126 pairwise_ciphers,
1127 akm_suites,
1128 })
1129 }
1130
1131 pub fn build(&self) -> Dot11Elt {
1133 let mut data = Vec::new();
1134
1135 data.extend_from_slice(&types::MICROSOFT_WPA_OUI);
1137 data.push(types::MICROSOFT_WPA_TYPE);
1138
1139 data.extend_from_slice(&self.version.to_le_bytes());
1141
1142 data.extend_from_slice(&self.group_cipher.to_bytes());
1144
1145 data.extend_from_slice(&(self.pairwise_ciphers.len() as u16).to_le_bytes());
1147 for cs in &self.pairwise_ciphers {
1148 data.extend_from_slice(&cs.to_bytes());
1149 }
1150
1151 data.extend_from_slice(&(self.akm_suites.len() as u16).to_le_bytes());
1153 for akm in &self.akm_suites {
1154 data.extend_from_slice(&akm.to_bytes());
1155 }
1156
1157 Dot11Elt::new(types::ie_id::VENDOR_SPECIFIC, data)
1158 }
1159}
1160
1161pub fn find_ie(elements: &[Dot11Elt], id: u8) -> Option<&Dot11Elt> {
1167 elements.iter().find(|e| e.id == id)
1168}
1169
1170pub fn find_all_ies(elements: &[Dot11Elt], id: u8) -> Vec<&Dot11Elt> {
1172 elements.iter().filter(|e| e.id == id).collect()
1173}
1174
1175pub fn extract_ssid(elements: &[Dot11Elt]) -> Option<String> {
1177 find_ie(elements, types::ie_id::SSID).and_then(|e| e.ssid_str())
1178}
1179
1180pub fn extract_channel(elements: &[Dot11Elt]) -> Option<u8> {
1182 find_ie(elements, types::ie_id::DS_PARAMETER_SET)
1183 .and_then(|e| Dot11EltDSSSet::parse(e))
1184 .map(|ds| ds.channel)
1185}
1186
1187#[cfg(test)]
1192mod tests {
1193 use super::*;
1194
1195 #[test]
1196 fn test_dot11elt_parse_build_roundtrip() {
1197 let elt = Dot11Elt::new(0, b"TestSSID".to_vec());
1198 let wire = elt.build();
1199 assert_eq!(wire[0], 0); assert_eq!(wire[1], 8); assert_eq!(&wire[2..], b"TestSSID");
1202
1203 let (parsed, consumed) = Dot11Elt::parse(&wire, 0).unwrap();
1204 assert_eq!(consumed, 10);
1205 assert_eq!(parsed.id, 0);
1206 assert_eq!(parsed.len, 8);
1207 assert_eq!(&parsed.info, b"TestSSID");
1208 }
1209
1210 #[test]
1211 fn test_dot11elt_parse_all() {
1212 let ssid = Dot11Elt::ssid("MyNetwork");
1213 let rates = Dot11Elt::new(1, vec![0x82, 0x84, 0x8B, 0x96]);
1214 let chain = Dot11Elt::build_chain(&[ssid.clone(), rates.clone()]);
1215
1216 let parsed = Dot11Elt::parse_all(&chain, 0);
1217 assert_eq!(parsed.len(), 2);
1218 assert_eq!(parsed[0].id, 0);
1219 assert_eq!(parsed[0].ssid_str().unwrap(), "MyNetwork");
1220 assert_eq!(parsed[1].id, 1);
1221 assert_eq!(parsed[1].info, vec![0x82, 0x84, 0x8B, 0x96]);
1222 }
1223
1224 #[test]
1225 fn test_ssid_ie() {
1226 let ssid_ie = Dot11EltSSID::new("HelloWiFi");
1227 assert_eq!(ssid_ie.ssid, "HelloWiFi");
1228 assert!(!ssid_ie.is_hidden());
1229
1230 let elt = ssid_ie.build();
1231 assert_eq!(elt.id, 0);
1232 let parsed = Dot11EltSSID::parse(&elt).unwrap();
1233 assert_eq!(parsed.ssid, "HelloWiFi");
1234
1235 let hidden = Dot11EltSSID::new("");
1237 assert!(hidden.is_hidden());
1238 }
1239
1240 #[test]
1241 fn test_rates_ie() {
1242 let rates = Dot11EltRates::new(vec![0x82, 0x84, 0x8B, 0x96, 0x0C, 0x12, 0x18, 0x24]);
1243 let elt = rates.build();
1244 assert_eq!(elt.id, 1);
1245
1246 let parsed = Dot11EltRates::parse(&elt).unwrap();
1247 assert_eq!(parsed.rates.len(), 8);
1248 assert!(Dot11EltRates::is_basic(0x82)); assert!(!Dot11EltRates::is_basic(0x0C)); assert_eq!(Dot11EltRates::rate_mbps(0x82), 1.0);
1251 assert_eq!(Dot11EltRates::rate_mbps(0x0C), 6.0);
1252 }
1253
1254 #[test]
1255 fn test_dsset_ie() {
1256 let ds = Dot11EltDSSSet::new(6);
1257 let elt = ds.build();
1258 assert_eq!(elt.id, 3);
1259 assert_eq!(elt.info, vec![6]);
1260
1261 let parsed = Dot11EltDSSSet::parse(&elt).unwrap();
1262 assert_eq!(parsed.channel, 6);
1263 }
1264
1265 #[test]
1266 fn test_tim_ie() {
1267 let tim = Dot11EltTIM::new(0, 3, 0, vec![0x00]);
1268 let elt = tim.build();
1269 assert_eq!(elt.id, 5);
1270 assert_eq!(elt.info.len(), 4);
1271
1272 let parsed = Dot11EltTIM::parse(&elt).unwrap();
1273 assert_eq!(parsed.dtim_count, 0);
1274 assert_eq!(parsed.dtim_period, 3);
1275 assert_eq!(parsed.bitmap_control, 0);
1276 assert_eq!(parsed.bitmap, vec![0x00]);
1277 }
1278
1279 #[test]
1280 fn test_country_ie() {
1281 let country = Dot11EltCountry::new(
1282 *b"US ",
1283 vec![
1284 CountryTriplet {
1285 first_channel: 1,
1286 num_channels: 11,
1287 max_power: 30,
1288 },
1289 CountryTriplet {
1290 first_channel: 36,
1291 num_channels: 4,
1292 max_power: 17,
1293 },
1294 ],
1295 );
1296 let elt = country.build();
1297 assert_eq!(elt.id, 7);
1298
1299 let parsed = Dot11EltCountry::parse(&elt).unwrap();
1300 assert_eq!(parsed.country_str(), "US ");
1301 assert_eq!(parsed.triplets.len(), 2);
1302 assert_eq!(parsed.triplets[0].first_channel, 1);
1303 assert_eq!(parsed.triplets[0].num_channels, 11);
1304 assert_eq!(parsed.triplets[0].max_power, 30);
1305 assert_eq!(parsed.triplets[1].first_channel, 36);
1306 }
1307
1308 #[test]
1309 fn test_csa_ie() {
1310 let csa = Dot11EltCSA::new(1, 11, 5);
1311 let elt = csa.build();
1312 assert_eq!(elt.id, 37);
1313
1314 let parsed = Dot11EltCSA::parse(&elt).unwrap();
1315 assert_eq!(parsed.mode, 1);
1316 assert_eq!(parsed.new_channel, 11);
1317 assert_eq!(parsed.count, 5);
1318 }
1319
1320 #[test]
1321 fn test_ht_capabilities_ie() {
1322 let ht = Dot11EltHTCapabilities {
1323 ht_cap_info: 0x016F, ampdu_params: 0x17,
1325 mcs_set: [0xFF, 0xFF, 0xFF, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1326 ht_ext_cap: 0x0000,
1327 txbf_cap: 0x00000000,
1328 asel_cap: 0x00,
1329 };
1330 let elt = ht.build();
1331 assert_eq!(elt.id, 45);
1332 assert_eq!(elt.info.len(), HT_CAP_LEN);
1333
1334 let parsed = Dot11EltHTCapabilities::parse(&elt).unwrap();
1335 assert!(parsed.ldpc());
1336 assert!(parsed.channel_width_set());
1337 assert!(parsed.short_gi_20());
1338 assert!(parsed.short_gi_40());
1339 assert_eq!(parsed.ampdu_params, 0x17);
1340 }
1341
1342 #[test]
1343 fn test_ht_info_ie() {
1344 let ht_info = Dot11EltHTInfo {
1345 primary_channel: 6,
1346 ht_info: [0x05, 0x00, 0x00, 0x00, 0x00], basic_mcs_set: [0; 16],
1348 };
1349 let elt = ht_info.build();
1350 assert_eq!(elt.id, 61);
1351 assert_eq!(elt.info.len(), HT_INFO_LEN);
1352
1353 let parsed = Dot11EltHTInfo::parse(&elt).unwrap();
1354 assert_eq!(parsed.primary_channel, 6);
1355 assert_eq!(parsed.secondary_channel_offset(), 1);
1356 assert!(parsed.sta_channel_width());
1357 }
1358
1359 #[test]
1360 fn test_vht_capabilities_ie() {
1361 let vht = Dot11EltVHTCapabilities {
1362 vht_cap_info: 0x00000062, mcs_nss_set: [0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00],
1364 };
1365 let elt = vht.build();
1366 assert_eq!(elt.id, 191);
1367 assert_eq!(elt.info.len(), VHT_CAP_LEN);
1368
1369 let parsed = Dot11EltVHTCapabilities::parse(&elt).unwrap();
1370 assert_eq!(parsed.max_mpdu_length(), 2);
1371 assert!(parsed.short_gi_80());
1372 assert!(parsed.short_gi_160());
1373 }
1374
1375 #[test]
1376 fn test_vht_operation_ie() {
1377 let vht_op = Dot11EltVHTOperation {
1378 channel_width: 1,
1379 center_freq_seg0: 42,
1380 center_freq_seg1: 0,
1381 basic_mcs_nss: 0xFFFC,
1382 };
1383 let elt = vht_op.build();
1384 assert_eq!(elt.id, 192);
1385 assert_eq!(elt.info.len(), VHT_OP_LEN);
1386
1387 let parsed = Dot11EltVHTOperation::parse(&elt).unwrap();
1388 assert_eq!(parsed.channel_width, 1);
1389 assert_eq!(parsed.center_freq_seg0, 42);
1390 assert_eq!(parsed.center_freq_seg1, 0);
1391 assert_eq!(parsed.basic_mcs_nss, 0xFFFC);
1392 }
1393
1394 #[test]
1395 fn test_rsn_ie_wpa2_psk() {
1396 let rsn = Dot11EltRSN {
1397 info: RsnInfo {
1398 version: 1,
1399 group_cipher: CipherSuite::from_bytes(&[0x00, 0x0F, 0xAC, 0x04]), pairwise_ciphers: vec![CipherSuite::from_bytes(&[0x00, 0x0F, 0xAC, 0x04])],
1401 akm_suites: vec![AkmSuite::from_bytes(&[0x00, 0x0F, 0xAC, 0x02])], rsn_capabilities: 0x000C,
1403 pmkid_count: 0,
1404 pmkids: Vec::new(),
1405 group_mgmt_cipher: None,
1406 },
1407 };
1408
1409 let elt = rsn.build();
1410 assert_eq!(elt.id, 48);
1411
1412 let parsed = Dot11EltRSN::parse(&elt).unwrap();
1413 assert_eq!(parsed.info.version, 1);
1414 assert_eq!(parsed.info.group_cipher.name(), "CCMP-128");
1415 assert_eq!(parsed.info.pairwise_ciphers.len(), 1);
1416 assert_eq!(parsed.info.pairwise_ciphers[0].name(), "CCMP-128");
1417 assert_eq!(parsed.info.akm_suites.len(), 1);
1418 assert_eq!(parsed.info.akm_suites[0].name(), "PSK");
1419 assert_eq!(parsed.info.rsn_capabilities, 0x000C);
1420 }
1421
1422 #[test]
1423 fn test_rsn_ie_with_mfp() {
1424 let rsn = Dot11EltRSN {
1425 info: RsnInfo {
1426 version: 1,
1427 group_cipher: CipherSuite::from_bytes(&[0x00, 0x0F, 0xAC, 0x04]),
1428 pairwise_ciphers: vec![CipherSuite::from_bytes(&[0x00, 0x0F, 0xAC, 0x04])],
1429 akm_suites: vec![AkmSuite::from_bytes(&[0x00, 0x0F, 0xAC, 0x08])], rsn_capabilities: 0x00CC, pmkid_count: 0,
1432 pmkids: Vec::new(),
1433 group_mgmt_cipher: Some(CipherSuite::from_bytes(&[0x00, 0x0F, 0xAC, 0x06])), },
1435 };
1436
1437 let elt = rsn.build();
1438 let parsed = Dot11EltRSN::parse(&elt).unwrap();
1439 assert!(parsed.mfp_required());
1440 assert!(parsed.mfp_capable());
1441 assert!(parsed.info.group_mgmt_cipher.is_some());
1442 assert_eq!(
1443 parsed.info.group_mgmt_cipher.unwrap().name(),
1444 "BIP-CMAC-128"
1445 );
1446 }
1447
1448 #[test]
1449 fn test_vendor_specific_ie() {
1450 let vs = Dot11EltVendorSpecific::new([0x00, 0x50, 0xF2], vec![0x01, 0x01, 0x00]);
1451 assert!(vs.is_wpa());
1452 assert!(!vs.is_wmm());
1453
1454 let elt = vs.build();
1455 assert_eq!(elt.id, 221);
1456
1457 let parsed = Dot11EltVendorSpecific::parse(&elt).unwrap();
1458 assert_eq!(parsed.oui, [0x00, 0x50, 0xF2]);
1459 assert!(parsed.is_wpa());
1460 }
1461
1462 #[test]
1463 fn test_microsoft_wpa_ie() {
1464 let wpa = Dot11EltMicrosoftWPA {
1465 version: 1,
1466 group_cipher: CipherSuite::from_bytes(&[0x00, 0x50, 0xF2, 0x02]), pairwise_ciphers: vec![CipherSuite::from_bytes(&[0x00, 0x50, 0xF2, 0x02])], akm_suites: vec![AkmSuite::from_bytes(&[0x00, 0x50, 0xF2, 0x02])], };
1470
1471 let elt = wpa.build();
1472 assert_eq!(elt.id, 221);
1473
1474 let vs = Dot11EltVendorSpecific::parse(&elt).unwrap();
1476 assert!(vs.is_wpa());
1477
1478 let parsed = Dot11EltMicrosoftWPA::parse(&vs).unwrap();
1479 assert_eq!(parsed.version, 1);
1480 assert_eq!(parsed.group_cipher.to_bytes(), [0x00, 0x50, 0xF2, 0x02]);
1481 assert_eq!(parsed.pairwise_ciphers.len(), 1);
1482 assert_eq!(parsed.akm_suites.len(), 1);
1483 }
1484
1485 #[test]
1486 fn test_find_ie_helpers() {
1487 let elements = vec![
1488 Dot11Elt::ssid("TestNet"),
1489 Dot11Elt::new(1, vec![0x82, 0x84]),
1490 Dot11Elt::new(3, vec![6]),
1491 ];
1492
1493 assert_eq!(extract_ssid(&elements), Some("TestNet".to_string()));
1494 assert_eq!(extract_channel(&elements), Some(6));
1495 assert!(find_ie(&elements, 48).is_none()); }
1497
1498 #[test]
1499 fn test_dot11elt_name() {
1500 let ssid = Dot11Elt::ssid("Test");
1501 assert_eq!(ssid.name(), "SSID");
1502
1503 let rsn = Dot11Elt::new(48, vec![]);
1504 assert_eq!(rsn.name(), "RSN");
1505
1506 let ht = Dot11Elt::new(45, vec![]);
1507 assert_eq!(ht.name(), "HT Capabilities");
1508 }
1509
1510 #[test]
1511 fn test_dot11elt_wire_len() {
1512 let elt = Dot11Elt::new(0, b"Test".to_vec());
1513 assert_eq!(elt.wire_len(), 6); }
1515
1516 #[test]
1517 fn test_parse_truncated_ie() {
1518 let buf = vec![0x00];
1520 assert!(Dot11Elt::parse(&buf, 0).is_err());
1521
1522 let buf = vec![0x00, 0x0A, 0x01, 0x02, 0x03, 0x04, 0x05];
1524 assert!(Dot11Elt::parse(&buf, 0).is_err());
1525 }
1526
1527 #[test]
1528 fn test_parse_all_partial() {
1529 let mut buf = Dot11Elt::ssid("AB").build();
1531 buf.extend(Dot11Elt::new(1, vec![0x82]).build());
1532 buf.extend(&[0x03, 0x05]); let parsed = Dot11Elt::parse_all(&buf, 0);
1535 assert_eq!(parsed.len(), 2); }
1537
1538 #[test]
1539 fn test_rates_mbps() {
1540 let rates = Dot11EltRates::new(vec![0x82, 0x84, 0x8B, 0x96, 0x0C, 0x12, 0x18, 0x24]);
1541 let mbps = rates.rates_mbps();
1542 assert_eq!(mbps, vec![1.0, 2.0, 5.5, 11.0, 6.0, 9.0, 12.0, 18.0]);
1543 }
1544}