Skip to content

Commit

Permalink
Major refactor.
Browse files Browse the repository at this point in the history
  • Loading branch information
Frostie314159 committed Dec 22, 2023
1 parent d15a3b7 commit 7526d68
Show file tree
Hide file tree
Showing 33 changed files with 1,632 additions and 1,442 deletions.
18 changes: 4 additions & 14 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,6 @@ repository = "https://github.com/Frostie314159/awdl-frame-parser"
opt-level = 3

[features]
read = ["tlv-rs/read"]
write = ["tlv-rs/write"]
version_tlv = []
dns_sd_tlvs = []
data_tlvs = []
sync_elect_tlvs = []
data_frame = []
debug = ["mac-parser/debug", "tlv-rs/debug"]
all_tlvs = ["version_tlv", "dns_sd_tlvs", "data_tlvs", "sync_elect_tlvs"]
default = ["write", "read", "all_tlvs", "data_frame", "debug"]

[dev-dependencies]
criterion = { version = "0.4.0", features = ["html_reports"] }
Expand All @@ -31,10 +21,10 @@ name = "awdl_frame_parser"
harness = false

[dependencies]
bin-utils = "0.2.1"
heapless = "0.7.16"
mac-parser = { version = "0.1.2", default-features = false }
macro-bits = "0.1.1"
mac-parser = { git = "https://github.com/Frostie314159/mac-parser.git" }
macro-bits = "0.1.4"
num-integer = { version = "0.1.45", default-features = false }
tlv-rs = { version = "0.2.1", default-features = false }
scroll = { git = "https://github.com/Frostie314159/scroll.git", branch = "fixed-array-impl", default-features = false }
tlv-rs = { git = "https://github.com/Frostie314159/tlv-rs.git" }
try_take = "0.1.0"
51 changes: 30 additions & 21 deletions benches/awdl_frame_parser.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use awdl_frame_parser::{
action_frame::AWDLActionFrame,
tlvs::{
data::DataPathStateTLV,
data_path::DataPathStateTLV,
dns_sd::{ArpaTLV, ServiceParametersTLV, ServiceResponseTLV},
sync_elect::{ChannelSequenceTLV, SyncTreeTLV},
},
};
use bin_utils::{Read, Write};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use scroll::{Pread, Pwrite};

macro_rules! bench_read {
($bench_name:ident, $type_name:ty) => {
Expand Down Expand Up @@ -50,12 +50,8 @@ bench_read!(bench_read_af, AWDLActionFrame);
bench_write!(bench_write_af, AWDLActionFrame);
bench_read!(bench_read_service_parmeters_tlv, ServiceParametersTLV);
bench_write!(bench_write_service_parameters_tlv, ServiceParametersTLV);
bench_read!(bench_read_arpa_tlv, ArpaTLV);
bench_write!(bench_write_arpa_tlv, ArpaTLV);
bench_read!(bench_read_channel_sequence_tlv, ChannelSequenceTLV);
bench_write!(bench_write_channel_sequence_tlv, ChannelSequenceTLV);
bench_read!(bench_read_service_response_tlv, ServiceResponseTLV);
bench_write!(bench_write_service_response_tlv, ServiceResponseTLV);
bench_read!(bench_read_sync_tree_tlv, SyncTreeTLV);
bench_write!(bench_write_sync_tree_tlv, SyncTreeTLV);
bench_read!(bench_read_data_path_state_tlv, DataPathStateTLV);
Expand Down Expand Up @@ -96,21 +92,34 @@ fn criterion_benchmark(c: &mut Criterion) {
register_bench_fn!(c, bench_write_sync_tree_tlv, &sync_tree);

let service_response_tlv_bytes =
include_bytes!("../test_bins/service_response_tlv_txt.bin")[3..].to_vec();
register_bench_fn!(
c,
bench_read_service_response_tlv,
service_response_tlv_bytes.clone()
);
let service_response =
ServiceResponseTLV::from_bytes(&mut service_response_tlv_bytes.clone().into_iter())
.unwrap();
register_bench_fn!(c, bench_write_service_response_tlv, &service_response);

let arpa_tlv_bytes = include_bytes!("../test_bins/arpa_tlv.bin")[3..].to_vec();
register_bench_fn!(c, bench_read_arpa_tlv, arpa_tlv_bytes.clone());
let arpa_tlv = ArpaTLV::from_bytes(&mut arpa_tlv_bytes.clone().into_iter()).unwrap();
register_bench_fn!(c, bench_write_arpa_tlv, &arpa_tlv);
&include_bytes!("../test_bins/service_response_tlv_txt.bin")[3..];
c.bench_function("bench_read_service_response_tlv", |b| {
b.iter(|| {
let _ = black_box(service_response_tlv_bytes).pread::<ServiceResponseTLV<'_>>(0);
})
});
let service_response = service_response_tlv_bytes
.pread::<ServiceResponseTLV<'_>>(0)
.unwrap();
let buf = [0x00; 0xff];
c.bench_function("bench_write_service_response_tlv", |b| {
b.iter(|| {
let _ = black_box(buf).pwrite(service_response.clone(), 0).unwrap();
})
});
let arpa_tlv_bytes = &include_bytes!("../test_bins/arpa_tlv.bin")[3..];
c.bench_function("bench_read_arpa_tlv", |b| {
b.iter(|| {
let _ = black_box(arpa_tlv_bytes).pread::<ArpaTLV<'_>>(0);
})
});
let arpa_tlv = service_response_tlv_bytes.pread::<ArpaTLV<'_>>(0).unwrap();
let buf = [0x00; 0xff];
c.bench_function("bench_write_arpa_tlv", |b| {
b.iter(|| {
let _ = black_box(buf).pwrite(arpa_tlv.clone(), 0).unwrap();
})
});

let channel_sequence_tlv_bytes =
include_bytes!("../test_bins/channel_sequence_tlv.bin")[3..].to_vec();
Expand Down
24 changes: 13 additions & 11 deletions examples/af.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use awdl_frame_parser::{
action_frame::AWDLActionFrame,
tlvs::{version::VersionTLV, TLVType, AWDLTLV},
};
use bin_utils::{Read, Write};
use awdl_frame_parser::{action_frame::AWDLActionFrame, tlvs::AWDLTLV};
use scroll::Pread;

fn main() {
let bytes = include_bytes!("../test_bins/mif.bin");
let af = AWDLActionFrame::from_bytes(&mut bytes.iter().copied()).unwrap();
let af = bytes.pread::<AWDLActionFrame>(0).unwrap();

println!("{af:#?}");
assert_eq!(af.to_bytes(), bytes.to_vec());

let version = af.get_tlvs(TLVType::Version).unwrap()[0].clone(); // Since a TLV could be present multiple times we have to this.
let version: VersionTLV = version.try_into().unwrap();
println!("awdl version: {version:#?}");
let _tlv: AWDLTLV = version.into();
println!(
"awdl version: {:#?}",
af.get_named_tlvs()
.find_map(|tlv| if let AWDLTLV::Version(version_tlv) = tlv {
Some(version_tlv)
} else {
None
})
.unwrap()
);
}
186 changes: 88 additions & 98 deletions src/action_frame.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,29 @@
use alloc::vec::Vec;

use bin_utils::*;
#[cfg(feature = "read")]
use try_take::try_take;
use macro_bits::serializable_enum;
use scroll::{
ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
Endian, Pread, Pwrite,
};

#[cfg(feature = "debug")]
use core::fmt::Debug;

use crate::{
common::AWDLVersion,
tlvs::{TLVType, AWDLTLV},
};

#[cfg_attr(feature = "debug", derive(Debug))]
#[derive(Clone, Copy, PartialEq, Eq)]
/// The subtype of the AF.
pub enum AWDLActionFrameSubType {
/// **P**eriodic **S**ynchronization **F**rame
PSF,
/// **M**aster **I**ndication **F**rame
MIF,

Unknown(u8),
}
enum_to_int! {
u8,
AWDLActionFrameSubType,

0x00,
AWDLActionFrameSubType::PSF,
0x03,
AWDLActionFrameSubType::MIF
use core::{iter::repeat, fmt::Debug};

use crate::tlvs::AWDLTLV;

serializable_enum! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum AWDLActionFrameSubType: u8 {
#[default]
/// **P**eriodic **S**ynchronization **F**rame
PSF => 0x00,
/// **M**aster **I**ndication **F**rame
MIF => 0x03
}
}

#[derive(Clone, PartialEq, Eq)]
/// An AWDL AF(**A**ction **F**rame).
pub struct AWDLActionFrame {
/**
* This is the version of the AWDL protocol.
* This is, for an unknown reason, always 1.0, the actual version is found in the Version TLV.
*/
pub awdl_version: AWDLVersion,

pub struct AWDLActionFrame<'a> {
/**
* This is the subtype of the AF. Options are [MIF](AWDLActionFrameSubType::MIF) and [PSF](AWDLActionFrameSubType::PSF)
*/
Expand All @@ -58,79 +40,87 @@ pub struct AWDLActionFrame {

//TLVs
/// The TLVs contained in the action frame.
pub tlvs: Vec<AWDLTLV>,
pub tagged_data: &'a [u8],
}
impl AWDLActionFrame {
pub fn get_tlvs(&self, tlv_type: TLVType) -> Option<Vec<&AWDLTLV>> {
return Some(
self.tlvs
.iter()
.filter(|tlv| tlv.tlv_type == tlv_type)
.collect(),
);
impl<'a> AWDLActionFrame<'a> {
pub fn get_named_tlvs(&'a self) -> impl Iterator<Item = AWDLTLV<'a>> {
repeat(()).scan(0, |offset, _| self.tagged_data.gread(offset).ok())
}
}
#[cfg(feature = "read")]
impl Read for AWDLActionFrame {
fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError> {
let mut header = try_take(data, 0xC).map_err(ParserError::TooLittleData)?;

// Using unwrap is ok now, since we would've already returned if data is shorter than 12 bytes.
if header.next().unwrap() != 0x08 {
return Err(ParserError::InvalidMagic);
}
let awdl_version = AWDLVersion::from(header.next().unwrap());

let subtype = header.next().unwrap().into();
let _ = header.next();

let phy_tx_time = u32::from_le_bytes(header.next_chunk().unwrap());
let target_tx_time = u32::from_le_bytes(header.next_chunk().unwrap());

let tlvs = <Vec<AWDLTLV> as Read>::from_bytes(data)?;

Ok(Self {
awdl_version,
subtype,
phy_tx_time,
target_tx_time,
tlvs,
})
}
}
#[cfg(feature = "write")]
impl Write for AWDLActionFrame {
fn to_bytes(&self) -> alloc::vec::Vec<u8> {
let mut header = [0x00; 12];

header[0] = 0x08;
header[1] = self.awdl_version.into();
header[2] = self.subtype.into();
header[4..8].copy_from_slice(&self.phy_tx_time.to_le_bytes());
header[8..12].copy_from_slice(&self.target_tx_time.to_le_bytes());
header.into_iter().chain(self.tlvs.to_bytes()).collect()
}
}
#[cfg(feature = "debug")]
impl Debug for AWDLActionFrame {
impl Debug for AWDLActionFrame<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("AWDLActionFrame")
.field("awdl_version", &self.awdl_version)
.field("subtype", &self.subtype)
.field("phy_tx_time", &self.phy_tx_time)
.field("target_tx_time", &self.target_tx_time)
.field(
"tlvs",
&self.tlvs.iter().map(|x| x.tlv_type).collect::<Vec<_>>(),
)
.field_with("tagged_data", |f| f.debug_list().entries(self.get_named_tlvs()).finish())
.finish()

}
}
impl MeasureWith<()> for AWDLActionFrame<'_> {
fn measure_with(&self, _ctx: &()) -> usize {
12 + self.tagged_data.len()
}
}

impl<'a> TryFromCtx<'a> for AWDLActionFrame<'a> {
type Error = scroll::Error;
fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
let mut offset = 0;
if from.gread::<u8>(&mut offset)? != 0x8u8 {
return Err(scroll::Error::BadInput {
size: offset,
msg: "AF didn't start with 0x8.",
});
}
if from.gread::<u8>(&mut offset)? != 0x10u8 {
return Err(scroll::Error::BadInput {
size: offset,
msg: "AF header version wasn't 1.0.",
});
}
let subtype = AWDLActionFrameSubType::from_representation(from.gread(&mut offset)?);
offset += 1;

let phy_tx_time = from.gread_with(&mut offset, Endian::Little)?;
let target_tx_time = from.gread_with(&mut offset, Endian::Little)?;
let tags = &from[offset..];

Ok((
Self {
subtype,
phy_tx_time,
target_tx_time,
tagged_data: tags,
},
offset,
))
}
}
impl<'a> TryIntoCtx for AWDLActionFrame<'a> {
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
buf.gwrite(8u8, &mut offset)?;
buf.gwrite(0x10u8, &mut offset)?;
buf.gwrite(self.subtype.to_representation(), &mut offset)?;
offset += 1;
buf.gwrite_with(self.phy_tx_time, &mut offset, Endian::Little)?;
buf.gwrite_with(self.target_tx_time, &mut offset, Endian::Little)?;
buf.gwrite(self.tagged_data, &mut offset)?;
Ok(offset)
}
}
#[cfg(test)]
#[test]
fn test_action_frame() {
let packet_bytes: &[u8] = include_bytes!("../test_bins/mif.bin");

let frame = AWDLActionFrame::from_bytes(&mut packet_bytes.iter().copied()).unwrap();
assert_eq!(frame.to_bytes(), packet_bytes);
use alloc::vec;

let packet_bytes = include_bytes!("../test_bins/mif.bin");
let parsed_af = packet_bytes.pread::<AWDLActionFrame<'_>>(0).unwrap();
let mut buf = vec![0; parsed_af.measure_with(&())];
assert_eq!(buf.len(), packet_bytes.len());
buf.pwrite(parsed_af, 0).unwrap();
assert_eq!(buf, packet_bytes);
}
5 changes: 2 additions & 3 deletions src/common/awdl_dns_compression.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use macro_bits::serializable_enum;

serializable_enum! {
#[cfg_attr(feature = "debug", derive(Debug))]
#[derive(Clone, Copy, Default, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
/// Compressed dns-sd domains/services. Compression might be the wrong word though.
pub enum AWDLDnsCompression: u16 {
Null => 0xC000,
Expand Down Expand Up @@ -38,7 +37,7 @@ serializable_enum! {
}
}
impl AWDLDnsCompression {
pub fn to_string(&self) -> &'static str {
pub fn to_static_string(&self) -> &'static str {
match self {
AWDLDnsCompression::Null => "",
AWDLDnsCompression::AirPlayTcpLocal => "_airplay._tcp.local",
Expand Down
Loading

0 comments on commit 7526d68

Please sign in to comment.