1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use super::*;
use byteorder::{ByteOrder, LittleEndian};

pub trait BeaconFixedParametersTrait: FrameTrait {
    // Fixed Parameters (24..36) on Beacons
    const FIXED_PARAMETERS_START: usize = 24;

    /// microseconds it has been active
    fn timestamp(&self) -> u64 {
        LittleEndian::read_u64(
            &self.bytes()[Self::FIXED_PARAMETERS_START..(Self::FIXED_PARAMETERS_START + 8)],
        )
    }

    /// in seconds
    fn beacon_interval(&self) -> f64 {
        f64::from(LittleEndian::read_u16(
            &self.bytes()[(Self::FIXED_PARAMETERS_START + 8)..(Self::FIXED_PARAMETERS_START + 10)],
        )) * 0.001_024_f64
    }

    fn capabilities_info(&self) -> CapabilitiesInfo {
        CapabilitiesInfo::from_bytes(
            &self.bytes()[(Self::FIXED_PARAMETERS_START + 10)..(Self::FIXED_PARAMETERS_START + 12)],
        )
    }
}

#[derive(Debug, PartialEq)]
pub struct CapabilitiesInfo {
    /// 0: Transmitter is a STA
    /// 1: Transmitter is an AP
    pub ess_capabilities: bool,

    /// 0: Transmitter belongs to a BSS
    /// 1: Transmitter belongs to an IBSS
    pub ibss_status: bool,

    // static const value_string sta_cf_pollable[] = {
    //   {0x00, "Station is not CF-Pollable"},
    //   {0x02, "Station is CF-Pollable, not requesting to be placed on the  CF-polling list"},
    //   {0x01, "Station is CF-Pollable, requesting to be placed on the CF-polling list"},
    //   {0x03, "Station is CF-Pollable, requesting never to be polled"},
    //   {0x80, "QSTA requesting association in QBSS"},
    //   {0x81, "Reserved"},
    //   {0x82, "Reserved"},
    //   {0x83, "Reserved"},
    //   {0, NULL}
    // };

    // static const value_string ap_cf_pollable[] = {
    //   {0x00, "No point coordinator at AP"},
    //   {0x02, "Point coordinator at AP for delivery only (no polling)"},
    //   {0x01, "Point coordinator at AP for delivery and polling"},
    //   {0x03, "Reserved"},
    //   {0x80, "QAP (HC) does not use CFP for delivery of unicast data type frames"},
    //   {0x82, "QAP (HC) uses CFP for delivery, but does not send CF-Polls to non-QoS STAs"},
    //   {0x81, "QAP (HC) uses CFP for delivery, and sends CF-Polls to non-QoS STAs"},
    //   {0x83, "Reserved"},
    //   {0, NULL}
    // };
    pub cfp_partitipation_capabilities: u8,

    /// 0: AP/STA cannot support WEP
    /// 1: AP/STA can support WEP
    pub privacy: bool,

    /// 0: Not Allowed
    pub short_preamble: bool,

    /// 0: Not Allowed
    pub pbcc: bool,

    /// 0: Not in use
    pub channel_agility: bool,

    /// 0: Not Implemented
    pub spectrum_management: bool,

    /// 1: In use
    pub short_slot_time: bool,

    /// 0: Not Implemented
    pub automatic_power_save_delivery: bool,

    /// 0: Not Implemented
    pub radio_measurement: bool,

    /// 0: Not Implemented
    pub dsss_ofdm: bool,

    /// 0: Not Implemented
    pub delayed_block_ack: bool,

    /// 0: Not Implemented
    pub immediate_block_ack: bool,
}
impl CapabilitiesInfo {
    #[must_use]
    pub fn from_bytes(bytes: &[u8]) -> Self {
        let b1 = bytes[0];
        let b2 = bytes[1];

        let n = u16::from(b1 & 0b0000_1100) | u16::from(b2 & 0b0000_0010);
        let cfp_partitipation_capabilities = (n >> 2) as u8;

        Self {
            ess_capabilities: (b1 & 0b0000_0001) != 0,
            ibss_status: (b1 & 0b0000_0010) != 0,
            cfp_partitipation_capabilities,
            privacy: (b1 & 0b0001_0000) != 0,
            short_preamble: (b1 & 0b0010_0000) != 0,
            pbcc: (b1 & 0b0100_0000) != 0,
            channel_agility: (b1 & 0b1000_0000) != 0,
            spectrum_management: (b2 & 0b0000_0001) != 0,
            short_slot_time: (b2 & 0b0000_0100) != 0,
            automatic_power_save_delivery: (b2 & 0b0000_1000) != 0,
            radio_measurement: (b2 & 0b0001_0000) != 0,
            dsss_ofdm: (b2 & 0b0010_0000) != 0,
            delayed_block_ack: (b2 & 0b0100_0000) != 0,
            immediate_block_ack: (b2 & 0b1000_0000) != 0,
        }
    }
}