wlan_common/mac/data/
msdu.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::big_endian::BigEndianU16;
6use crate::buffer_reader::BufferReader;
7use crate::mac::data::*;
8use crate::mac::{DataFrame, MacAddr};
9use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
10
11// RFC 1042
12pub 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// IEEE Std 802.2-1998, 3.2
17// IETF RFC 1042
18#[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: BigEndianU16,
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        // An LLC frame is only valid if it contains enough bytes for the header and one or more
39        // bytes for the body.
40        let (hdr, body) = Ref::from_prefix(bytes).ok()?;
41        if body.is_empty() {
42            None
43        } else {
44            Some(Self { hdr, body })
45        }
46    }
47
48    pub fn into_body(self) -> B {
49        self.body
50    }
51}
52
53/// A single MSDU.
54pub struct Msdu<B> {
55    pub dst_addr: MacAddr,
56    pub src_addr: MacAddr,
57    pub llc_frame: LlcFrame<B>,
58}
59
60impl<B> Msdu<B> {
61    pub fn into_body(self) -> B {
62        self.llc_frame.into_body()
63    }
64}
65
66/// Iterator over the MSDUs of a data frame.
67///
68/// This iterator supports NULL, non-aggregated, and aggregated data fields, which yield zero, one,
69/// and zero or more MSDUs, respectively.
70pub struct IntoMsduIter<B> {
71    subtype: MsduIterSubtype<B>,
72}
73
74impl<B> From<DataFrame<B>> for IntoMsduIter<B>
75where
76    B: SplitByteSlice,
77{
78    fn from(frame: DataFrame<B>) -> Self {
79        IntoMsduIter { subtype: frame.into() }
80    }
81}
82
83impl<B> Iterator for IntoMsduIter<B>
84where
85    B: SplitByteSlice,
86{
87    // TODO(https://fxbug.dev/330761628): The item should probably be `Result<Msdu<B>, _>` so that
88    //                                    client code can distinguish between exhausting the
89    //                                    iterator and a parse failure (which is unexpected and
90    //                                    likely indicates a meaningful error).
91    type Item = Msdu<B>;
92
93    fn next(&mut self) -> Option<Self::Item> {
94        match self.subtype {
95            MsduIterSubtype::Null => None,
96            MsduIterSubtype::Llc { dst_addr, src_addr, ref mut body } => body
97                .take()
98                .and_then(LlcFrame::parse)
99                .map(|llc_frame| Msdu { dst_addr, src_addr, llc_frame }),
100            MsduIterSubtype::Amsdu(ref mut reader) => AmsduSubframe::parse(reader)
101                .and_then(|AmsduSubframe { hdr, body }| {
102                    LlcFrame::parse(body).map(|llc_frame| (hdr, llc_frame))
103                })
104                .map(|(hdr, llc_frame)| Msdu { dst_addr: hdr.da, src_addr: hdr.sa, llc_frame }),
105        }
106    }
107}
108
109enum MsduIterSubtype<B> {
110    /// Non-aggregated data frame (exactly one MSDU).
111    Llc { dst_addr: MacAddr, src_addr: MacAddr, body: Option<B> },
112    /// Aggregated data frame (zero or more MSDUs).
113    Amsdu(BufferReader<B>),
114    /// NULL data frame (zero MSDUs).
115    Null,
116}
117
118impl<B> From<DataFrame<B>> for MsduIterSubtype<B>
119where
120    B: SplitByteSlice,
121{
122    fn from(frame: DataFrame<B>) -> Self {
123        let fc = frame.fixed_fields.frame_ctrl;
124        if fc.data_subtype().null() {
125            MsduIterSubtype::Null
126        } else if frame.qos_ctrl.is_some_and(|qos_ctrl| qos_ctrl.get().amsdu_present()) {
127            MsduIterSubtype::Amsdu(BufferReader::new(frame.body))
128        } else {
129            MsduIterSubtype::Llc {
130                dst_addr: data_dst_addr(&frame.fixed_fields),
131                src_addr: data_src_addr(&frame.fixed_fields, frame.addr4.map(|addr4| *addr4))
132                    .expect("failed to reparse data frame source address"),
133                body: Some(frame.body),
134            }
135        }
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use crate::assert_variant;
143    use crate::mac::{self, data};
144    use crate::test_utils::fake_frames::*;
145
146    #[test]
147    fn msdu_iter_non_aggregated() {
148        let bytes = make_data_frame_single_llc(None, None);
149        data::harness::assert_msdus_exactly_one_eq(
150            mac::DataFrame::parse(bytes.as_slice(), false)
151                .expect("failed to parse non-aggregated data frame"),
152            mac::Msdu {
153                dst_addr: mac::MacAddr::from([3; 6]),
154                src_addr: mac::MacAddr::from([4; 6]),
155                llc_frame: mac::LlcFrame {
156                    hdr: Ref::from_bytes(&[7, 7, 7, 8, 8, 8, 9, 10][..]).unwrap(),
157                    body: &[11; 3][..],
158                },
159            },
160        );
161    }
162
163    #[test]
164    fn msdu_iter_non_aggregated_with_padding() {
165        let bytes = make_data_frame_with_padding();
166        data::harness::assert_msdus_exactly_one_eq(
167            mac::DataFrame::parse(bytes.as_slice(), true)
168                .expect("failed to parse non-aggregated data frame with padding"),
169            mac::Msdu {
170                dst_addr: mac::MacAddr::from([3; 6]),
171                src_addr: mac::MacAddr::from([4; 6]),
172                llc_frame: mac::LlcFrame {
173                    hdr: Ref::from_bytes(&[7, 7, 7, 8, 8, 8, 9, 10][..]).unwrap(),
174                    body: &[11; 5][..],
175                },
176            },
177        );
178    }
179
180    #[test]
181    fn msdu_iter_null() {
182        let bytes = make_null_data_frame();
183        let data_frame = mac::DataFrame::parse(bytes.as_slice(), false)
184            .expect("failed to parse NULL data frame");
185        let n = data_frame.into_iter().count();
186        assert_eq!(0, n, "expected no MSDUs, but read {}", n);
187    }
188
189    #[test]
190    fn parse_llc_frame_with_addr4_ht_ctrl() {
191        let bytes =
192            make_data_frame_single_llc(Some(MacAddr::from([1, 2, 3, 4, 5, 6])), Some([4, 3, 2, 1]));
193        assert_variant!(
194            mac::DataFrame::parse(bytes.as_slice(), false),
195            Some(mac::DataFrame { body, .. }) => {
196                let llc_frame = LlcFrame::parse(body).expect("failed to parse LLC frame");
197                assert_eq!(7, llc_frame.hdr.dsap);
198                assert_eq!(7, llc_frame.hdr.ssap);
199                assert_eq!(7, llc_frame.hdr.control);
200                assert_eq!([8, 8, 8], llc_frame.hdr.oui);
201                assert_eq!([9, 10], llc_frame.hdr.protocol_id.0);
202                assert_eq!(0x090A, llc_frame.hdr.protocol_id.to_native());
203                assert_eq!(&[11, 11, 11], llc_frame.body);
204            },
205            "failed to parse data frame",
206        );
207    }
208}