use alloc::borrow::ToOwned;
use alloc::fmt;
use alloc::str::FromStr;
use alloc::string::{String, ToString};
use alloc::{vec, vec::Vec};
#[derive(Debug)]
pub enum AddressParseError {
CallsignTooLong,
InvalidFormat,
InvalidSsid { source: core::num::ParseIntError },
SsidOutOfRange,
}
#[cfg(feature = "std")]
impl std::error::Error for AddressParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::InvalidSsid { source } => Some(source),
_ => None,
}
}
}
impl fmt::Display for AddressParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CallsignTooLong => write!(f, "Address can be at most 6 characters long"),
Self::InvalidFormat => write!(
f,
"Address must be a callsign optionally followed by a `-` and numeric SSID. Example: VK7NTK-5"
),
Self::InvalidSsid { source } => write!(f, "Could not parse SSID: {}", source),
Self::SsidOutOfRange => write!(f, "SSID must be between 0 and 15 inclusive"),
}
}
}
#[derive(Debug)]
pub enum FrameParseError {
OnlyNullBytes,
NoEndToAddressField,
AddressFieldTooShort {
start: usize,
end: usize,
},
FrameTooShort {
len: usize,
},
AddressInvalidUtf8 {
source: alloc::string::FromUtf8Error,
},
ContentZeroLength,
MissingPidField,
UnrecognisedSFieldType,
UnrecognisedUFieldType,
WrongSizeFrmrInfo,
}
#[cfg(feature = "std")]
impl std::error::Error for FrameParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::AddressInvalidUtf8 { source } => Some(source),
_ => None,
}
}
}
impl fmt::Display for FrameParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OnlyNullBytes => write!(f, "Supplied frame only contains null bytes"),
Self::NoEndToAddressField => write!(f, "Unable to locate end of address field"),
Self::AddressFieldTooShort { start, end } => {
write!(f, "Address field too short: start {} end {}", start, end)
}
Self::FrameTooShort { len } => write!(f, "Frame is too short: len {}", len),
Self::AddressInvalidUtf8 { .. } => write!(f, "Callsign is not valid UTF-8"),
Self::ContentZeroLength => write!(f, "Content section of frame is empty"),
Self::MissingPidField => write!(f, "Protocol ID field is missing"),
Self::UnrecognisedUFieldType => write!(f, "Unrecognised U field type"),
Self::UnrecognisedSFieldType => write!(f, "Unrecognised S field type"),
Self::WrongSizeFrmrInfo => write!(f, "Wrong size for FRMR info"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ProtocolIdentifier {
Layer3Impl,
X25Plp,
CompressedTcpIp,
UncompressedTcpIp,
SegmentationFragment,
TexnetDatagram,
LinkQuality,
Appletalk,
AppletalkArp,
ArpaIp,
ArpaAddress,
Flexnet,
NetRom,
None,
Escape,
Unknown(u8),
}
impl ProtocolIdentifier {
fn from_byte(byte: u8) -> ProtocolIdentifier {
match byte {
pid if pid & 0b0011_0000 == 0b0001_0000 || pid & 0b0011_0000 == 0b0010_0000 => {
ProtocolIdentifier::Layer3Impl
}
0x01 => ProtocolIdentifier::X25Plp,
0x06 => ProtocolIdentifier::CompressedTcpIp,
0x07 => ProtocolIdentifier::UncompressedTcpIp,
0x08 => ProtocolIdentifier::SegmentationFragment,
0xC3 => ProtocolIdentifier::TexnetDatagram,
0xC4 => ProtocolIdentifier::LinkQuality,
0xCA => ProtocolIdentifier::Appletalk,
0xCB => ProtocolIdentifier::AppletalkArp,
0xCC => ProtocolIdentifier::ArpaIp,
0xCD => ProtocolIdentifier::ArpaAddress,
0xCE => ProtocolIdentifier::Flexnet,
0xCF => ProtocolIdentifier::NetRom,
0xF0 => ProtocolIdentifier::None,
0xFF => ProtocolIdentifier::Escape,
pid => ProtocolIdentifier::Unknown(pid),
}
}
fn to_byte(&self) -> u8 {
match *self {
ProtocolIdentifier::Layer3Impl => 0b0001_0000,
ProtocolIdentifier::X25Plp => 0x01,
ProtocolIdentifier::CompressedTcpIp => 0x06,
ProtocolIdentifier::UncompressedTcpIp => 0x07,
ProtocolIdentifier::SegmentationFragment => 0x08,
ProtocolIdentifier::TexnetDatagram => 0xC3,
ProtocolIdentifier::LinkQuality => 0xC4,
ProtocolIdentifier::Appletalk => 0xCA,
ProtocolIdentifier::AppletalkArp => 0xCB,
ProtocolIdentifier::ArpaIp => 0xCC,
ProtocolIdentifier::ArpaAddress => 0xCD,
ProtocolIdentifier::Flexnet => 0xCE,
ProtocolIdentifier::NetRom => 0xCF,
ProtocolIdentifier::None => 0xF0,
ProtocolIdentifier::Escape => 0xFF,
ProtocolIdentifier::Unknown(pid) => pid,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CommandResponse {
Command,
Response,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Information {
pub pid: ProtocolIdentifier,
pub info: Vec<u8>,
pub receive_sequence: u8,
pub send_sequence: u8,
pub poll: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReceiveReady {
pub receive_sequence: u8,
pub poll_or_final: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReceiveNotReady {
pub receive_sequence: u8,
pub poll_or_final: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Reject {
pub receive_sequence: u8,
pub poll_or_final: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SetAsynchronousBalancedMode {
pub poll: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Disconnect {
pub poll: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DisconnectedMode {
pub final_bit: bool, }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnnumberedAcknowledge {
pub final_bit: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FrameReject {
pub final_bit: bool,
pub rejected_control_field_raw: u8,
pub z: bool,
pub y: bool,
pub x: bool,
pub w: bool,
pub receive_sequence: u8,
pub send_sequence: u8,
pub command_response: CommandResponse,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnnumberedInformation {
pub pid: ProtocolIdentifier,
pub info: Vec<u8>,
pub poll_or_final: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownContent {
pub raw: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FrameContent {
Information(Information),
ReceiveReady(ReceiveReady),
ReceiveNotReady(ReceiveNotReady),
Reject(Reject),
SetAsynchronousBalancedMode(SetAsynchronousBalancedMode),
Disconnect(Disconnect),
DisconnectedMode(DisconnectedMode),
UnnumberedAcknowledge(UnnumberedAcknowledge),
FrameReject(FrameReject),
UnnumberedInformation(UnnumberedInformation),
UnknownContent(UnknownContent),
}
impl FrameContent {
fn encode(&self) -> Vec<u8> {
let mut encoded = Vec::new();
match *self {
FrameContent::Information(ref i) => {
let mut c: u8 = 0;
c |= (i.receive_sequence & 0b0000_0111) << 5;
c |= if i.poll { 1 << 4 } else { 0 };
c |= (i.send_sequence & 0b0000_0111) << 1;
encoded.push(c);
encoded.push(i.pid.to_byte());
encoded.extend(&i.info);
}
FrameContent::ReceiveReady(ref rr) => {
let mut c: u8 = 0b0000_0001;
c |= if rr.poll_or_final { 1 << 4 } else { 0 };
c |= (rr.receive_sequence & 0b0000_0111) << 5;
encoded.push(c);
}
FrameContent::ReceiveNotReady(ref rnr) => {
let mut c: u8 = 0b0000_0101;
c |= if rnr.poll_or_final { 1 << 4 } else { 0 };
c |= (rnr.receive_sequence & 0b0000_0111) << 5;
encoded.push(c);
}
FrameContent::Reject(ref rej) => {
let mut c: u8 = 0b0000_1001;
c |= if rej.poll_or_final { 1 << 4 } else { 0 };
c |= (rej.receive_sequence & 0b0000_0111) << 5;
encoded.push(c);
}
FrameContent::SetAsynchronousBalancedMode(ref sabm) => {
let mut c: u8 = 0b0010_1111;
c |= if sabm.poll { 1 << 4 } else { 0 };
encoded.push(c);
}
FrameContent::Disconnect(ref disc) => {
let mut c: u8 = 0b0100_0011;
c |= if disc.poll { 1 << 4 } else { 0 };
encoded.push(c);
}
FrameContent::DisconnectedMode(ref dm) => {
let mut c: u8 = 0b0000_1111;
c |= if dm.final_bit { 1 << 4 } else { 0 };
encoded.push(c);
}
FrameContent::UnnumberedAcknowledge(ref ua) => {
let mut c: u8 = 0b0110_0011;
c |= if ua.final_bit { 1 << 4 } else { 0 };
encoded.push(c);
}
FrameContent::FrameReject(ref fr) => {
let mut c: u8 = 0b1000_0111;
c |= if fr.final_bit { 1 << 4 } else { 0 };
encoded.push(c);
let mut frmr1: u8 = 0;
frmr1 |= if fr.z { 1 << 3 } else { 0 };
frmr1 |= if fr.y { 1 << 2 } else { 0 };
frmr1 |= if fr.x { 1 << 1 } else { 0 };
frmr1 |= if fr.w { 1 } else { 0 };
encoded.push(frmr1);
let mut frmr2: u8 = 0;
frmr2 |= (fr.receive_sequence & 0b0000_0111) << 5;
frmr2 |= if fr.command_response == CommandResponse::Response {
1 << 4
} else {
0
};
frmr2 |= (fr.send_sequence & 0b0000_0111) << 1;
encoded.push(frmr2);
encoded.push(fr.rejected_control_field_raw);
}
FrameContent::UnnumberedInformation(ref ui) => {
let mut c: u8 = 0b0000_0011;
c |= if ui.poll_or_final { 1 << 4 } else { 0 };
encoded.push(c);
encoded.push(ui.pid.to_byte());
encoded.extend(&ui.info);
}
FrameContent::UnknownContent(ref uc) => {
encoded.extend(&uc.raw);
}
}
encoded
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address {
callsign: String,
ssid: u8,
}
impl Address {
pub fn from_parts(callsign: String, ssid: u8) -> Result<Self, AddressParseError> {
let callsign = callsign.to_uppercase();
if callsign.is_empty() {
return Err(AddressParseError::InvalidFormat);
}
if callsign.len() > 6 {
return Err(AddressParseError::CallsignTooLong);
}
for c in callsign.chars() {
if !c.is_alphanumeric() {
return Err(AddressParseError::InvalidFormat);
}
}
if ssid > 15 {
return Err(AddressParseError::SsidOutOfRange);
}
Ok(Address { callsign, ssid })
}
pub fn callsign(&self) -> &str {
&self.callsign
}
pub fn ssid(&self) -> u8 {
self.ssid
}
fn to_bytes(&self, high_bit: bool, final_in_address: bool) -> Vec<u8> {
let mut encoded = Vec::new();
for b in self.callsign.as_bytes() {
encoded.push(b << 1);
}
while encoded.len() != 6 {
encoded.push(b' ' << 1);
}
let high = if high_bit { 0b1000_0000 } else { 0 };
let low = if final_in_address { 0b0000_0001 } else { 0 };
let ssid_byte = (self.ssid << 1) | 0b0110_0000 | high | low;
encoded.push(ssid_byte);
encoded
}
}
impl Default for Address {
fn default() -> Address {
Address {
callsign: "NOCALL".to_string(),
ssid: 0,
}
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ssid_str = match self.ssid {
0 => "".to_string(),
ssid => alloc::format!("-{}", ssid),
};
write!(f, "{}{}", self.callsign, ssid_str)
}
}
impl FromStr for Address {
type Err = AddressParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split('-').collect();
if parts.len() == 1 {
Self::from_parts(parts[0].to_owned(), 0)
} else if parts.len() == 2 {
let ssid = parts[1]
.parse::<u8>()
.map_err(|e| AddressParseError::InvalidSsid { source: e })?;
Self::from_parts(parts[0].to_owned(), ssid)
} else {
Err(AddressParseError::InvalidFormat)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RouteEntry {
pub repeater: Address,
pub has_repeated: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Ax25Frame {
pub source: Address,
pub destination: Address,
pub route: Vec<RouteEntry>,
pub command_or_response: Option<CommandResponse>,
pub content: FrameContent,
}
impl Ax25Frame {
pub fn from_bytes(bytes: &[u8]) -> Result<Ax25Frame, FrameParseError> {
let addr_start = bytes
.iter()
.position(|&c| c != 0)
.ok_or(FrameParseError::OnlyNullBytes)?;
let addr_end = bytes
.iter()
.position(|&c| c & 0x01 == 0x01)
.ok_or(FrameParseError::NoEndToAddressField)?;
let control = addr_end + 1;
if addr_end - addr_start + 1 < 14 {
return Err(FrameParseError::AddressFieldTooShort {
start: addr_start,
end: addr_end,
});
}
if control >= bytes.len() {
return Err(FrameParseError::FrameTooShort { len: bytes.len() });
}
let dest = parse_address(&bytes[addr_start..addr_start + 7])?;
let src = parse_address(&bytes[addr_start + 7..addr_start + 14])?;
let rpt_count = (addr_end + 1 - addr_start - 14) / 7;
let mut route: Vec<RouteEntry> = Vec::new();
for i in 0..rpt_count {
let repeater =
parse_address(&bytes[addr_start + 14 + i * 7..addr_start + 14 + (i + 1) * 7])?;
let entry = RouteEntry {
has_repeated: repeater.high_bit,
repeater: repeater.address,
};
route.push(entry);
}
let content = parse_content(&bytes[control..])?;
let command_or_response = match (dest.high_bit, src.high_bit) {
(true, false) => Some(CommandResponse::Command),
(false, true) => Some(CommandResponse::Response),
_ => None,
};
Ok(Ax25Frame {
source: src.address,
destination: dest.address,
route,
content,
command_or_response,
})
}
pub fn new_simple_ui_frame(source: Address, destination: Address, info: Vec<u8>) -> Self {
Self {
source,
destination,
content: FrameContent::UnnumberedInformation(UnnumberedInformation {
pid: ProtocolIdentifier::None,
info,
poll_or_final: false,
}),
..Default::default()
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut frame = Vec::new();
let (dest_c_bit, src_c_bit) = match self.command_or_response {
Some(CommandResponse::Command) => (true, false),
Some(CommandResponse::Response) => (false, true),
_ => (true, false), };
frame.extend(self.destination.to_bytes(dest_c_bit, false));
frame.extend(self.source.to_bytes(src_c_bit, self.route.is_empty()));
for (i, entry) in self.route.iter().enumerate() {
frame.extend(
entry
.repeater
.to_bytes(entry.has_repeated, i + 1 == self.route.len()),
);
}
frame.extend(self.content.encode());
frame
}
pub fn info_string_lossy(&self) -> Option<String> {
match self.content {
FrameContent::Information(ref i) => Some(String::from_utf8_lossy(&i.info).into_owned()),
FrameContent::UnnumberedInformation(ref ui) => {
Some(String::from_utf8_lossy(&ui.info).into_owned())
}
_ => None,
}
}
}
impl Default for Ax25Frame {
fn default() -> Self {
Self {
source: Address::default(),
destination: Address::default(),
route: vec![],
command_or_response: Some(CommandResponse::Command),
content: FrameContent::UnnumberedInformation(UnnumberedInformation {
pid: ProtocolIdentifier::None,
info: vec![],
poll_or_final: false,
}),
}
}
}
impl fmt::Display for Ax25Frame {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let info_display = match self.info_string_lossy() {
Some(ref info) => info.clone(),
None => "-".to_string(),
};
write!(
f,
"Source\t\t{}\nDestination\t{}\n\
Data\t\t\"{}\"",
self.source, self.destination, info_display
)
}
}
struct ParsedAddress {
address: Address,
high_bit: bool,
}
fn parse_address(bytes: &[u8]) -> Result<ParsedAddress, FrameParseError> {
let mut dest_utf8: Vec<u8> = bytes[0..6]
.iter()
.rev()
.map(|&c| c >> 1)
.skip_while(|&c| c == b' ')
.collect::<Vec<u8>>();
dest_utf8.reverse();
let address = Address {
callsign: String::from_utf8(dest_utf8)
.map_err(|e| FrameParseError::AddressInvalidUtf8 { source: e })?,
ssid: (bytes[6] >> 1) & 0x0f,
};
Ok(ParsedAddress {
address,
high_bit: bytes[6] & 0b1000_0000 > 0,
})
}
fn parse_i_frame(bytes: &[u8]) -> Result<FrameContent, FrameParseError> {
if bytes.len() < 2 {
return Err(FrameParseError::MissingPidField);
}
let c = bytes[0]; Ok(FrameContent::Information(Information {
receive_sequence: (c & 0b1110_0000) >> 5,
send_sequence: (c & 0b0000_1110) >> 1,
poll: (c & 0b0001_0000) > 0,
pid: ProtocolIdentifier::from_byte(bytes[1]),
info: bytes[2..].to_vec(), }))
}
fn parse_s_frame(bytes: &[u8]) -> Result<FrameContent, FrameParseError> {
let c = bytes[0];
let n_r = (c & 0b1110_0000) >> 5;
let poll_or_final = (c & 0b0001_0000) > 0;
match c & 0b0000_1111 {
0b0000_0001 => Ok(FrameContent::ReceiveReady(ReceiveReady {
receive_sequence: n_r,
poll_or_final,
})),
0b0000_0101 => Ok(FrameContent::ReceiveNotReady(ReceiveNotReady {
receive_sequence: n_r,
poll_or_final,
})),
0b0000_1001 => Ok(FrameContent::Reject(Reject {
receive_sequence: n_r,
poll_or_final,
})),
_ => Err(FrameParseError::UnrecognisedSFieldType),
}
}
fn parse_u_frame(bytes: &[u8]) -> Result<FrameContent, FrameParseError> {
let c = bytes[0];
let poll_or_final = c & 0b0001_0000 > 0;
match c & 0b1110_1111 {
0b0010_1111 => Ok(FrameContent::SetAsynchronousBalancedMode(
SetAsynchronousBalancedMode {
poll: poll_or_final,
},
)),
0b0100_0011 => Ok(FrameContent::Disconnect(Disconnect {
poll: poll_or_final,
})),
0b0000_1111 => Ok(FrameContent::DisconnectedMode(DisconnectedMode {
final_bit: poll_or_final,
})),
0b0110_0011 => Ok(FrameContent::UnnumberedAcknowledge(UnnumberedAcknowledge {
final_bit: poll_or_final,
})),
0b1000_0111 => parse_frmr_frame(bytes),
0b0000_0011 => parse_ui_frame(bytes),
_ => Err(FrameParseError::UnrecognisedUFieldType),
}
}
fn parse_ui_frame(bytes: &[u8]) -> Result<FrameContent, FrameParseError> {
if bytes.len() < 2 {
return Err(FrameParseError::MissingPidField);
}
Ok(FrameContent::UnnumberedInformation(UnnumberedInformation {
poll_or_final: bytes[0] & 0b0001_0000 > 0,
pid: ProtocolIdentifier::from_byte(bytes[1]),
info: bytes[2..].to_vec(),
}))
}
fn parse_frmr_frame(bytes: &[u8]) -> Result<FrameContent, FrameParseError> {
if bytes.len() != 4 {
return Err(FrameParseError::WrongSizeFrmrInfo);
}
Ok(FrameContent::FrameReject(FrameReject {
final_bit: bytes[0] & 0b0001_0000 > 0,
rejected_control_field_raw: bytes[3],
z: bytes[1] & 0b0000_1000 > 0,
y: bytes[1] & 0b0000_0100 > 0,
x: bytes[1] & 0b0000_0010 > 0,
w: bytes[1] & 0b0000_0001 > 0,
receive_sequence: (bytes[2] & 0b1110_0000) >> 5,
command_response: if bytes[2] & 0b0001_0000 > 0 {
CommandResponse::Response
} else {
CommandResponse::Command
},
send_sequence: (bytes[2] & 0b0000_1110) >> 1,
}))
}
fn parse_content(bytes: &[u8]) -> Result<FrameContent, FrameParseError> {
if bytes.is_empty() {
return Err(FrameParseError::ContentZeroLength);
}
match bytes[0] {
c if c & 0x01 == 0x00 => parse_i_frame(bytes),
c if c & 0x03 == 0x01 => parse_s_frame(bytes),
c if c & 0x03 == 0x03 => parse_u_frame(bytes),
_ => Ok(FrameContent::UnknownContent(UnknownContent {
raw: bytes.to_vec(),
})),
}
}
#[test]
fn pid_test() {
assert_eq!(
ProtocolIdentifier::from_byte(0x01),
ProtocolIdentifier::X25Plp
);
assert_eq!(
ProtocolIdentifier::from_byte(0xCA),
ProtocolIdentifier::Appletalk
);
assert_eq!(
ProtocolIdentifier::from_byte(0xFF),
ProtocolIdentifier::Escape
);
assert_eq!(
ProtocolIdentifier::from_byte(0x45),
ProtocolIdentifier::Unknown(0x45)
);
assert_eq!(
ProtocolIdentifier::from_byte(0x10),
ProtocolIdentifier::Layer3Impl
);
assert_eq!(
ProtocolIdentifier::from_byte(0x20),
ProtocolIdentifier::Layer3Impl
);
assert_eq!(
ProtocolIdentifier::from_byte(0xA5),
ProtocolIdentifier::Layer3Impl
);
}
#[test]
fn test_address_fromstr() {
assert_eq!(
Address::from_str("VK7NTK-1").unwrap(),
Address {
callsign: "VK7NTK".to_string(),
ssid: 1,
}
);
assert_eq!(
Address::from_str("ID-15").unwrap(),
Address {
callsign: "ID".to_string(),
ssid: 15,
}
);
let addr_0 = Address::from_str("VK7NTK").unwrap();
assert_eq!(addr_0.callsign(), "VK7NTK");
assert_eq!(addr_0.ssid(), 0);
assert!(Address::from_str("vk7ntk-5").is_ok());
assert!(Address::from_str("8").is_ok());
assert!(Address::from_str("-1").is_err());
assert!(Address::from_str("VK7N -5").is_err());
assert!(Address::from_str("VK7NTK-16").is_err());
assert!(Address::from_str("vk7n--1").is_err());
}
#[test]
fn test_round_trips() {
use std::fs::{read_dir, File};
use std::io::Read;
let mut paths: Vec<_> = read_dir("testdata/linux-ax0")
.unwrap()
.map(|r| r.unwrap())
.collect();
paths.sort_by_key(|dir| dir.path());
for entry in paths {
let entry_path = entry.path();
println!("Testing round trip on {}", entry_path.display());
let filename = entry_path.to_str().unwrap();
let mut file = File::open(filename).unwrap();
let mut frame_data: Vec<u8> = Vec::new();
let _ = file.read_to_end(&mut frame_data);
let frame_data_fixed = &frame_data[1..];
match Ax25Frame::from_bytes(frame_data_fixed) {
Ok(parsed) => {
assert_eq!(frame_data_fixed, &parsed.to_bytes()[..])
}
Err(e) => panic!("Could not parse! {}", e),
};
}
}