wlan_common/mac/
frame_class.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::mac;
6use zerocopy::SplitByteSlice;
7
8#[derive(Copy, Clone, PartialOrd, PartialEq, Debug, Ord, Eq)]
9pub enum FrameClass {
10    Class1 = 1,
11    Class2 = 2,
12    Class3 = 3,
13}
14
15/// Converts a MacFrame into a FrameClass.
16impl<B: SplitByteSlice> From<&mac::MacFrame<B>> for FrameClass {
17    fn from(mac_frame: &mac::MacFrame<B>) -> FrameClass {
18        frame_class(&mac_frame.frame_ctrl())
19    }
20}
21
22// TODO(https://fxbug.dev/332571044): Factor this function into an inherent function of
23//                                    `FrameClass` and provide similar inherent functions for
24//                                    `MacFrame` and its variant types.
25/// IEEE Std 802.11-2016, 11.3.3
26/// Unlike IEEE which only considers Public and Self-Protected Action frames Class 1 frames,
27/// Fuchsia considers all Action frames Class 1 frames when checking a frame's FrameControl.
28/// Use `action_frame_class(category)` to determine an Action frame's proper frame Class.
29/// Fuchsia supports neither IBSS nor PBSS, thus, every frame is evaluated in respect to an
30/// Infrastructure BSS.
31pub fn frame_class(fc: &mac::FrameControl) -> FrameClass {
32    // Class 1 frames:
33    match fc.frame_type() {
34        mac::FrameType::CTRL => match fc.ctrl_subtype() {
35            // Control extensions such as SSW and Grant are excluded as Fuchsia does not
36            // support any of those frames yet.
37            mac::CtrlSubtype::RTS
38            | mac::CtrlSubtype::CTS
39            | mac::CtrlSubtype::ACK
40            | mac::CtrlSubtype::CF_END
41            | mac::CtrlSubtype::CF_END_ACK => return FrameClass::Class1,
42            _ => (),
43        },
44        mac::FrameType::MGMT => match fc.mgmt_subtype() {
45            mac::MgmtSubtype::ACTION
46            | mac::MgmtSubtype::PROBE_REQ
47            | mac::MgmtSubtype::PROBE_RESP
48            | mac::MgmtSubtype::BEACON
49            | mac::MgmtSubtype::AUTH
50            | mac::MgmtSubtype::DEAUTH
51            | mac::MgmtSubtype::ATIM => return FrameClass::Class1,
52            _ => (),
53        },
54        _ => (),
55    };
56
57    // Class 2 frames:
58    // Data frames are excluded as DLS is not supported by Fuchsia
59    if let mac::FrameType::MGMT = fc.frame_type() {
60        match fc.mgmt_subtype() {
61            mac::MgmtSubtype::ASSOC_REQ
62            | mac::MgmtSubtype::ASSOC_RESP
63            | mac::MgmtSubtype::REASSOC_REQ
64            | mac::MgmtSubtype::REASSOC_RESP
65            | mac::MgmtSubtype::DISASSOC => return FrameClass::Class2,
66            _ => (),
67        }
68    };
69
70    FrameClass::Class3
71}
72
73// IEEE Std 802.11-2016, 11.3.3
74pub fn action_frame_class(category: mac::ActionCategory) -> FrameClass {
75    match category {
76        // Class 1 frames:
77        mac::ActionCategory::PUBLIC | mac::ActionCategory::SELF_PROTECTED => FrameClass::Class1,
78        // All other action frames are Class 3 frames:
79        _ => FrameClass::Class3,
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn mgmt_frame_class() {
89        // Class 1 frames:
90        let mut fc = mac::FrameControl(0)
91            .with_frame_type(mac::FrameType::MGMT)
92            .with_mgmt_subtype(mac::MgmtSubtype::BEACON);
93        assert_eq!(FrameClass::Class1, frame_class(&fc));
94        fc.set_mgmt_subtype(mac::MgmtSubtype::AUTH);
95        assert_eq!(FrameClass::Class1, frame_class(&fc));
96        fc.set_mgmt_subtype(mac::MgmtSubtype::DEAUTH);
97        assert_eq!(FrameClass::Class1, frame_class(&fc));
98        fc.set_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ);
99        assert_eq!(FrameClass::Class1, frame_class(&fc));
100        fc.set_mgmt_subtype(mac::MgmtSubtype::PROBE_RESP);
101        assert_eq!(FrameClass::Class1, frame_class(&fc));
102        fc.set_mgmt_subtype(mac::MgmtSubtype::ATIM);
103        assert_eq!(FrameClass::Class1, frame_class(&fc));
104        fc.set_mgmt_subtype(mac::MgmtSubtype::ACTION);
105        assert_eq!(FrameClass::Class1, frame_class(&fc));
106
107        // Class 2 frames:
108        fc.set_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ);
109        assert_eq!(FrameClass::Class2, frame_class(&fc));
110        fc.set_mgmt_subtype(mac::MgmtSubtype::ASSOC_RESP);
111        assert_eq!(FrameClass::Class2, frame_class(&fc));
112        fc.set_mgmt_subtype(mac::MgmtSubtype::REASSOC_REQ);
113        assert_eq!(FrameClass::Class2, frame_class(&fc));
114        fc.set_mgmt_subtype(mac::MgmtSubtype::REASSOC_RESP);
115        assert_eq!(FrameClass::Class2, frame_class(&fc));
116        fc.set_mgmt_subtype(mac::MgmtSubtype::DISASSOC);
117        assert_eq!(FrameClass::Class2, frame_class(&fc));
118
119        // Class 3 frames:
120        fc.set_mgmt_subtype(mac::MgmtSubtype::TIMING_AD);
121        assert_eq!(FrameClass::Class3, frame_class(&fc));
122        fc.set_mgmt_subtype(mac::MgmtSubtype::ACTION_NO_ACK);
123        assert_eq!(FrameClass::Class3, frame_class(&fc));
124    }
125
126    #[test]
127    fn data_frame_class() {
128        // Data frames are always Class 3 frames:
129        let fc = mac::FrameControl(0).with_frame_type(mac::FrameType::DATA);
130        assert_eq!(FrameClass::Class3, frame_class(&fc));
131    }
132
133    #[test]
134    fn ctrl_frame_class() {
135        // Class 1 frames:
136        let mut fc = mac::FrameControl(0)
137            .with_frame_type(mac::FrameType::CTRL)
138            .with_ctrl_subtype(mac::CtrlSubtype::ACK);
139        assert_eq!(FrameClass::Class1, frame_class(&fc));
140        fc.set_ctrl_subtype(mac::CtrlSubtype::RTS);
141        assert_eq!(FrameClass::Class1, frame_class(&fc));
142        fc.set_ctrl_subtype(mac::CtrlSubtype::CTS);
143        assert_eq!(FrameClass::Class1, frame_class(&fc));
144
145        // Class 3 frames:
146        fc.set_ctrl_subtype(mac::CtrlSubtype::PS_POLL);
147        assert_eq!(FrameClass::Class3, frame_class(&fc));
148        fc.set_ctrl_subtype(mac::CtrlSubtype::BLOCK_ACK);
149        assert_eq!(FrameClass::Class3, frame_class(&fc));
150        fc.set_ctrl_subtype(mac::CtrlSubtype::BLOCK_ACK_REQ);
151        assert_eq!(FrameClass::Class3, frame_class(&fc));
152    }
153
154    #[test]
155    fn action_frames() {
156        // Class 1 frames:
157        assert_eq!(FrameClass::Class1, action_frame_class(mac::ActionCategory::PUBLIC));
158        assert_eq!(FrameClass::Class1, action_frame_class(mac::ActionCategory::SELF_PROTECTED));
159
160        // Class 3 frames:
161        assert_eq!(FrameClass::Class3, action_frame_class(mac::ActionCategory::BLOCK_ACK));
162        assert_eq!(FrameClass::Class3, action_frame_class(mac::ActionCategory::MESH));
163    }
164}