]> code.octet-stream.net Git - m17rt/blob - m17core/src/reflector/packet.rs
add RfToVoice converter for reflector tx path
[m17rt] / m17core / src / reflector / packet.rs
1 //! UDP datagrams and binary encoding/decoding for client-reflector and reflector-reflector communication.
2
3 use crate::address::Address;
4 use crate::protocol::LsfFrame;
5
6 macro_rules! define_message {
7 ($t:tt, $sz:tt, $min_sz:tt, $magic:tt) => {
8 pub struct $t(pub [u8; $sz], pub usize);
9
10 impl $t {
11 pub fn new() -> Self {
12 let mut bytes = [0u8; $sz];
13 bytes[0..4].copy_from_slice($magic);
14 Self(bytes, $sz)
15 }
16
17 #[allow(clippy::double_comparisons)] // occurs in some macro invocations
18 #[allow(clippy::manual_range_contains)] // way more readable, good grief
19 pub fn from_bytes(b: &[u8]) -> Option<Self> {
20 let len = b.len();
21 if len > $sz || len < $min_sz {
22 return None;
23 }
24 let mut s = Self([0; $sz], len);
25 s.0[0..len].copy_from_slice(b);
26 if !s.verify_integrity() {
27 return None;
28 }
29 Some(s)
30 }
31
32 pub fn as_bytes(&self) -> &[u8] {
33 &self.0[0..self.1]
34 }
35 }
36
37 impl Default for $t {
38 fn default() -> Self {
39 Self::new()
40 }
41 }
42 };
43 }
44
45 macro_rules! impl_stream_id {
46 ($t:ty, $from:tt) => {
47 impl $t {
48 pub fn stream_id(&self) -> u16 {
49 u16::from_be_bytes([self.0[$from], self.0[$from + 1]])
50 }
51
52 pub fn set_stream_id(&mut self, id: u16) {
53 let bytes = id.to_be_bytes();
54 self.0[$from] = bytes[0];
55 self.0[$from + 1] = bytes[1];
56 self.recalculate_crc();
57 }
58 }
59 };
60 }
61
62 macro_rules! impl_link_setup {
63 ($t:ty, $from:tt) => {
64 impl $t {
65 pub fn link_setup_frame(&self) -> LsfFrame {
66 let mut frame = LsfFrame([0; 30]);
67 frame.0[0..28].copy_from_slice(&self.0[$from..($from + 28)]);
68 frame.recalculate_crc();
69 frame
70 }
71
72 pub fn set_link_setup_frame(&mut self, lsf: &LsfFrame) {
73 self.0[$from..($from + 28)].copy_from_slice(&lsf.0[0..28]);
74 self.recalculate_crc();
75 }
76 }
77 };
78 }
79
80 macro_rules! impl_link_setup_frame {
81 ($t:ty, $from:tt) => {
82 impl $t {
83 pub fn link_setup_frame(&self) -> LsfFrame {
84 let mut frame = LsfFrame([0; 30]);
85 frame.0[..].copy_from_slice(&self.0[$from..($from + 30)]);
86 frame
87 }
88
89 pub fn set_link_setup_frame(&mut self, lsf: &LsfFrame) {
90 debug_assert_eq!(lsf.check_crc(), 0);
91 self.0[$from..($from + 30)].copy_from_slice(&lsf.0);
92 self.recalculate_crc();
93 }
94 }
95 };
96 }
97
98 macro_rules! impl_frame_number {
99 ($t:ty, $from:tt) => {
100 impl $t {
101 pub fn frame_number(&self) -> u16 {
102 let frame_num = u16::from_be_bytes([self.0[$from], self.0[$from + 1]]);
103 frame_num & 0x7fff
104 }
105
106 pub fn is_end_of_stream(&self) -> bool {
107 let frame_num = u16::from_be_bytes([self.0[$from], self.0[$from + 1]]);
108 (frame_num & 0x8000) > 0
109 }
110
111 pub fn set_frame_number(&mut self, number: u16) {
112 let existing_eos = u16::from_be_bytes([self.0[$from], self.0[$from + 1]]) & 0x8000;
113 let new = (existing_eos | (number & 0x7fff)).to_be_bytes();
114 self.0[$from] = new[0];
115 self.0[$from + 1] = new[1];
116 self.recalculate_crc();
117 }
118
119 pub fn set_end_of_stream(&mut self, eos: bool) {
120 let existing_fn = u16::from_be_bytes([self.0[$from], self.0[$from + 1]]) & 0x7fff;
121 let new = (existing_fn | (if eos { 0x8000 } else { 0 })).to_be_bytes();
122 self.0[$from] = new[0];
123 self.0[$from + 1] = new[1];
124 self.recalculate_crc();
125 }
126 }
127 };
128 }
129
130 macro_rules! impl_payload {
131 ($t:ty, $from:tt, $to:tt) => {
132 impl $t {
133 pub fn payload(&self) -> &[u8] {
134 &self.0[$from..$to]
135 }
136
137 pub fn set_payload(&mut self, bytes: &[u8]) {
138 self.0[$from..$to].copy_from_slice(bytes);
139 self.recalculate_crc();
140 }
141 }
142 };
143 }
144
145 macro_rules! impl_modules {
146 ($t:ty, $from:tt, $to:tt) => {
147 impl $t {
148 pub fn modules(&self) -> ModulesIterator {
149 ModulesIterator::new(&self.0[$from..$to])
150 }
151
152 pub fn set_modules(&mut self, list: &str) {
153 debug_assert!(list.len() < 27);
154 let mut idx = $from;
155 for m in list.chars() {
156 self.0[idx] = m as u8;
157 idx += 1;
158 }
159 self.0[idx] = 0;
160 self.recalculate_crc();
161 }
162 }
163 };
164 }
165
166 macro_rules! impl_module {
167 ($t:ty, $at:tt) => {
168 impl $t {
169 pub fn module(&self) -> char {
170 self.0[$at] as char
171 }
172
173 pub fn set_module(&mut self, m: char) {
174 self.0[$at] = m as u8;
175 self.recalculate_crc();
176 }
177 }
178 };
179 }
180
181 macro_rules! impl_address {
182 ($t:ty, $from:tt) => {
183 impl $t {
184 pub fn address(&self) -> Address {
185 crate::address::decode_address(self.0[$from..($from + 6)].try_into().unwrap())
186 }
187
188 pub fn set_address(&mut self, address: Address) {
189 let encoded = crate::address::encode_address(&address);
190 self.0[$from..($from + 6)].copy_from_slice(&encoded);
191 self.recalculate_crc();
192 }
193 }
194 };
195 }
196
197 macro_rules! impl_trailing_crc_verify {
198 ($t:ty) => {
199 impl $t {
200 pub fn verify_integrity(&self) -> bool {
201 crate::crc::m17_crc(&self.0) == 0
202 }
203
204 pub fn recalculate_crc(&mut self) {
205 let len = self.0.len();
206 let start_crc = crate::crc::m17_crc(&self.0[0..(len - 2)]).to_be_bytes();
207 self.0[len - 2] = start_crc[0];
208 self.0[len - 1] = start_crc[1];
209 debug_assert!(self.verify_integrity());
210 }
211 }
212 };
213 }
214
215 macro_rules! impl_internal_crc {
216 ($t:ty, $from:tt, $to:tt) => {
217 impl $t {
218 pub fn verify_integrity(&self) -> bool {
219 crate::crc::m17_crc(&self.0[$from..$to]) == 0
220 }
221
222 pub fn recalculate_crc(&mut self) {
223 // assume the last two bytes of the range are the CRC
224 let start_crc = crate::crc::m17_crc(&self.0[$from..($to - 2)]).to_be_bytes();
225 self.0[$to - 2] = start_crc[0];
226 self.0[$to - 1] = start_crc[1];
227 debug_assert!(self.verify_integrity());
228 }
229 }
230 };
231 }
232
233 macro_rules! no_crc {
234 ($t:ty) => {
235 impl $t {
236 pub fn verify_integrity(&self) -> bool {
237 true
238 }
239 pub fn recalculate_crc(&mut self) {}
240 }
241 };
242 }
243
244 macro_rules! impl_is_relayed {
245 ($t:ty) => {
246 impl $t {
247 pub fn is_relayed(&self) -> bool {
248 self.0[self.0.len() - 1] != 0
249 }
250
251 pub fn set_relayed(&mut self, relayed: bool) {
252 self.0[self.0.len() - 1] = if relayed { 1 } else { 0 };
253 self.recalculate_crc();
254 }
255 }
256 };
257 }
258
259 pub struct ModulesIterator<'a> {
260 modules: &'a [u8],
261 idx: usize,
262 }
263
264 impl<'a> ModulesIterator<'a> {
265 fn new(modules: &'a [u8]) -> Self {
266 Self { modules, idx: 0 }
267 }
268 }
269
270 impl Iterator for ModulesIterator<'_> {
271 type Item = char;
272
273 fn next(&mut self) -> Option<Self::Item> {
274 if self.idx < self.modules.len() {
275 if self.modules[self.idx] == 0 {
276 return None;
277 }
278 self.idx += 1;
279 return Some(self.modules[self.idx - 1] as char);
280 }
281 None
282 }
283 }
284
285 pub const MAGIC_VOICE: &[u8] = b"M17 ";
286 pub const MAGIC_VOICE_HEADER: &[u8] = b"M17H";
287 pub const MAGIC_VOICE_DATA: &[u8] = b"M17D";
288 pub const MAGIC_PACKET: &[u8] = b"M17P";
289 pub const MAGIC_ACKNOWLEDGE: &[u8] = b"ACKN";
290 pub const MAGIC_CONNECT: &[u8] = b"CONN";
291 pub const MAGIC_DISCONNECT: &[u8] = b"DISC";
292 pub const MAGIC_LISTEN: &[u8] = b"LSTN";
293 pub const MAGIC_NACK: &[u8] = b"NACK";
294 pub const MAGIC_PING: &[u8] = b"PING";
295 pub const MAGIC_PONG: &[u8] = b"PONG";
296
297 /// Messages sent from a station/client to a reflector
298 #[allow(clippy::large_enum_variant)]
299 pub enum ClientMessage {
300 Voice(Voice),
301 VoiceHeader(VoiceHeader),
302 VoiceData(VoiceData),
303 Packet(Packet),
304 Pong(Pong),
305 Connect(Connect),
306 Listen(Listen),
307 Disconnect(Disconnect),
308 }
309
310 impl ClientMessage {
311 pub fn parse(bytes: &[u8]) -> Option<Self> {
312 if bytes.len() < 4 {
313 return None;
314 }
315 match &bytes[0..4] {
316 MAGIC_VOICE => Some(Self::Voice(Voice::from_bytes(bytes)?)),
317 MAGIC_VOICE_HEADER => Some(Self::VoiceHeader(VoiceHeader::from_bytes(bytes)?)),
318 MAGIC_VOICE_DATA => Some(Self::VoiceData(VoiceData::from_bytes(bytes)?)),
319 MAGIC_PACKET => Some(Self::Packet(Packet::from_bytes(bytes)?)),
320 MAGIC_PONG => Some(Self::Pong(Pong::from_bytes(bytes)?)),
321 MAGIC_CONNECT => Some(Self::Connect(Connect::from_bytes(bytes)?)),
322 MAGIC_LISTEN => Some(Self::Listen(Listen::from_bytes(bytes)?)),
323 MAGIC_DISCONNECT => Some(Self::Disconnect(Disconnect::from_bytes(bytes)?)),
324 _ => None,
325 }
326 }
327 }
328
329 /// Messages sent from a reflector to a station/client
330 #[allow(clippy::large_enum_variant)]
331 pub enum ServerMessage {
332 Voice(Voice),
333 VoiceHeader(VoiceHeader),
334 VoiceData(VoiceData),
335 Packet(Packet),
336 Ping(Ping),
337 DisconnectAcknowledge(DisconnectAcknowledge),
338 ForceDisconnect(ForceDisconnect),
339 ConnectAcknowledge(ConnectAcknowledge),
340 ConnectNack(ConnectNack),
341 }
342
343 impl ServerMessage {
344 pub fn parse(bytes: &[u8]) -> Option<Self> {
345 if bytes.len() < 4 {
346 return None;
347 }
348 match &bytes[0..4] {
349 MAGIC_VOICE => Some(Self::Voice(Voice::from_bytes(bytes)?)),
350 MAGIC_VOICE_HEADER => Some(Self::VoiceHeader(VoiceHeader::from_bytes(bytes)?)),
351 MAGIC_VOICE_DATA => Some(Self::VoiceData(VoiceData::from_bytes(bytes)?)),
352 MAGIC_PACKET => Some(Self::Packet(Packet::from_bytes(bytes)?)),
353 MAGIC_PING => Some(Self::Ping(Ping::from_bytes(bytes)?)),
354 MAGIC_DISCONNECT if bytes.len() == 4 => Some(Self::DisconnectAcknowledge(
355 DisconnectAcknowledge::from_bytes(bytes)?,
356 )),
357 MAGIC_DISCONNECT => Some(Self::ForceDisconnect(ForceDisconnect::from_bytes(bytes)?)),
358 MAGIC_ACKNOWLEDGE => Some(Self::ConnectAcknowledge(ConnectAcknowledge::from_bytes(
359 bytes,
360 )?)),
361 MAGIC_NACK => Some(Self::ConnectNack(ConnectNack::from_bytes(bytes)?)),
362 _ => None,
363 }
364 }
365 }
366
367 /// Messages sent and received between reflectors
368 #[allow(clippy::large_enum_variant)]
369 pub enum InterlinkMessage {
370 VoiceInterlink(VoiceInterlink),
371 VoiceHeaderInterlink(VoiceHeaderInterlink),
372 VoiceDataInterlink(VoiceDataInterlink),
373 PacketInterlink(PacketInterlink),
374 Ping(Ping),
375 ConnectInterlink(ConnectInterlink),
376 ConnectInterlinkAcknowledge(ConnectInterlinkAcknowledge),
377 ConnectNack(ConnectNack),
378 DisconnectInterlink(DisconnectInterlink),
379 }
380
381 impl InterlinkMessage {
382 pub fn parse(bytes: &[u8]) -> Option<Self> {
383 if bytes.len() < 4 {
384 return None;
385 }
386 match &bytes[0..4] {
387 MAGIC_VOICE => Some(Self::VoiceInterlink(VoiceInterlink::from_bytes(bytes)?)),
388 MAGIC_VOICE_HEADER => Some(Self::VoiceHeaderInterlink(
389 VoiceHeaderInterlink::from_bytes(bytes)?,
390 )),
391 MAGIC_VOICE_DATA => Some(Self::VoiceDataInterlink(VoiceDataInterlink::from_bytes(
392 bytes,
393 )?)),
394 MAGIC_PACKET => Some(Self::PacketInterlink(PacketInterlink::from_bytes(bytes)?)),
395 MAGIC_PING => Some(Self::Ping(Ping::from_bytes(bytes)?)),
396 MAGIC_CONNECT => Some(Self::ConnectInterlink(ConnectInterlink::from_bytes(bytes)?)),
397 MAGIC_ACKNOWLEDGE => Some(Self::ConnectInterlinkAcknowledge(
398 ConnectInterlinkAcknowledge::from_bytes(bytes)?,
399 )),
400 MAGIC_NACK => Some(Self::ConnectNack(ConnectNack::from_bytes(bytes)?)),
401 MAGIC_DISCONNECT => Some(Self::DisconnectInterlink(DisconnectInterlink::from_bytes(
402 bytes,
403 )?)),
404 _ => None,
405 }
406 }
407 }
408
409 define_message!(Voice, 54, 54, MAGIC_VOICE);
410 impl_stream_id!(Voice, 4);
411 impl_link_setup!(Voice, 6);
412 impl_frame_number!(Voice, 34);
413 impl_payload!(Voice, 36, 52);
414 impl_trailing_crc_verify!(Voice);
415
416 define_message!(VoiceHeader, 36, 36, MAGIC_VOICE_HEADER);
417 impl_stream_id!(VoiceHeader, 4);
418 impl_link_setup!(VoiceHeader, 6);
419 impl_trailing_crc_verify!(VoiceHeader);
420
421 define_message!(VoiceData, 26, 26, MAGIC_VOICE_DATA);
422 impl_stream_id!(VoiceData, 4);
423 impl_frame_number!(VoiceData, 6);
424 impl_payload!(VoiceData, 8, 24);
425 impl_trailing_crc_verify!(VoiceData);
426
427 define_message!(Packet, 859, 38, MAGIC_PACKET);
428 impl_link_setup_frame!(Packet, 4);
429
430 impl Packet {
431 pub fn payload(&self) -> &[u8] {
432 &self.0[34..self.1]
433 }
434
435 pub fn set_payload(&mut self, bytes: &[u8]) {
436 let end = 34 + bytes.len();
437 self.0[34..end].copy_from_slice(bytes);
438 self.1 = end;
439 }
440
441 pub fn verify_integrity(&self) -> bool {
442 self.link_setup_frame().check_crc() == 0
443 && self.payload().len() >= 4
444 && crate::crc::m17_crc(self.payload()) == 0
445 }
446
447 pub fn recalculate_crc(&mut self) {
448 // LSF and payload should be confirmed valid before construction
449 }
450 }
451
452 define_message!(Pong, 10, 10, MAGIC_PONG);
453 impl_address!(Pong, 4);
454 no_crc!(Pong);
455
456 define_message!(Connect, 11, 11, MAGIC_CONNECT);
457 impl_address!(Connect, 4);
458 impl_module!(Connect, 10);
459 no_crc!(Connect);
460
461 define_message!(Listen, 11, 11, MAGIC_LISTEN);
462 impl_address!(Listen, 4);
463 impl_module!(Listen, 10);
464 no_crc!(Listen);
465
466 define_message!(Disconnect, 10, 10, MAGIC_DISCONNECT);
467 impl_address!(Disconnect, 4);
468 no_crc!(Disconnect);
469
470 define_message!(Ping, 10, 10, MAGIC_PING);
471 impl_address!(Ping, 4);
472 no_crc!(Ping);
473
474 define_message!(DisconnectAcknowledge, 4, 4, MAGIC_DISCONNECT);
475 no_crc!(DisconnectAcknowledge);
476
477 define_message!(ForceDisconnect, 10, 10, MAGIC_DISCONNECT);
478 impl_address!(ForceDisconnect, 4);
479 no_crc!(ForceDisconnect);
480
481 define_message!(ConnectAcknowledge, 4, 4, MAGIC_ACKNOWLEDGE);
482 no_crc!(ConnectAcknowledge);
483
484 define_message!(ConnectNack, 4, 4, MAGIC_NACK);
485 no_crc!(ConnectNack);
486
487 define_message!(VoiceInterlink, 55, 55, MAGIC_VOICE);
488 impl_stream_id!(VoiceInterlink, 4);
489 impl_link_setup!(VoiceInterlink, 6);
490 impl_frame_number!(VoiceInterlink, 34);
491 impl_payload!(VoiceInterlink, 36, 52);
492 impl_internal_crc!(VoiceInterlink, 0, 54);
493 impl_is_relayed!(VoiceInterlink);
494
495 define_message!(VoiceHeaderInterlink, 37, 37, MAGIC_VOICE_HEADER);
496 impl_stream_id!(VoiceHeaderInterlink, 4);
497 impl_link_setup!(VoiceHeaderInterlink, 6);
498 impl_internal_crc!(VoiceHeaderInterlink, 0, 36);
499 impl_is_relayed!(VoiceHeaderInterlink);
500
501 define_message!(VoiceDataInterlink, 27, 27, MAGIC_VOICE_DATA);
502 impl_stream_id!(VoiceDataInterlink, 4);
503 impl_frame_number!(VoiceDataInterlink, 6);
504 impl_payload!(VoiceDataInterlink, 8, 24);
505 impl_internal_crc!(VoiceDataInterlink, 0, 24);
506 impl_is_relayed!(VoiceDataInterlink);
507
508 define_message!(PacketInterlink, 860, 39, MAGIC_PACKET);
509 impl_link_setup_frame!(PacketInterlink, 4);
510 impl_is_relayed!(PacketInterlink);
511
512 impl PacketInterlink {
513 pub fn payload(&self) -> &[u8] {
514 &self.0[34..(self.1 - 1)]
515 }
516
517 pub fn set_payload(&mut self, bytes: &[u8]) {
518 let is_relayed = self.is_relayed();
519 let end = 34 + bytes.len();
520 self.0[34..end].copy_from_slice(bytes);
521 self.1 = end + 1;
522 self.set_relayed(is_relayed);
523 }
524
525 pub fn verify_integrity(&self) -> bool {
526 self.link_setup_frame().check_crc() == 0
527 && self.payload().len() >= 4
528 && crate::crc::m17_crc(self.payload()) == 0
529 }
530
531 pub fn recalculate_crc(&mut self) {
532 // LSF and payload should be confirmed valid before construction
533 }
534 }
535
536 define_message!(ConnectInterlink, 37, 37, MAGIC_CONNECT);
537 impl_address!(ConnectInterlink, 4);
538 impl_modules!(ConnectInterlink, 10, 37);
539 no_crc!(ConnectInterlink);
540
541 define_message!(ConnectInterlinkAcknowledge, 37, 37, MAGIC_ACKNOWLEDGE);
542 impl_address!(ConnectInterlinkAcknowledge, 4);
543 impl_modules!(ConnectInterlinkAcknowledge, 10, 37);
544 no_crc!(ConnectInterlinkAcknowledge);
545
546 define_message!(DisconnectInterlink, 10, 10, MAGIC_DISCONNECT);
547 impl_address!(DisconnectInterlink, 4);
548 no_crc!(DisconnectInterlink);