1use crate::buffer_reader::BufferReader;
6use crate::mac::data::*;
7use crate::mac::{DataFrame, MacAddr};
8use zerocopy::byteorder::big_endian::U16;
9use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
10
11pub const LLC_SNAP_EXTENSION: u8 = 0xAA;
13pub const LLC_SNAP_UNNUMBERED_INFO: u8 = 0x03;
14pub const LLC_SNAP_OUI: [u8; 3] = [0, 0, 0];
15
16#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
19#[repr(C, packed)]
20pub struct LlcHdr {
21 pub dsap: u8,
22 pub ssap: u8,
23 pub control: u8,
24 pub oui: [u8; 3],
25 pub protocol_id: U16,
26}
27
28pub struct LlcFrame<B> {
29 pub hdr: Ref<B, LlcHdr>,
30 pub body: B,
31}
32
33impl<B> LlcFrame<B> {
34 pub fn parse(bytes: B) -> Option<Self>
35 where
36 B: SplitByteSlice,
37 {
38 let (hdr, body) = Ref::from_prefix(bytes).ok()?;
41 if body.is_empty() { None } else { Some(Self { hdr, body }) }
42 }
43
44 pub fn into_body(self) -> B {
45 self.body
46 }
47}
48
49pub struct Msdu<B> {
51 pub dst_addr: MacAddr,
52 pub src_addr: MacAddr,
53 pub llc_frame: LlcFrame<B>,
54}
55
56impl<B> Msdu<B> {
57 pub fn into_body(self) -> B {
58 self.llc_frame.into_body()
59 }
60}
61
62pub struct IntoMsduIter<B> {
67 subtype: MsduIterSubtype<B>,
68}
69
70impl<B> From<DataFrame<B>> for IntoMsduIter<B>
71where
72 B: SplitByteSlice,
73{
74 fn from(frame: DataFrame<B>) -> Self {
75 IntoMsduIter { subtype: frame.into() }
76 }
77}
78
79impl<B> Iterator for IntoMsduIter<B>
80where
81 B: SplitByteSlice,
82{
83 type Item = Msdu<B>;
88
89 fn next(&mut self) -> Option<Self::Item> {
90 match self.subtype {
91 MsduIterSubtype::Null => None,
92 MsduIterSubtype::Llc { dst_addr, src_addr, ref mut body } => body
93 .take()
94 .and_then(LlcFrame::parse)
95 .map(|llc_frame| Msdu { dst_addr, src_addr, llc_frame }),
96 MsduIterSubtype::Amsdu(ref mut reader) => AmsduSubframe::parse(reader)
97 .and_then(|AmsduSubframe { hdr, body }| {
98 LlcFrame::parse(body).map(|llc_frame| (hdr, llc_frame))
99 })
100 .map(|(hdr, llc_frame)| Msdu { dst_addr: hdr.da, src_addr: hdr.sa, llc_frame }),
101 }
102 }
103}
104
105enum MsduIterSubtype<B> {
106 Llc { dst_addr: MacAddr, src_addr: MacAddr, body: Option<B> },
108 Amsdu(BufferReader<B>),
110 Null,
112}
113
114impl<B> From<DataFrame<B>> for MsduIterSubtype<B>
115where
116 B: SplitByteSlice,
117{
118 fn from(frame: DataFrame<B>) -> Self {
119 let fc = frame.fixed_fields.frame_ctrl;
120 if fc.data_subtype().null() {
121 MsduIterSubtype::Null
122 } else if frame.qos_ctrl.is_some_and(|qos_ctrl| qos_ctrl.get().amsdu_present()) {
123 MsduIterSubtype::Amsdu(BufferReader::new(frame.body))
124 } else {
125 MsduIterSubtype::Llc {
126 dst_addr: data_dst_addr(&frame.fixed_fields),
127 src_addr: data_src_addr(&frame.fixed_fields, frame.addr4.map(|addr4| *addr4))
128 .expect("failed to reparse data frame source address"),
129 body: Some(frame.body),
130 }
131 }
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use crate::mac::{self, data};
139 use crate::test_utils::fake_frames::*;
140 use assert_matches::assert_matches;
141
142 #[test]
143 fn msdu_iter_non_aggregated() {
144 let bytes = make_data_frame_single_llc(None, None);
145 data::harness::assert_msdus_exactly_one_eq(
146 mac::DataFrame::parse(bytes.as_slice(), false)
147 .expect("failed to parse non-aggregated data frame"),
148 mac::Msdu {
149 dst_addr: mac::MacAddr::from([3; 6]),
150 src_addr: mac::MacAddr::from([4; 6]),
151 llc_frame: mac::LlcFrame {
152 hdr: Ref::from_bytes(&[7, 7, 7, 8, 8, 8, 9, 10][..]).unwrap(),
153 body: &[11; 3][..],
154 },
155 },
156 );
157 }
158
159 #[test]
160 fn msdu_iter_non_aggregated_with_padding() {
161 let bytes = make_data_frame_with_padding();
162 data::harness::assert_msdus_exactly_one_eq(
163 mac::DataFrame::parse(bytes.as_slice(), true)
164 .expect("failed to parse non-aggregated data frame with padding"),
165 mac::Msdu {
166 dst_addr: mac::MacAddr::from([3; 6]),
167 src_addr: mac::MacAddr::from([4; 6]),
168 llc_frame: mac::LlcFrame {
169 hdr: Ref::from_bytes(&[7, 7, 7, 8, 8, 8, 9, 10][..]).unwrap(),
170 body: &[11; 5][..],
171 },
172 },
173 );
174 }
175
176 #[test]
177 fn msdu_iter_null() {
178 let bytes = make_null_data_frame();
179 let data_frame = mac::DataFrame::parse(bytes.as_slice(), false)
180 .expect("failed to parse NULL data frame");
181 let n = data_frame.into_iter().count();
182 assert_eq!(0, n, "expected no MSDUs, but read {}", n);
183 }
184
185 #[test]
186 fn parse_llc_frame_with_addr4_ht_ctrl() {
187 let bytes =
188 make_data_frame_single_llc(Some(MacAddr::from([1, 2, 3, 4, 5, 6])), Some([4, 3, 2, 1]));
189 assert_matches!(
190 mac::DataFrame::parse(bytes.as_slice(), false),
191 Some(mac::DataFrame { body, .. }) => {
192 let llc_frame = LlcFrame::parse(body).expect("failed to parse LLC frame");
193 assert_eq!(7, llc_frame.hdr.dsap);
194 assert_eq!(7, llc_frame.hdr.ssap);
195 assert_eq!(7, llc_frame.hdr.control);
196 assert_eq!([8, 8, 8], llc_frame.hdr.oui);
197 assert_eq!([9, 10], llc_frame.hdr.protocol_id.to_bytes());
198 assert_eq!(0x090A, llc_frame.hdr.protocol_id.get());
199 assert_eq!(&[11, 11, 11], llc_frame.body);
200 },
201 "failed to parse data frame");
202 }
203}