X-Git-Url: https://code.octet-stream.net/m17rt/blobdiff_plain/e67ea96c8a3d7c23ba29c6ed91ddb451927176a1..2798b7a8f62b73aa2a88d4b34e861debd6462015:/m17core/src/protocol.rs diff --git a/m17core/src/protocol.rs b/m17core/src/protocol.rs index 96def5b..f2e154e 100755 --- a/m17core/src/protocol.rs +++ b/m17core/src/protocol.rs @@ -1,23 +1,23 @@ -use crate::address::Address; +use crate::address::{encode_address, Address}; pub(crate) const LSF_SYNC: [i8; 8] = [1, 1, 1, 1, -1, -1, 1, -1]; pub(crate) const BERT_SYNC: [i8; 8] = [-1, 1, -1, -1, 1, 1, 1, 1]; pub(crate) const STREAM_SYNC: [i8; 8] = [-1, -1, -1, -1, 1, 1, -1, 1]; pub(crate) const PACKET_SYNC: [i8; 8] = [1, -1, 1, 1, -1, -1, -1, -1]; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum Mode { Packet, Stream, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum DataType { Reserved, Data, Voice, VoiceAndData, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum EncryptionType { None, Scrambler, @@ -29,10 +29,11 @@ pub enum EncryptionType { pub enum Frame { Lsf(LsfFrame), Stream(StreamFrame), - // Packet + Packet(PacketFrame), // BERT } +#[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum PacketType { /// RAW Raw, @@ -53,6 +54,22 @@ pub enum PacketType { } impl PacketType { + pub fn from_proto(buf: &[u8]) -> Option<(Self, usize)> { + buf.utf8_chunks() + .next() + .and_then(|chunk| chunk.valid().chars().next()) + .map(|c| match c as u32 { + 0x00 => (PacketType::Raw, 1), + 0x01 => (PacketType::Ax25, 1), + 0x02 => (PacketType::Aprs, 1), + 0x03 => (PacketType::SixLowPan, 1), + 0x04 => (PacketType::Ipv4, 1), + 0x05 => (PacketType::Sms, 1), + 0x06 => (PacketType::Winlink, 1), + _ => (PacketType::Other(c), c.len_utf8()), + }) + } + pub fn as_proto(&self) -> ([u8; 4], usize) { match self { PacketType::Raw => ([0, 0, 0, 0], 1), @@ -70,29 +87,34 @@ impl PacketType { } } } - - pub fn from_proto(&self, buf: &[u8]) -> Option { - buf.utf8_chunks() - .next() - .and_then(|chunk| chunk.valid().chars().next()) - .map(|c| match c as u32 { - 0x00 => PacketType::Raw, - 0x01 => PacketType::Ax25, - 0x02 => PacketType::Aprs, - 0x03 => PacketType::SixLowPan, - 0x04 => PacketType::Ipv4, - 0x05 => PacketType::Sms, - 0x06 => PacketType::Winlink, - _ => PacketType::Other(c), - }) - } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct LsfFrame(pub [u8; 30]); impl LsfFrame { - pub fn crc(&self) -> u16 { + pub fn new_voice(source: &Address, destination: &Address) -> Self { + let mut out = Self([0u8; 30]); + out.set_source(source); + out.set_destination(destination); + out.set_mode(Mode::Stream); + out.set_data_type(DataType::Voice); + out.set_encryption_type(EncryptionType::None); + out + } + + pub fn new_packet(source: &Address, destination: &Address) -> Self { + let mut out = Self([0u8; 30]); + out.set_source(source); + out.set_destination(destination); + out.set_mode(Mode::Packet); + out.set_data_type(DataType::Data); + out.set_encryption_type(EncryptionType::None); + out + } + + /// Calculate crc of entire frame. If zero, it is a valid frame. + pub fn check_crc(&self) -> u16 { crate::crc::m17_crc(&self.0) } @@ -105,7 +127,7 @@ impl LsfFrame { } pub fn mode(&self) -> Mode { - if self.0[12] & 0x01 > 0 { + if self.lsf_type() & 0x0001 > 0 { Mode::Stream } else { Mode::Packet @@ -123,7 +145,7 @@ impl LsfFrame { } pub fn encryption_type(&self) -> EncryptionType { - match (self.0[12] >> 3) & 0x03 { + match (self.lsf_type() >> 3) & 0x0003 { 0b00 => EncryptionType::None, 0b01 => EncryptionType::Scrambler, 0b10 => EncryptionType::Aes, @@ -132,16 +154,71 @@ impl LsfFrame { } } + // TODO: encryption sub-type + pub fn channel_access_number(&self) -> u8 { - (self.0[12] >> 7) & 0x0f + ((self.lsf_type() >> 7) & 0x000f) as u8 } pub fn meta(&self) -> [u8; 14] { self.0[14..28].try_into().unwrap() } + + pub fn set_destination(&mut self, destination: &Address) { + self.0[0..6].copy_from_slice(&encode_address(&destination)); + self.recalculate_crc(); + } + + pub fn set_source(&mut self, source: &Address) { + self.0[6..12].copy_from_slice(&encode_address(&source)); + self.recalculate_crc(); + } + + pub fn set_mode(&mut self, mode: Mode) { + let existing_type = self.lsf_type(); + let new_type = (existing_type & !0x0001) | if mode == Mode::Stream { 1 } else { 0 }; + self.0[12..14].copy_from_slice(&new_type.to_be_bytes()); + self.recalculate_crc(); + } + + pub fn set_data_type(&mut self, data_type: DataType) { + let type_part = match data_type { + DataType::Reserved => 0b00 << 1, + DataType::Data => 0b01 << 1, + DataType::Voice => 0b10 << 1, + DataType::VoiceAndData => 0b11 << 1, + }; + let existing_type = self.lsf_type(); + let new_type = (existing_type & !0x0006) | type_part; + self.0[12..14].copy_from_slice(&new_type.to_be_bytes()); + self.recalculate_crc(); + } + + pub fn set_encryption_type(&mut self, encryption_type: EncryptionType) { + let type_part = match encryption_type { + EncryptionType::None => 0b00 << 3, + EncryptionType::Scrambler => 0b01 << 3, + EncryptionType::Aes => 0b10 << 3, + EncryptionType::Other => 0b11 << 3, + }; + let existing_type = self.lsf_type(); + let new_type = (existing_type & !0x0018) | type_part; + self.0[12..14].copy_from_slice(&new_type.to_be_bytes()); + self.recalculate_crc(); + } + + fn recalculate_crc(&mut self) { + let new_crc = crate::crc::m17_crc(&self.0[0..28]); + self.0[28..30].copy_from_slice(&new_crc.to_be_bytes()); + debug_assert_eq!(self.check_crc(), 0); + } + + fn lsf_type(&self) -> u16 { + u16::from_be_bytes([self.0[12], self.0[13]]) + } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct StreamFrame { /// Which LICH segment is given in this frame, from 0 to 5 inclusive pub lich_idx: u8, @@ -155,6 +232,33 @@ pub struct StreamFrame { pub stream_data: [u8; 16], } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PacketFrame { + /// Application packet payload (chunk) + pub payload: [u8; 25], + + /// Frame counter, which provides different information depending on whether this is the last frame or not. + pub counter: PacketFrameCounter, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum PacketFrameCounter { + /// Any packet frame that comes after the LSF and is not the final frame. + Frame { + /// Which frame this is in the superframe, from 0 to 31 inclusive. + /// + /// If a 33rd frame exists (index 32), it will be a `FinalFrame` instead. + /// + /// All 25 bytes of of `payload` are filled and valid. + index: usize, + }, + /// The final frame in the packet superframe. + FinalFrame { + /// The number of bytes in `payload` that are filled. + payload_len: usize, + }, +} + pub struct LichCollection([Option<[u8; 5]>; 6]); impl LichCollection {