wlan_common/mac/data/
amsdu.rsuse crate::big_endian::BigEndianU16;
use crate::buffer_reader::BufferReader;
use crate::mac::{round_up, MacAddr};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
#[repr(C, packed)]
pub struct AmsduSubframeHdr {
pub da: MacAddr,
pub sa: MacAddr,
pub msdu_len: BigEndianU16,
}
pub struct AmsduSubframe<B> {
pub hdr: Ref<B, AmsduSubframeHdr>,
pub body: B,
}
impl<B: SplitByteSlice> AmsduSubframe<B> {
pub fn parse(buffer_reader: &mut BufferReader<B>) -> Option<Self> {
let hdr = buffer_reader.read::<AmsduSubframeHdr>()?;
let msdu_len = hdr.msdu_len.to_native() as usize;
if buffer_reader.bytes_remaining() < msdu_len {
None
} else {
let body = buffer_reader.read_bytes(msdu_len)?;
let base_len = std::mem::size_of::<AmsduSubframeHdr>() + msdu_len;
let padded_len = round_up(base_len, 4);
let padding_len = padded_len - base_len;
if buffer_reader.bytes_remaining() == 0 {
Some(Self { hdr, body })
} else if buffer_reader.bytes_remaining() <= padding_len {
None
} else {
buffer_reader.read_bytes(padding_len)?;
Some(Self { hdr, body })
}
}
}
}
#[cfg(test)]
mod tests {
use crate::mac::{self, data};
use crate::test_utils::fake_frames::*;
use zerocopy::Ref;
#[test]
fn msdu_iter_aggregated() {
let bytes = make_data_frame_amsdu();
data::harness::assert_msdus_llc_frame_eq(
mac::DataFrame::parse(bytes.as_slice(), false)
.expect("failed to parse aggregated data frame"),
[
mac::LlcFrame {
hdr: Ref::from_bytes(MSDU_1_LLC_HDR).unwrap(),
body: MSDU_1_PAYLOAD,
},
mac::LlcFrame {
hdr: Ref::from_bytes(MSDU_2_LLC_HDR).unwrap(),
body: MSDU_2_PAYLOAD,
},
],
);
}
#[test]
fn msdu_iter_aggregated_with_padding_too_short() {
let bytes = make_data_frame_amsdu_padding_too_short();
data::harness::assert_msdus_llc_frame_eq(
mac::DataFrame::parse(bytes.as_slice(), false)
.expect("failed to parse aggregated data frame"),
[mac::LlcFrame { hdr: Ref::from_bytes(MSDU_1_LLC_HDR).unwrap(), body: MSDU_1_PAYLOAD }],
);
}
}