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