]> code.octet-stream.net Git - m17rt/blob - m17core/src/reflector.rs
Parsing functions for reflector packets
[m17rt] / m17core / src / reflector.rs
1 // Based on https://github.com/n7tae/mrefd/blob/master/Packet-Description.md
2 // and the main M17 specification
3
4 use crate::protocol::LsfFrame;
5
6 macro_rules! define_message {
7 ($t:tt, $sz:tt) => {
8 pub struct $t([u8; $sz]);
9 impl $t {
10 pub fn from_bytes(b: &[u8]) -> Option<Self> {
11 if b.len() != $sz {
12 return None;
13 }
14 let mut s = Self([0; $sz]);
15 s.0[..].copy_from_slice(b);
16 if !s.verify_integrity() {
17 return None;
18 }
19 Some(s)
20 }
21 }
22 };
23 }
24
25 macro_rules! impl_stream_id {
26 ($t:ty, $from:tt) => {
27 impl $t {
28 pub fn stream_id(&self) -> u16 {
29 u16::from_be_bytes([self.0[$from], self.0[$from + 1]])
30 }
31 }
32 };
33 }
34
35 macro_rules! impl_link_setup {
36 ($t:ty, $from:tt) => {
37 impl $t {
38 pub fn link_setup_frame(&self) -> LsfFrame {
39 let mut frame = LsfFrame([0; 30]);
40 frame.0[0..28].copy_from_slice(&self.0[$from..($from + 28)]);
41 frame.recalculate_crc();
42 frame
43 }
44 }
45 };
46 }
47
48 macro_rules! impl_link_setup_frame {
49 ($t:ty, $from:tt) => {
50 impl $t {
51 pub fn link_setup_frame(&self) -> LsfFrame {
52 let mut frame = LsfFrame([0; 30]);
53 frame.0[..].copy_from_slice(&self.0[$from..($from + 30)]);
54 frame
55 }
56 }
57 };
58 }
59
60 macro_rules! impl_frame_number {
61 ($t:ty, $from:tt) => {
62 impl $t {
63 pub fn frame_number(&self) -> u16 {
64 let frame_num = u16::from_be_bytes([self.0[$from], self.0[$from + 1]]);
65 frame_num & 0x7fff
66 }
67
68 pub fn is_end_of_stream(&self) -> bool {
69 let frame_num = u16::from_be_bytes([self.0[$from], self.0[$from + 1]]);
70 (frame_num & 0x8000) > 0
71 }
72 }
73 };
74 }
75
76 macro_rules! impl_payload {
77 ($t:ty, $from:tt, $to:tt) => {
78 impl $t {
79 pub fn payload(&self) -> &[u8] {
80 &self.0[$from..$to]
81 }
82 }
83 };
84 }
85
86 macro_rules! impl_modules {
87 ($t:ty, $from:tt, $to:tt) => {
88 impl $t {
89 pub fn modules(&self) -> ModulesIterator {
90 ModulesIterator::new(&self.0[$from..$to])
91 }
92 }
93 };
94 }
95
96 macro_rules! impl_module {
97 ($t:ty, $at:tt) => {
98 impl $t {
99 pub fn module(&self) -> char {
100 self.0[$at] as char
101 }
102 }
103 };
104 }
105
106 macro_rules! impl_address {
107 ($t:ty, $from:tt) => {
108 impl $t {
109 pub fn address(&self) -> crate::address::Address {
110 crate::address::decode_address(self.0[$from..($from + 6)].try_into().unwrap())
111 }
112 }
113 };
114 }
115
116 macro_rules! impl_trailing_crc_verify {
117 ($t:ty) => {
118 impl $t {
119 pub fn verify_integrity(&self) -> bool {
120 crate::crc::m17_crc(&self.0) == 0
121 }
122 }
123 };
124 }
125
126 macro_rules! impl_internal_crc {
127 ($t:ty, $from:tt, $to:tt) => {
128 impl $t {
129 pub fn verify_integrity(&self) -> bool {
130 crate::crc::m17_crc(&self.0[$from..$to]) == 0
131 }
132 }
133 };
134 }
135
136 macro_rules! no_crc {
137 ($t:ty) => {
138 impl $t {
139 pub fn verify_integrity(&self) -> bool {
140 true
141 }
142 }
143 };
144 }
145
146 macro_rules! impl_is_relayed {
147 ($t:ty) => {
148 impl $t {
149 pub fn is_relayed(&self) -> bool {
150 self.0[self.0.len() - 1] != 0
151 }
152 }
153 };
154 }
155
156 pub struct ModulesIterator<'a> {
157 modules: &'a [u8],
158 idx: usize,
159 }
160
161 impl<'a> ModulesIterator<'a> {
162 fn new(modules: &'a [u8]) -> Self {
163 Self { modules, idx: 0 }
164 }
165 }
166
167 impl Iterator for ModulesIterator<'_> {
168 type Item = char;
169
170 fn next(&mut self) -> Option<Self::Item> {
171 if self.idx < self.modules.len() {
172 if self.modules[self.idx] == 0 {
173 return None;
174 }
175 self.idx += 1;
176 return Some(self.modules[self.idx - 1] as char);
177 }
178 None
179 }
180 }
181
182 pub const MAGIC_VOICE: &[u8] = b"M17 ";
183 pub const MAGIC_VOICE_HEADER: &[u8] = b"M17H";
184 pub const MAGIC_VOICE_DATA: &[u8] = b"M17D";
185 pub const MAGIC_PACKET: &[u8] = b"M17P";
186 pub const MAGIC_ACKNOWLEDGE: &[u8] = b"ACKN";
187 pub const MAGIC_CONNECT: &[u8] = b"CONN";
188 pub const MAGIC_DISCONNECT: &[u8] = b"DISC";
189 pub const MAGIC_LISTEN: &[u8] = b"LSTN";
190 pub const MAGIC_NACK: &[u8] = b"NACK";
191 pub const MAGIC_PING: &[u8] = b"PING";
192 pub const MAGIC_PONG: &[u8] = b"PONG";
193
194 /// Messages sent from a station/client to a reflector
195 #[allow(clippy::large_enum_variant)]
196 pub enum ClientMessage {
197 VoiceFull(VoiceFull),
198 VoiceHeader(VoiceHeader),
199 VoiceData(VoiceData),
200 Packet(Packet),
201 Pong(Pong),
202 Connect(Connect),
203 Listen(Listen),
204 Disconnect(Disconnect),
205 }
206
207 impl ClientMessage {
208 pub fn parse(bytes: &[u8]) -> Option<Self> {
209 if bytes.len() < 4 {
210 return None;
211 }
212 match &bytes[0..4] {
213 MAGIC_VOICE => Some(Self::VoiceFull(VoiceFull::from_bytes(&bytes)?)),
214 MAGIC_VOICE_HEADER => Some(Self::VoiceHeader(VoiceHeader::from_bytes(&bytes)?)),
215 MAGIC_VOICE_DATA => Some(Self::VoiceData(VoiceData::from_bytes(&bytes)?)),
216 MAGIC_PACKET => Some(Self::Packet(Packet::from_bytes(&bytes)?)),
217 MAGIC_PONG => Some(Self::Pong(Pong::from_bytes(&bytes)?)),
218 MAGIC_CONNECT => Some(Self::Connect(Connect::from_bytes(&bytes)?)),
219 MAGIC_LISTEN => Some(Self::Listen(Listen::from_bytes(&bytes)?)),
220 MAGIC_DISCONNECT => Some(Self::Disconnect(Disconnect::from_bytes(&bytes)?)),
221 _ => None,
222 }
223 }
224 }
225
226 /// Messages sent from a reflector to a station/client
227 #[allow(clippy::large_enum_variant)]
228 pub enum ServerMessage {
229 VoiceFull(VoiceFull),
230 VoiceHeader(VoiceHeader),
231 VoiceData(VoiceData),
232 Packet(Packet),
233 Ping(Ping),
234 DisconnectAcknowledge(DisconnectAcknowledge),
235 ForceDisconnect(ForceDisconnect),
236 ConnectAcknowledge(ConnectAcknowledge),
237 ConnectNack(ConnectNack),
238 }
239
240 impl ServerMessage {
241 pub fn parse(bytes: &[u8]) -> Option<Self> {
242 if bytes.len() < 4 {
243 return None;
244 }
245 match &bytes[0..4] {
246 MAGIC_VOICE => Some(Self::VoiceFull(VoiceFull::from_bytes(&bytes)?)),
247 MAGIC_VOICE_HEADER => Some(Self::VoiceHeader(VoiceHeader::from_bytes(&bytes)?)),
248 MAGIC_VOICE_DATA => Some(Self::VoiceData(VoiceData::from_bytes(&bytes)?)),
249 MAGIC_PACKET => Some(Self::Packet(Packet::from_bytes(&bytes)?)),
250 MAGIC_PING => Some(Self::Ping(Ping::from_bytes(&bytes)?)),
251 MAGIC_DISCONNECT if bytes.len() == 4 => Some(Self::DisconnectAcknowledge(
252 DisconnectAcknowledge::from_bytes(&bytes)?,
253 )),
254 MAGIC_DISCONNECT => Some(Self::ForceDisconnect(ForceDisconnect::from_bytes(&bytes)?)),
255 MAGIC_ACKNOWLEDGE => Some(Self::ConnectAcknowledge(ConnectAcknowledge::from_bytes(
256 &bytes,
257 )?)),
258 MAGIC_NACK => Some(Self::ConnectNack(ConnectNack::from_bytes(&bytes)?)),
259 _ => None,
260 }
261 }
262 }
263
264 /// Messages sent and received between reflectors
265 #[allow(clippy::large_enum_variant)]
266 pub enum InterlinkMessage {
267 VoiceInterlink(VoiceInterlink),
268 VoiceHeaderInterlink(VoiceHeaderInterlink),
269 VoiceDataInterlink(VoiceDataInterlink),
270 PacketInterlink(PacketInterlink),
271 Ping(Ping),
272 ConnectInterlink(ConnectInterlink),
273 ConnectInterlinkAcknowledge(ConnectInterlinkAcknowledge),
274 ConnectNack(ConnectNack),
275 DisconnectInterlink(DisconnectInterlink),
276 }
277
278 impl InterlinkMessage {
279 pub fn parse(bytes: &[u8]) -> Option<Self> {
280 if bytes.len() < 4 {
281 return None;
282 }
283 match &bytes[0..4] {
284 MAGIC_VOICE => Some(Self::VoiceInterlink(VoiceInterlink::from_bytes(&bytes)?)),
285 MAGIC_VOICE_HEADER => Some(Self::VoiceHeaderInterlink(
286 VoiceHeaderInterlink::from_bytes(&bytes)?,
287 )),
288 MAGIC_VOICE_DATA => Some(Self::VoiceDataInterlink(VoiceDataInterlink::from_bytes(
289 &bytes,
290 )?)),
291 MAGIC_PACKET => Some(Self::PacketInterlink(PacketInterlink::from_bytes(&bytes)?)),
292 MAGIC_PING => Some(Self::Ping(Ping::from_bytes(&bytes)?)),
293 MAGIC_CONNECT => Some(Self::ConnectInterlink(ConnectInterlink::from_bytes(
294 &bytes,
295 )?)),
296 MAGIC_ACKNOWLEDGE => Some(Self::ConnectInterlinkAcknowledge(
297 ConnectInterlinkAcknowledge::from_bytes(&bytes)?,
298 )),
299 MAGIC_NACK => Some(Self::ConnectNack(ConnectNack::from_bytes(&bytes)?)),
300 MAGIC_DISCONNECT => Some(Self::DisconnectInterlink(DisconnectInterlink::from_bytes(
301 &bytes,
302 )?)),
303 _ => None,
304 }
305 }
306 }
307
308 define_message!(VoiceFull, 54);
309 impl_stream_id!(VoiceFull, 4);
310 impl_link_setup!(VoiceFull, 6);
311 impl_frame_number!(VoiceFull, 34);
312 impl_payload!(VoiceFull, 36, 52);
313 impl_trailing_crc_verify!(VoiceFull);
314
315 define_message!(VoiceHeader, 36);
316 impl_stream_id!(VoiceHeader, 4);
317 impl_link_setup!(VoiceHeader, 6);
318 impl_trailing_crc_verify!(VoiceHeader);
319
320 define_message!(VoiceData, 26);
321 impl_stream_id!(VoiceData, 4);
322 impl_frame_number!(VoiceData, 6);
323 impl_payload!(VoiceData, 8, 24);
324 impl_trailing_crc_verify!(VoiceData);
325
326 define_message!(Packet, 859);
327 impl_link_setup_frame!(Packet, 4);
328
329 impl Packet {
330 pub fn payload(&self) -> &[u8] {
331 &self.0[34..]
332 }
333
334 pub fn verify_integrity(&self) -> bool {
335 self.link_setup_frame().check_crc() == 0
336 && self.payload().len() >= 4
337 && crate::crc::m17_crc(self.payload()) == 0
338 }
339 }
340
341 define_message!(Pong, 10);
342 impl_address!(Pong, 4);
343 no_crc!(Pong);
344
345 define_message!(Connect, 11);
346 impl_address!(Connect, 4);
347 impl_module!(Connect, 10);
348 no_crc!(Connect);
349
350 define_message!(Listen, 11);
351 impl_address!(Listen, 4);
352 impl_module!(Listen, 10);
353 no_crc!(Listen);
354
355 define_message!(Disconnect, 10);
356 impl_address!(Disconnect, 4);
357 no_crc!(Disconnect);
358
359 define_message!(Ping, 10);
360 impl_address!(Ping, 4);
361 no_crc!(Ping);
362
363 define_message!(DisconnectAcknowledge, 4);
364 no_crc!(DisconnectAcknowledge);
365
366 define_message!(ForceDisconnect, 10);
367 impl_address!(ForceDisconnect, 4);
368 no_crc!(ForceDisconnect);
369
370 define_message!(ConnectAcknowledge, 4);
371 no_crc!(ConnectAcknowledge);
372
373 define_message!(ConnectNack, 4);
374 no_crc!(ConnectNack);
375
376 define_message!(VoiceInterlink, 55);
377 impl_stream_id!(VoiceInterlink, 4);
378 impl_link_setup!(VoiceInterlink, 6);
379 impl_frame_number!(VoiceInterlink, 34);
380 impl_payload!(VoiceInterlink, 36, 52);
381 impl_internal_crc!(VoiceInterlink, 0, 54);
382 impl_is_relayed!(VoiceInterlink);
383
384 define_message!(VoiceHeaderInterlink, 37);
385 impl_stream_id!(VoiceHeaderInterlink, 4);
386 impl_link_setup!(VoiceHeaderInterlink, 6);
387 impl_internal_crc!(VoiceHeaderInterlink, 0, 36);
388 impl_is_relayed!(VoiceHeaderInterlink);
389
390 define_message!(VoiceDataInterlink, 27);
391 impl_stream_id!(VoiceDataInterlink, 4);
392 impl_frame_number!(VoiceDataInterlink, 6);
393 impl_payload!(VoiceDataInterlink, 8, 24);
394 impl_internal_crc!(VoiceDataInterlink, 0, 24);
395 impl_is_relayed!(VoiceDataInterlink);
396
397 define_message!(PacketInterlink, 860);
398 impl_link_setup_frame!(PacketInterlink, 4);
399 impl_is_relayed!(PacketInterlink);
400
401 impl PacketInterlink {
402 pub fn payload(&self) -> &[u8] {
403 &self.0[34..(self.0.len() - 1)]
404 }
405
406 pub fn verify_integrity(&self) -> bool {
407 self.link_setup_frame().check_crc() == 0
408 && self.payload().len() >= 4
409 && crate::crc::m17_crc(self.payload()) == 0
410 }
411 }
412
413 define_message!(ConnectInterlink, 37);
414 impl_address!(ConnectInterlink, 4);
415 impl_modules!(ConnectInterlink, 10, 37);
416 no_crc!(ConnectInterlink);
417
418 define_message!(ConnectInterlinkAcknowledge, 37);
419 impl_address!(ConnectInterlinkAcknowledge, 4);
420 impl_modules!(ConnectInterlinkAcknowledge, 10, 37);
421 no_crc!(ConnectInterlinkAcknowledge);
422
423 define_message!(DisconnectInterlink, 10);
424 impl_address!(DisconnectInterlink, 4);
425 no_crc!(DisconnectInterlink);