1use packet_encoding::{Decodable, Encodable, decodable_enum};
6
7mod command_response;
9pub use command_response::CommandResponse;
10mod error;
12pub use error::FrameParseError;
13mod fcs;
15mod field;
17pub mod mux_commands;
19
20use self::fcs::{calculate_fcs, verify_fcs};
21use self::field::*;
22use self::mux_commands::MuxCommand;
23use crate::{DLCI, Role};
24
25decodable_enum! {
26 pub enum FrameTypeMarker<u8, FrameParseError, UnsupportedFrameType> {
30 SetAsynchronousBalancedMode = 0b00101111,
31 UnnumberedAcknowledgement = 0b01100011,
32 DisconnectedMode = 0b00001111,
33 Disconnect = 0b01000011,
34 UnnumberedInfoHeaderCheck = 0b11101111,
35 }
36}
37
38impl FrameTypeMarker {
39 fn is_mux_startup(&self, dlci: &DLCI) -> bool {
44 dlci.is_mux_control()
45 && (*self == FrameTypeMarker::SetAsynchronousBalancedMode
46 || *self == FrameTypeMarker::UnnumberedAcknowledgement
47 || *self == FrameTypeMarker::DisconnectedMode)
48 }
49
50 fn fcs_octets(&self) -> usize {
52 if *self == FrameTypeMarker::UnnumberedInfoHeaderCheck { 2 } else { 3 }
55 }
56
57 fn has_credit_octet(&self, credit_based_flow: bool, poll_final: bool, dlci: DLCI) -> bool {
66 *self == FrameTypeMarker::UnnumberedInfoHeaderCheck
67 && !dlci.is_mux_control()
68 && credit_based_flow
69 && poll_final
70 }
71}
72
73#[derive(Clone, Debug, PartialEq)]
75pub struct UserData {
76 pub information: Vec<u8>,
77}
78
79impl UserData {
80 pub fn is_empty(&self) -> bool {
81 self.information.is_empty()
82 }
83
84 pub fn empty() -> Self {
85 Self { information: vec![] }
86 }
87}
88
89impl Decodable for UserData {
90 type Error = FrameParseError;
91
92 fn decode(buf: &[u8]) -> Result<Self, FrameParseError> {
93 Ok(Self { information: buf.to_vec() })
94 }
95}
96
97impl Encodable for UserData {
98 type Error = FrameParseError;
99
100 fn encoded_len(&self) -> usize {
101 self.information.len()
102 }
103
104 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
105 if buf.len() < self.encoded_len() {
106 return Err(FrameParseError::BufferTooSmall);
107 }
108 buf.copy_from_slice(&self.information);
109 Ok(())
110 }
111}
112
113#[derive(Clone, Debug, PartialEq)]
115pub enum UIHData {
116 User(UserData),
118 Mux(MuxCommand),
120}
121
122impl Encodable for UIHData {
123 type Error = FrameParseError;
124
125 fn encoded_len(&self) -> usize {
126 match self {
127 UIHData::User(data) => data.encoded_len(),
128 UIHData::Mux(command) => command.encoded_len(),
129 }
130 }
131
132 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
133 if buf.len() < self.encoded_len() {
134 return Err(FrameParseError::BufferTooSmall);
135 }
136
137 match self {
138 UIHData::User(data) => data.encode(buf),
139 UIHData::Mux(command) => command.encode(buf),
140 }
141 }
142}
143
144#[derive(Clone, Debug, PartialEq)]
147pub enum FrameData {
148 SetAsynchronousBalancedMode,
149 UnnumberedAcknowledgement,
150 DisconnectedMode,
151 Disconnect,
152 UnnumberedInfoHeaderCheck(UIHData),
153}
154
155impl FrameData {
156 pub fn marker(&self) -> FrameTypeMarker {
157 match self {
158 FrameData::SetAsynchronousBalancedMode => FrameTypeMarker::SetAsynchronousBalancedMode,
159 FrameData::UnnumberedAcknowledgement => FrameTypeMarker::UnnumberedAcknowledgement,
160 FrameData::DisconnectedMode => FrameTypeMarker::DisconnectedMode,
161 FrameData::Disconnect => FrameTypeMarker::Disconnect,
162 FrameData::UnnumberedInfoHeaderCheck(_) => FrameTypeMarker::UnnumberedInfoHeaderCheck,
163 }
164 }
165
166 fn decode(
167 frame_type: &FrameTypeMarker,
168 dlci: &DLCI,
169 buf: &[u8],
170 ) -> Result<Self, FrameParseError> {
171 let data = match frame_type {
172 FrameTypeMarker::SetAsynchronousBalancedMode => FrameData::SetAsynchronousBalancedMode,
173 FrameTypeMarker::UnnumberedAcknowledgement => FrameData::UnnumberedAcknowledgement,
174 FrameTypeMarker::DisconnectedMode => FrameData::DisconnectedMode,
175 FrameTypeMarker::Disconnect => FrameData::Disconnect,
176 FrameTypeMarker::UnnumberedInfoHeaderCheck => {
177 let uih_data = if dlci.is_mux_control() {
178 UIHData::Mux(MuxCommand::decode(buf)?)
179 } else {
180 UIHData::User(UserData::decode(buf)?)
181 };
182 FrameData::UnnumberedInfoHeaderCheck(uih_data)
183 }
184 };
185 Ok(data)
186 }
187}
188
189impl Encodable for FrameData {
190 type Error = FrameParseError;
191
192 fn encoded_len(&self) -> usize {
193 match self {
194 FrameData::SetAsynchronousBalancedMode
195 | FrameData::UnnumberedAcknowledgement
196 | FrameData::DisconnectedMode
197 | FrameData::Disconnect => 0,
198 FrameData::UnnumberedInfoHeaderCheck(data) => data.encoded_len(),
199 }
200 }
201
202 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
203 if buf.len() < self.encoded_len() {
204 return Err(FrameParseError::BufferTooSmall);
205 }
206
207 match self {
208 FrameData::SetAsynchronousBalancedMode
209 | FrameData::UnnumberedAcknowledgement
210 | FrameData::DisconnectedMode
211 | FrameData::Disconnect => Ok(()),
212 FrameData::UnnumberedInfoHeaderCheck(data) => data.encode(buf),
213 }
214 }
215}
216
217const MIN_FRAME_SIZE: usize = 4;
220
221pub const MAX_RFCOMM_HEADER_SIZE: usize = 6;
225
226const MAX_SINGLE_OCTET_LENGTH: usize = 127;
228
229pub const MAX_INFORMATION_LENGTH: usize = 32767;
232
233fn is_two_octet_length(length: usize) -> bool {
235 length > MAX_SINGLE_OCTET_LENGTH
236}
237
238fn cr_bit_for_non_uih_frame(role: Role, command_response: CommandResponse) -> bool {
240 match (role, command_response) {
242 (Role::Initiator, CommandResponse::Command)
243 | (Role::Responder, CommandResponse::Response) => true,
244 _ => false,
245 }
246}
247
248fn cr_bit_for_uih_frame(role: Role) -> bool {
251 match role {
253 Role::Initiator => true,
254 _ => false,
255 }
256}
257
258#[derive(Clone, Debug, PartialEq)]
260pub struct Frame {
261 pub role: Role,
263 pub dlci: DLCI,
265 pub data: FrameData,
267 pub poll_final: bool,
270 pub command_response: CommandResponse,
272 pub credits: Option<u8>,
275}
276
277impl Frame {
278 pub fn parse(role: Role, credit_based_flow: bool, buf: &[u8]) -> Result<Self, FrameParseError> {
284 if buf.len() < MIN_FRAME_SIZE {
285 return Err(FrameParseError::BufferTooSmall);
286 }
287
288 let address_field = AddressField(buf[FRAME_ADDRESS_IDX]);
290 let dlci: DLCI = address_field.dlci()?;
291 let cr_bit: bool = address_field.cr_bit();
292
293 let control_field = ControlField(buf[FRAME_CONTROL_IDX]);
295 let frame_type: FrameTypeMarker = control_field.frame_type()?;
296 let poll_final = control_field.poll_final();
297
298 if !role.is_multiplexer_started() && !frame_type.is_mux_startup(&dlci) {
301 return Err(FrameParseError::InvalidFrame);
302 }
303
304 let command_response = CommandResponse::classify(role, frame_type, cr_bit)?;
307
308 let information_field = InformationField(buf[FRAME_INFORMATION_IDX]);
311 let is_two_octet_length = !information_field.ea_bit();
312 let mut length = information_field.length() as u16;
313 if is_two_octet_length {
314 length |= (buf[FRAME_INFORMATION_IDX + 1] as u16) << INFORMATION_SECOND_OCTET_SHIFT;
315 }
316
317 let mut header_size = 2 + if is_two_octet_length { 2 } else { 1 };
320 let mut credits = None;
321 if frame_type.has_credit_octet(credit_based_flow, poll_final, dlci) {
322 if buf.len() < header_size {
323 return Err(FrameParseError::BufferTooSmall);
324 }
325 credits = Some(buf[header_size]);
326 header_size += 1;
327 }
328
329 let fcs_index = header_size + usize::from(length);
331 if buf.len() <= fcs_index {
332 return Err(FrameParseError::BufferTooSmall);
333 }
334 let fcs = buf[fcs_index];
335 if !verify_fcs(fcs, &buf[..frame_type.fcs_octets()]) {
336 return Err(FrameParseError::FCSCheckFailed);
337 }
338
339 let data = &buf[header_size..fcs_index];
340 let data = FrameData::decode(&frame_type, &dlci, data)?;
341
342 Ok(Self { role, dlci, data, poll_final, command_response, credits })
343 }
344
345 pub fn make_sabm_command(role: Role, dlci: DLCI) -> Self {
346 Self {
347 role,
348 dlci,
349 data: FrameData::SetAsynchronousBalancedMode,
350 poll_final: true, command_response: CommandResponse::Command,
352 credits: None,
353 }
354 }
355
356 pub fn make_dm_response(role: Role, dlci: DLCI) -> Self {
357 Self {
358 role,
359 dlci,
360 data: FrameData::DisconnectedMode,
361 poll_final: true, command_response: CommandResponse::Response,
363 credits: None,
364 }
365 }
366
367 pub fn make_ua_response(role: Role, dlci: DLCI) -> Self {
368 Self {
369 role,
370 dlci,
371 data: FrameData::UnnumberedAcknowledgement,
372 poll_final: true, command_response: CommandResponse::Response,
374 credits: None,
375 }
376 }
377
378 pub fn make_mux_command(role: Role, data: MuxCommand) -> Self {
379 let command_response = data.command_response;
380 Self {
381 role,
382 dlci: DLCI::MUX_CONTROL_DLCI,
383 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::Mux(data)),
384 poll_final: false, command_response,
386 credits: None,
387 }
388 }
389
390 pub fn make_user_data_frame(
391 role: Role,
392 dlci: DLCI,
393 user_data: UserData,
394 credits: Option<u8>,
395 ) -> Self {
396 Self {
400 role,
401 dlci,
402 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(user_data)),
403 poll_final: credits.is_some(),
404 command_response: CommandResponse::Command,
405 credits,
406 }
407 }
408
409 pub fn make_disc_command(role: Role, dlci: DLCI) -> Self {
410 Self {
411 role,
412 dlci,
413 data: FrameData::Disconnect,
414 poll_final: true, command_response: CommandResponse::Command,
416 credits: None,
417 }
418 }
419}
420
421impl Encodable for Frame {
422 type Error = FrameParseError;
423
424 fn encoded_len(&self) -> usize {
425 3 + self.credits.map_or(0, |_| 1)
427 + if is_two_octet_length(self.data.encoded_len()) { 2 } else { 1 }
428 + self.data.encoded_len()
429 }
430
431 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
432 if buf.len() != self.encoded_len() {
433 return Err(FrameParseError::BufferTooSmall);
434 }
435
436 let assumed_role = if !self.role.is_multiplexer_started() {
437 if !self.data.marker().is_mux_startup(&self.dlci) {
438 return Err(FrameParseError::InvalidFrame);
439 }
440 if self.data.marker() == FrameTypeMarker::SetAsynchronousBalancedMode {
443 Role::Initiator
444 } else {
445 Role::Responder
446 }
447 } else {
448 self.role
449 };
450 let cr_bit = if self.data.marker() == FrameTypeMarker::UnnumberedInfoHeaderCheck {
454 cr_bit_for_uih_frame(assumed_role)
455 } else {
456 cr_bit_for_non_uih_frame(assumed_role, self.command_response)
457 };
458
459 let mut address_field = AddressField(0);
461 address_field.set_ea_bit(true);
462 address_field.set_cr_bit(cr_bit);
463 address_field.set_dlci(u8::from(self.dlci));
464 buf[FRAME_ADDRESS_IDX] = address_field.0;
465
466 let mut control_field = ControlField(0);
468 control_field.set_frame_type(u8::from(&self.data.marker()));
469 control_field.set_poll_final(self.poll_final);
470 buf[FRAME_CONTROL_IDX] = control_field.0;
471
472 let data_length = self.data.encoded_len();
474 if data_length > MAX_INFORMATION_LENGTH {
475 return Err(FrameParseError::FrameTooLarge(data_length));
476 }
477 let is_two_octet_length = is_two_octet_length(data_length);
478 let mut first_octet_length = InformationField(0);
479 first_octet_length.set_length(data_length as u8);
480 first_octet_length.set_ea_bit(!is_two_octet_length);
481 buf[FRAME_INFORMATION_IDX] = first_octet_length.0;
482 if is_two_octet_length {
484 let second_octet_length = (data_length >> INFORMATION_SECOND_OCTET_SHIFT) as u8;
485 buf[FRAME_INFORMATION_IDX + 1] = second_octet_length;
486 }
487
488 let mut header_size = 2 + if is_two_octet_length { 2 } else { 1 };
490
491 let credit_based_flow = self.credits.is_some();
493 if self.data.marker().has_credit_octet(credit_based_flow, self.poll_final, self.dlci) {
494 buf[header_size] = self.credits.unwrap();
495 header_size += 1;
496 }
497
498 let fcs_idx = header_size + data_length as usize;
499
500 self.data.encode(&mut buf[header_size..fcs_idx])?;
502
503 buf[fcs_idx] = calculate_fcs(&buf[..self.data.marker().fcs_octets()]);
505
506 Ok(())
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use crate::frame::mux_commands::ModemStatusParams;
513
514 use super::*;
515
516 use assert_matches::assert_matches;
517 use mux_commands::{MuxCommandParams, RemotePortNegotiationParams};
518
519 #[test]
520 fn test_is_mux_startup_frame() {
521 let control_dlci = DLCI::try_from(0).unwrap();
522 let user_dlci = DLCI::try_from(5).unwrap();
523
524 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
525 assert!(frame_type.is_mux_startup(&control_dlci));
526 assert!(!frame_type.is_mux_startup(&user_dlci));
527
528 let frame_type = FrameTypeMarker::UnnumberedAcknowledgement;
529 assert!(frame_type.is_mux_startup(&control_dlci));
530 assert!(!frame_type.is_mux_startup(&user_dlci));
531
532 let frame_type = FrameTypeMarker::DisconnectedMode;
533 assert!(frame_type.is_mux_startup(&control_dlci));
534 assert!(!frame_type.is_mux_startup(&user_dlci));
535
536 let frame_type = FrameTypeMarker::Disconnect;
537 assert!(!frame_type.is_mux_startup(&control_dlci));
538 assert!(!frame_type.is_mux_startup(&user_dlci));
539 }
540
541 #[test]
542 fn test_has_credit_octet() {
543 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
544 let pf = true;
545 let credit_based_flow = true;
546 let dlci = DLCI::try_from(3).unwrap();
547 assert!(frame_type.has_credit_octet(credit_based_flow, pf, dlci));
548
549 let pf = false;
550 let credit_based_flow = true;
551 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
552
553 let pf = true;
554 let credit_based_flow = false;
555 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
556
557 let pf = true;
558 let credit_based_flow = true;
559 let dlci = DLCI::try_from(0).unwrap(); assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
561
562 let pf = false;
563 let credit_based_flow = false;
564 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
565
566 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
567 let pf = true;
568 let credit_based_flow = true;
569 let dlci = DLCI::try_from(5).unwrap();
570 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
571 }
572
573 #[test]
574 fn test_parse_too_small_frame() {
575 let role = Role::Unassigned;
576 let buf: &[u8] = &[0x00];
577 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::BufferTooSmall));
578 }
579
580 #[test]
581 fn test_parse_invalid_dlci() {
582 let role = Role::Unassigned;
583 let buf: &[u8] = &[
584 0b00000101, 0b00101111, 0b00000001, 0x00, ];
589 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::InvalidDLCI(1)));
590 }
591
592 #[test]
595 fn test_parse_invalid_frame_type() {
596 let role = Role::Unassigned;
597 let buf: &[u8] = &[
598 0b00000001, 0b10101010, 0b00000001, 0x00, ];
603 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::UnsupportedFrameType));
604 }
605
606 #[test]
609 fn test_parse_invalid_frame_type_sent_before_mux_startup() {
610 let role = Role::Unassigned;
611 let buf: &[u8] = &[
612 0b00000001, 0b11101111, 0b00000001, 0x00, ];
617 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::InvalidFrame));
618 }
619
620 #[test]
621 fn test_parse_invalid_frame_missing_fcs() {
622 let role = Role::Unassigned;
623 let buf: &[u8] = &[
624 0b00000011, 0b00101111, 0b00000000, 0b00000001, ];
630 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::BufferTooSmall));
631 }
632
633 #[test]
634 fn test_parse_valid_frame_over_mux_dlci() {
635 let role = Role::Unassigned;
636 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
637 let mut buf = vec![
638 0b00000011, 0b00101111, 0b00000001, ];
642 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
644 buf.push(fcs);
645
646 let res = Frame::parse(role, false, &buf[..]).unwrap();
647 let expected_frame = Frame {
648 role,
649 dlci: DLCI::try_from(0).unwrap(),
650 data: FrameData::SetAsynchronousBalancedMode,
651 poll_final: false,
652 command_response: CommandResponse::Command,
653 credits: None,
654 };
655 assert_eq!(res, expected_frame);
656 }
657
658 #[test]
659 fn test_parse_valid_frame_over_user_dlci() {
660 let role = Role::Responder;
661 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
662 let mut buf = vec![
663 0b00001111, 0b00101111, 0b00000001, ];
667 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
669 buf.push(fcs);
670
671 let res = Frame::parse(role, false, &buf[..]).unwrap();
672 let expected_frame = Frame {
673 role,
674 dlci: DLCI::try_from(3).unwrap(),
675 data: FrameData::SetAsynchronousBalancedMode,
676 poll_final: false,
677 command_response: CommandResponse::Response,
678 credits: None,
679 };
680 assert_eq!(res, expected_frame);
681 }
682
683 #[test]
684 fn test_parse_frame_with_information_length_invalid_buf_size() {
685 let role = Role::Responder;
686 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
687 let mut buf = vec![
688 0b00001111, 0b11101111, 0b00000111, 0b00000000, ];
693 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
695 buf.push(fcs);
696
697 assert_matches!(Frame::parse(role, false, &buf[..]), Err(FrameParseError::BufferTooSmall));
698 }
699
700 #[test]
701 fn test_parse_valid_frame_with_information_length() {
702 let role = Role::Responder;
703 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
704 let mut buf = vec![
705 0b00001101, 0b11101111, 0b00000101, 0b00000000, 0b00000000, ];
711 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
713 buf.push(fcs);
714
715 let res = Frame::parse(role, false, &buf[..]).unwrap();
716 let expected_frame = Frame {
717 role,
718 dlci: DLCI::try_from(3).unwrap(),
719 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
720 information: vec![
721 0b00000000, 0b00000000, ],
724 })),
725 poll_final: false,
726 command_response: CommandResponse::Response,
727 credits: None,
728 };
729 assert_eq!(res, expected_frame);
730 }
731
732 #[test]
733 fn test_parse_valid_frame_with_two_octet_information_length() {
734 let role = Role::Responder;
735 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
736 let length = 129;
737 let length_data = vec![0; length];
738
739 let buf = vec![
741 0b00001101, 0b11101111, 0b00000010, 0b00000001, ];
746 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
748 let buf = [buf, length_data.clone(), vec![fcs]].concat();
749
750 let res = Frame::parse(role, false, &buf[..]).unwrap();
751 let expected_frame = Frame {
752 role,
753 dlci: DLCI::try_from(3).unwrap(),
754 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
755 information: length_data,
756 })),
757 poll_final: false,
758 command_response: CommandResponse::Response,
759 credits: None,
760 };
761 assert_eq!(res, expected_frame);
762 }
763
764 #[test]
765 fn test_parse_uih_frame_with_mux_command() {
766 let role = Role::Responder;
767 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
768 let mut buf = vec![
769 0b00000001, 0b11111111, 0b00000111, 0b10010001, 0b00000011, 0b00011111, ];
776 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
778 buf.push(fcs);
779
780 let res = Frame::parse(role, false, &buf[..]).unwrap();
781 let expected_mux_command = MuxCommand {
782 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
783 dlci: DLCI::try_from(7).unwrap(),
784 port_values: None,
785 }),
786 command_response: CommandResponse::Response,
787 };
788 let expected_frame = Frame {
789 role,
790 dlci: DLCI::try_from(0).unwrap(),
791 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::Mux(expected_mux_command)),
792 poll_final: true,
793 command_response: CommandResponse::Response,
794 credits: None,
795 };
796 assert_eq!(res, expected_frame);
797 }
798
799 #[test]
800 fn test_parse_uih_frame_with_credits() {
801 let role = Role::Initiator;
802 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
803 let credit_based_flow = true;
804 let mut buf = vec![
805 0b00011111, 0b11111111, 0b00000111, 0b00000101, 0b00000000, 0b00000001, 0b00000010, ];
813 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
815 buf.push(fcs);
816
817 let res = Frame::parse(role, credit_based_flow, &buf[..]).unwrap();
818 let expected_user_data = UserData { information: vec![0x00, 0x01, 0x02] };
819 let expected_frame = Frame {
820 role,
821 dlci: DLCI::try_from(7).unwrap(),
822 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(expected_user_data)),
823 poll_final: true,
824 command_response: CommandResponse::Command,
825 credits: Some(5),
826 };
827 assert_eq!(res, expected_frame);
828 }
829
830 #[test]
831 fn test_encode_frame_invalid_buf() {
832 let frame = Frame {
833 role: Role::Unassigned,
834 dlci: DLCI::try_from(0).unwrap(),
835 data: FrameData::SetAsynchronousBalancedMode,
836 poll_final: false,
837 command_response: CommandResponse::Command,
838 credits: None,
839 };
840 let mut buf = [];
841 assert_matches!(frame.encode(&mut buf[..]), Err(FrameParseError::BufferTooSmall));
842 }
843
844 #[test]
846 fn test_encode_mux_startup_frame_over_user_dlci_fails() {
847 let frame = Frame {
848 role: Role::Unassigned,
849 dlci: DLCI::try_from(3).unwrap(),
850 data: FrameData::SetAsynchronousBalancedMode,
851 poll_final: false,
852 command_response: CommandResponse::Command,
853 credits: None,
854 };
855 let mut buf = vec![0; frame.encoded_len()];
856 assert_matches!(frame.encode(&mut buf[..]), Err(FrameParseError::InvalidFrame));
857 }
858
859 #[test]
860 fn encode_mux_startup_command_succeeds() {
861 let frame = Frame {
862 role: Role::Unassigned,
863 dlci: DLCI::try_from(0).unwrap(),
864 data: FrameData::SetAsynchronousBalancedMode,
865 poll_final: true,
866 command_response: CommandResponse::Command,
867 credits: None,
868 };
869 let mut buf = vec![0; frame.encoded_len()];
870 assert!(frame.encode(&mut buf[..]).is_ok());
871 let expected = vec![
872 0b00000011, 0b00111111, 0b00000001, 0b00011100, ];
877 assert_eq!(buf, expected);
878 }
879
880 #[test]
881 fn encode_mux_startup_response_succeeds() {
882 let frame = Frame::make_ua_response(Role::Unassigned, DLCI::try_from(0).unwrap());
883 let mut buf = vec![0; frame.encoded_len()];
884 assert!(frame.encode(&mut buf[..]).is_ok());
885 let expected = vec![
886 0b00000011, 0b01110011, 0b00000001, 0b11010111, ];
891 assert_eq!(buf, expected);
892 }
893
894 #[test]
895 fn encode_user_data_as_initiator_succeeds() {
896 let frame = Frame::make_user_data_frame(
897 Role::Initiator,
898 DLCI::try_from(3).unwrap(),
899 UserData {
900 information: vec![
901 0b00000001, 0b00000010, ],
904 },
905 Some(8),
906 );
907 let mut buf = vec![0; frame.encoded_len()];
908 assert!(frame.encode(&mut buf[..]).is_ok());
909 let expected = vec![
910 0b00001111, 0b11111111, 0b00000101, 0b00001000, 0b00000001, 0b00000010, 0b11110011, ];
918 assert_eq!(buf, expected);
919 }
920
921 #[test]
922 fn test_encode_user_data_as_responder_succeeds() {
923 let frame = Frame::make_user_data_frame(
924 Role::Responder,
925 DLCI::try_from(9).unwrap(),
926 UserData {
927 information: vec![
928 0b00000001, ],
930 },
931 Some(10),
932 );
933 let mut buf = vec![0; frame.encoded_len()];
934 assert!(frame.encode(&mut buf[..]).is_ok());
935 let expected = vec![
936 0b00100101, 0b11111111, 0b00000011, 0b00001010, 0b00000001, 0b11101001, ];
943 assert_eq!(buf, expected);
944 }
945
946 #[test]
947 fn encode_mux_command_as_initiator() {
948 let mux_command = MuxCommand {
949 params: MuxCommandParams::ModemStatus(ModemStatusParams::default(
950 DLCI::try_from(5).unwrap(),
951 )),
952 command_response: CommandResponse::Command,
953 };
954 let frame = Frame::make_mux_command(Role::Initiator, mux_command);
955
956 let mut buf = vec![0; frame.encoded_len()];
957 assert!(frame.encode(&mut buf[..]).is_ok());
958 let expected = vec![
959 0b00000011, 0b11101111, 0b00001001, 0b11100011, 0b00000101, 0b00010111, 0b10001101, 0b01110000, ];
968 assert_eq!(buf, expected);
969 }
970
971 #[test]
972 fn encode_mux_command_as_responder() {
973 let mux_command = MuxCommand {
974 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
975 dlci: DLCI::try_from(7).unwrap(),
976 port_values: None,
977 }),
978 command_response: CommandResponse::Command,
979 };
980 let frame = Frame::make_mux_command(Role::Responder, mux_command);
981
982 let mut buf = vec![0; frame.encoded_len()];
983 assert!(frame.encode(&mut buf[..]).is_ok());
984 let expected = vec![
985 0b00000001, 0b11101111, 0b00000111, 0b10010011, 0b00000011, 0b00011111, 0b10101010, ];
993 assert_eq!(buf, expected);
994 }
995
996 #[test]
997 fn encode_mux_response_as_initiator() {
998 let mux_command = MuxCommand {
999 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
1000 dlci: DLCI::try_from(13).unwrap(),
1001 port_values: None,
1002 }),
1003 command_response: CommandResponse::Response,
1004 };
1005 let frame = Frame::make_mux_command(Role::Initiator, mux_command);
1006
1007 let mut buf = vec![0; frame.encoded_len()];
1008 assert!(frame.encode(&mut buf[..]).is_ok());
1009 let expected = vec![
1010 0b00000011, 0b11101111, 0b00000111, 0b10010001, 0b00000011, 0b00110111, 0b01110000, ];
1018 assert_eq!(buf, expected);
1019 }
1020
1021 #[test]
1022 fn encode_mux_response_as_responder() {
1023 let mux_command = MuxCommand {
1024 params: MuxCommandParams::ModemStatus(ModemStatusParams::default(
1025 DLCI::try_from(11).unwrap(),
1026 )),
1027 command_response: CommandResponse::Response,
1028 };
1029 let frame = Frame::make_mux_command(Role::Responder, mux_command);
1030
1031 let mut buf = vec![0; frame.encoded_len()];
1032 assert!(frame.encode(&mut buf[..]).is_ok());
1033 let expected = vec![
1034 0b00000001, 0b11101111, 0b00001001, 0b11100001, 0b00000101, 0b00101111, 0b10001101, 0b10101010, ];
1043 assert_eq!(buf, expected);
1044 }
1045
1046 #[test]
1047 fn test_encode_user_data_with_two_octet_length_succeeds() {
1048 let length = 130;
1049 let mut information = vec![0; length];
1050 let frame = Frame {
1051 role: Role::Initiator,
1052 dlci: DLCI::try_from(5).unwrap(),
1053 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
1054 information: information.clone(),
1055 })),
1056 poll_final: true,
1057 command_response: CommandResponse::Command,
1058 credits: Some(8),
1059 };
1060 let mut buf = vec![0; frame.encoded_len()];
1061 assert!(frame.encode(&mut buf[..]).is_ok());
1062 let mut expected = vec![
1063 0b00010111, 0b11111111, 0b00000100, 0b00000001, 0b00001000, ];
1069 expected.append(&mut information);
1071 expected.push(0b0000_1100);
1073 assert_eq!(buf, expected);
1074 }
1075
1076 #[test]
1077 fn test_parse_frame_with_invalid_fcs() {
1078 let role = Role::Responder;
1079 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
1080 let mut buf = vec![
1081 0b00001111, 0b00101111, 0b00000001, ];
1085 let correct_fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
1087 let invalid_fcs = correct_fcs ^ 0xFF;
1089 buf.push(invalid_fcs);
1090
1091 assert_matches!(Frame::parse(role, false, &buf[..]), Err(FrameParseError::FCSCheckFailed));
1092 }
1093
1094 #[test]
1095 fn encode_oversized_user_data_fails() {
1096 let length = 32_768;
1097 let information = vec![0; length];
1098 let frame = Frame {
1099 role: Role::Initiator,
1100 dlci: DLCI::try_from(5).unwrap(),
1101 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData { information })),
1102 poll_final: true,
1103 command_response: CommandResponse::Command,
1104 credits: None,
1105 };
1106 let mut buf = vec![0; frame.encoded_len()];
1107 assert_matches!(frame.encode(&mut buf[..]), Err(FrameParseError::FrameTooLarge(32768)));
1108 }
1109}