1use packet_encoding::{decodable_enum, Decodable, Encodable};
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::{Role, DLCI};
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 {
55 2
56 } else {
57 3
58 }
59 }
60
61 fn has_credit_octet(&self, credit_based_flow: bool, poll_final: bool, dlci: DLCI) -> bool {
70 *self == FrameTypeMarker::UnnumberedInfoHeaderCheck
71 && !dlci.is_mux_control()
72 && credit_based_flow
73 && poll_final
74 }
75}
76
77#[derive(Clone, Debug, PartialEq)]
79pub struct UserData {
80 pub information: Vec<u8>,
81}
82
83impl UserData {
84 pub fn is_empty(&self) -> bool {
85 self.information.is_empty()
86 }
87
88 pub fn empty() -> Self {
89 Self { information: vec![] }
90 }
91}
92
93impl Decodable for UserData {
94 type Error = FrameParseError;
95
96 fn decode(buf: &[u8]) -> Result<Self, FrameParseError> {
97 Ok(Self { information: buf.to_vec() })
98 }
99}
100
101impl Encodable for UserData {
102 type Error = FrameParseError;
103
104 fn encoded_len(&self) -> usize {
105 self.information.len()
106 }
107
108 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
109 if buf.len() < self.encoded_len() {
110 return Err(FrameParseError::BufferTooSmall);
111 }
112 buf.copy_from_slice(&self.information);
113 Ok(())
114 }
115}
116
117#[derive(Clone, Debug, PartialEq)]
119pub enum UIHData {
120 User(UserData),
122 Mux(MuxCommand),
124}
125
126impl Encodable for UIHData {
127 type Error = FrameParseError;
128
129 fn encoded_len(&self) -> usize {
130 match self {
131 UIHData::User(data) => data.encoded_len(),
132 UIHData::Mux(command) => command.encoded_len(),
133 }
134 }
135
136 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
137 if buf.len() < self.encoded_len() {
138 return Err(FrameParseError::BufferTooSmall);
139 }
140
141 match self {
142 UIHData::User(data) => data.encode(buf),
143 UIHData::Mux(command) => command.encode(buf),
144 }
145 }
146}
147
148#[derive(Clone, Debug, PartialEq)]
151pub enum FrameData {
152 SetAsynchronousBalancedMode,
153 UnnumberedAcknowledgement,
154 DisconnectedMode,
155 Disconnect,
156 UnnumberedInfoHeaderCheck(UIHData),
157}
158
159impl FrameData {
160 pub fn marker(&self) -> FrameTypeMarker {
161 match self {
162 FrameData::SetAsynchronousBalancedMode => FrameTypeMarker::SetAsynchronousBalancedMode,
163 FrameData::UnnumberedAcknowledgement => FrameTypeMarker::UnnumberedAcknowledgement,
164 FrameData::DisconnectedMode => FrameTypeMarker::DisconnectedMode,
165 FrameData::Disconnect => FrameTypeMarker::Disconnect,
166 FrameData::UnnumberedInfoHeaderCheck(_) => FrameTypeMarker::UnnumberedInfoHeaderCheck,
167 }
168 }
169
170 fn decode(
171 frame_type: &FrameTypeMarker,
172 dlci: &DLCI,
173 buf: &[u8],
174 ) -> Result<Self, FrameParseError> {
175 let data = match frame_type {
176 FrameTypeMarker::SetAsynchronousBalancedMode => FrameData::SetAsynchronousBalancedMode,
177 FrameTypeMarker::UnnumberedAcknowledgement => FrameData::UnnumberedAcknowledgement,
178 FrameTypeMarker::DisconnectedMode => FrameData::DisconnectedMode,
179 FrameTypeMarker::Disconnect => FrameData::Disconnect,
180 FrameTypeMarker::UnnumberedInfoHeaderCheck => {
181 let uih_data = if dlci.is_mux_control() {
182 UIHData::Mux(MuxCommand::decode(buf)?)
183 } else {
184 UIHData::User(UserData::decode(buf)?)
185 };
186 FrameData::UnnumberedInfoHeaderCheck(uih_data)
187 }
188 };
189 Ok(data)
190 }
191}
192
193impl Encodable for FrameData {
194 type Error = FrameParseError;
195
196 fn encoded_len(&self) -> usize {
197 match self {
198 FrameData::SetAsynchronousBalancedMode
199 | FrameData::UnnumberedAcknowledgement
200 | FrameData::DisconnectedMode
201 | FrameData::Disconnect => 0,
202 FrameData::UnnumberedInfoHeaderCheck(data) => data.encoded_len(),
203 }
204 }
205
206 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
207 if buf.len() < self.encoded_len() {
208 return Err(FrameParseError::BufferTooSmall);
209 }
210
211 match self {
212 FrameData::SetAsynchronousBalancedMode
213 | FrameData::UnnumberedAcknowledgement
214 | FrameData::DisconnectedMode
215 | FrameData::Disconnect => Ok(()),
216 FrameData::UnnumberedInfoHeaderCheck(data) => data.encode(buf),
217 }
218 }
219}
220
221const MIN_FRAME_SIZE: usize = 4;
224
225pub const MAX_RFCOMM_HEADER_SIZE: usize = 6;
229
230const MAX_SINGLE_OCTET_LENGTH: usize = 127;
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 let is_two_octet_length = is_two_octet_length(data_length);
475 let mut first_octet_length = InformationField(0);
476 first_octet_length.set_length(data_length as u8);
477 first_octet_length.set_ea_bit(!is_two_octet_length);
478 buf[FRAME_INFORMATION_IDX] = first_octet_length.0;
479 if is_two_octet_length {
481 let second_octet_length = (data_length >> INFORMATION_SECOND_OCTET_SHIFT) as u8;
482 buf[FRAME_INFORMATION_IDX + 1] = second_octet_length;
483 }
484
485 let mut header_size = 2 + if is_two_octet_length { 2 } else { 1 };
487
488 let credit_based_flow = self.credits.is_some();
490 if self.data.marker().has_credit_octet(credit_based_flow, self.poll_final, self.dlci) {
491 buf[header_size] = self.credits.unwrap();
492 header_size += 1;
493 }
494
495 let fcs_idx = header_size + data_length as usize;
496
497 self.data.encode(&mut buf[header_size..fcs_idx])?;
499
500 buf[fcs_idx] = calculate_fcs(&buf[..self.data.marker().fcs_octets()]);
502
503 Ok(())
504 }
505}
506
507#[cfg(test)]
508mod tests {
509 use crate::frame::mux_commands::ModemStatusParams;
510
511 use super::*;
512
513 use assert_matches::assert_matches;
514 use mux_commands::{MuxCommandParams, RemotePortNegotiationParams};
515
516 #[test]
517 fn test_is_mux_startup_frame() {
518 let control_dlci = DLCI::try_from(0).unwrap();
519 let user_dlci = DLCI::try_from(5).unwrap();
520
521 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
522 assert!(frame_type.is_mux_startup(&control_dlci));
523 assert!(!frame_type.is_mux_startup(&user_dlci));
524
525 let frame_type = FrameTypeMarker::UnnumberedAcknowledgement;
526 assert!(frame_type.is_mux_startup(&control_dlci));
527 assert!(!frame_type.is_mux_startup(&user_dlci));
528
529 let frame_type = FrameTypeMarker::DisconnectedMode;
530 assert!(frame_type.is_mux_startup(&control_dlci));
531 assert!(!frame_type.is_mux_startup(&user_dlci));
532
533 let frame_type = FrameTypeMarker::Disconnect;
534 assert!(!frame_type.is_mux_startup(&control_dlci));
535 assert!(!frame_type.is_mux_startup(&user_dlci));
536 }
537
538 #[test]
539 fn test_has_credit_octet() {
540 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
541 let pf = true;
542 let credit_based_flow = true;
543 let dlci = DLCI::try_from(3).unwrap();
544 assert!(frame_type.has_credit_octet(credit_based_flow, pf, dlci));
545
546 let pf = false;
547 let credit_based_flow = true;
548 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
549
550 let pf = true;
551 let credit_based_flow = false;
552 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
553
554 let pf = true;
555 let credit_based_flow = true;
556 let dlci = DLCI::try_from(0).unwrap(); assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
558
559 let pf = false;
560 let credit_based_flow = false;
561 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
562
563 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
564 let pf = true;
565 let credit_based_flow = true;
566 let dlci = DLCI::try_from(5).unwrap();
567 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
568 }
569
570 #[test]
571 fn test_parse_too_small_frame() {
572 let role = Role::Unassigned;
573 let buf: &[u8] = &[0x00];
574 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::BufferTooSmall));
575 }
576
577 #[test]
578 fn test_parse_invalid_dlci() {
579 let role = Role::Unassigned;
580 let buf: &[u8] = &[
581 0b00000101, 0b00101111, 0b00000001, 0x00, ];
586 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::InvalidDLCI(1)));
587 }
588
589 #[test]
592 fn test_parse_invalid_frame_type() {
593 let role = Role::Unassigned;
594 let buf: &[u8] = &[
595 0b00000001, 0b10101010, 0b00000001, 0x00, ];
600 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::UnsupportedFrameType));
601 }
602
603 #[test]
606 fn test_parse_invalid_frame_type_sent_before_mux_startup() {
607 let role = Role::Unassigned;
608 let buf: &[u8] = &[
609 0b00000001, 0b11101111, 0b00000001, 0x00, ];
614 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::InvalidFrame));
615 }
616
617 #[test]
618 fn test_parse_invalid_frame_missing_fcs() {
619 let role = Role::Unassigned;
620 let buf: &[u8] = &[
621 0b00000011, 0b00101111, 0b00000000, 0b00000001, ];
627 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::BufferTooSmall));
628 }
629
630 #[test]
631 fn test_parse_valid_frame_over_mux_dlci() {
632 let role = Role::Unassigned;
633 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
634 let mut buf = vec![
635 0b00000011, 0b00101111, 0b00000001, ];
639 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
641 buf.push(fcs);
642
643 let res = Frame::parse(role, false, &buf[..]).unwrap();
644 let expected_frame = Frame {
645 role,
646 dlci: DLCI::try_from(0).unwrap(),
647 data: FrameData::SetAsynchronousBalancedMode,
648 poll_final: false,
649 command_response: CommandResponse::Command,
650 credits: None,
651 };
652 assert_eq!(res, expected_frame);
653 }
654
655 #[test]
656 fn test_parse_valid_frame_over_user_dlci() {
657 let role = Role::Responder;
658 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
659 let mut buf = vec![
660 0b00001111, 0b00101111, 0b00000001, ];
664 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
666 buf.push(fcs);
667
668 let res = Frame::parse(role, false, &buf[..]).unwrap();
669 let expected_frame = Frame {
670 role,
671 dlci: DLCI::try_from(3).unwrap(),
672 data: FrameData::SetAsynchronousBalancedMode,
673 poll_final: false,
674 command_response: CommandResponse::Response,
675 credits: None,
676 };
677 assert_eq!(res, expected_frame);
678 }
679
680 #[test]
681 fn test_parse_frame_with_information_length_invalid_buf_size() {
682 let role = Role::Responder;
683 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
684 let mut buf = vec![
685 0b00001111, 0b11101111, 0b00000111, 0b00000000, ];
690 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
692 buf.push(fcs);
693
694 assert_matches!(Frame::parse(role, false, &buf[..]), Err(FrameParseError::BufferTooSmall));
695 }
696
697 #[test]
698 fn test_parse_valid_frame_with_information_length() {
699 let role = Role::Responder;
700 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
701 let mut buf = vec![
702 0b00001101, 0b11101111, 0b00000101, 0b00000000, 0b00000000, ];
708 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
710 buf.push(fcs);
711
712 let res = Frame::parse(role, false, &buf[..]).unwrap();
713 let expected_frame = Frame {
714 role,
715 dlci: DLCI::try_from(3).unwrap(),
716 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
717 information: vec![
718 0b00000000, 0b00000000, ],
721 })),
722 poll_final: false,
723 command_response: CommandResponse::Response,
724 credits: None,
725 };
726 assert_eq!(res, expected_frame);
727 }
728
729 #[test]
730 fn test_parse_valid_frame_with_two_octet_information_length() {
731 let role = Role::Responder;
732 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
733 let length = 129;
734 let length_data = vec![0; length];
735
736 let buf = vec![
738 0b00001101, 0b11101111, 0b00000010, 0b00000001, ];
743 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
745 let buf = [buf, length_data.clone(), vec![fcs]].concat();
746
747 let res = Frame::parse(role, false, &buf[..]).unwrap();
748 let expected_frame = Frame {
749 role,
750 dlci: DLCI::try_from(3).unwrap(),
751 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
752 information: length_data,
753 })),
754 poll_final: false,
755 command_response: CommandResponse::Response,
756 credits: None,
757 };
758 assert_eq!(res, expected_frame);
759 }
760
761 #[test]
762 fn test_parse_uih_frame_with_mux_command() {
763 let role = Role::Responder;
764 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
765 let mut buf = vec![
766 0b00000001, 0b11111111, 0b00000111, 0b10010001, 0b00000011, 0b00011111, ];
773 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
775 buf.push(fcs);
776
777 let res = Frame::parse(role, false, &buf[..]).unwrap();
778 let expected_mux_command = MuxCommand {
779 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
780 dlci: DLCI::try_from(7).unwrap(),
781 port_values: None,
782 }),
783 command_response: CommandResponse::Response,
784 };
785 let expected_frame = Frame {
786 role,
787 dlci: DLCI::try_from(0).unwrap(),
788 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::Mux(expected_mux_command)),
789 poll_final: true,
790 command_response: CommandResponse::Response,
791 credits: None,
792 };
793 assert_eq!(res, expected_frame);
794 }
795
796 #[test]
797 fn test_parse_uih_frame_with_credits() {
798 let role = Role::Initiator;
799 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
800 let credit_based_flow = true;
801 let mut buf = vec![
802 0b00011111, 0b11111111, 0b00000111, 0b00000101, 0b00000000, 0b00000001, 0b00000010, ];
810 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
812 buf.push(fcs);
813
814 let res = Frame::parse(role, credit_based_flow, &buf[..]).unwrap();
815 let expected_user_data = UserData { information: vec![0x00, 0x01, 0x02] };
816 let expected_frame = Frame {
817 role,
818 dlci: DLCI::try_from(7).unwrap(),
819 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(expected_user_data)),
820 poll_final: true,
821 command_response: CommandResponse::Command,
822 credits: Some(5),
823 };
824 assert_eq!(res, expected_frame);
825 }
826
827 #[test]
828 fn test_encode_frame_invalid_buf() {
829 let frame = Frame {
830 role: Role::Unassigned,
831 dlci: DLCI::try_from(0).unwrap(),
832 data: FrameData::SetAsynchronousBalancedMode,
833 poll_final: false,
834 command_response: CommandResponse::Command,
835 credits: None,
836 };
837 let mut buf = [];
838 assert_matches!(frame.encode(&mut buf[..]), Err(FrameParseError::BufferTooSmall));
839 }
840
841 #[test]
843 fn test_encode_mux_startup_frame_over_user_dlci_fails() {
844 let frame = Frame {
845 role: Role::Unassigned,
846 dlci: DLCI::try_from(3).unwrap(),
847 data: FrameData::SetAsynchronousBalancedMode,
848 poll_final: false,
849 command_response: CommandResponse::Command,
850 credits: None,
851 };
852 let mut buf = vec![0; frame.encoded_len()];
853 assert_matches!(frame.encode(&mut buf[..]), Err(FrameParseError::InvalidFrame));
854 }
855
856 #[test]
857 fn encode_mux_startup_command_succeeds() {
858 let frame = Frame {
859 role: Role::Unassigned,
860 dlci: DLCI::try_from(0).unwrap(),
861 data: FrameData::SetAsynchronousBalancedMode,
862 poll_final: true,
863 command_response: CommandResponse::Command,
864 credits: None,
865 };
866 let mut buf = vec![0; frame.encoded_len()];
867 assert!(frame.encode(&mut buf[..]).is_ok());
868 let expected = vec![
869 0b00000011, 0b00111111, 0b00000001, 0b00011100, ];
874 assert_eq!(buf, expected);
875 }
876
877 #[test]
878 fn encode_mux_startup_response_succeeds() {
879 let frame = Frame::make_ua_response(Role::Unassigned, DLCI::try_from(0).unwrap());
880 let mut buf = vec![0; frame.encoded_len()];
881 assert!(frame.encode(&mut buf[..]).is_ok());
882 let expected = vec![
883 0b00000011, 0b01110011, 0b00000001, 0b11010111, ];
888 assert_eq!(buf, expected);
889 }
890
891 #[test]
892 fn encode_user_data_as_initiator_succeeds() {
893 let frame = Frame::make_user_data_frame(
894 Role::Initiator,
895 DLCI::try_from(3).unwrap(),
896 UserData {
897 information: vec![
898 0b00000001, 0b00000010, ],
901 },
902 Some(8),
903 );
904 let mut buf = vec![0; frame.encoded_len()];
905 assert!(frame.encode(&mut buf[..]).is_ok());
906 let expected = vec![
907 0b00001111, 0b11111111, 0b00000101, 0b00001000, 0b00000001, 0b00000010, 0b11110011, ];
915 assert_eq!(buf, expected);
916 }
917
918 #[test]
919 fn test_encode_user_data_as_responder_succeeds() {
920 let frame = Frame::make_user_data_frame(
921 Role::Responder,
922 DLCI::try_from(9).unwrap(),
923 UserData {
924 information: vec![
925 0b00000001, ],
927 },
928 Some(10),
929 );
930 let mut buf = vec![0; frame.encoded_len()];
931 assert!(frame.encode(&mut buf[..]).is_ok());
932 let expected = vec![
933 0b00100101, 0b11111111, 0b00000011, 0b00001010, 0b00000001, 0b11101001, ];
940 assert_eq!(buf, expected);
941 }
942
943 #[test]
944 fn encode_mux_command_as_initiator() {
945 let mux_command = MuxCommand {
946 params: MuxCommandParams::ModemStatus(ModemStatusParams::default(
947 DLCI::try_from(5).unwrap(),
948 )),
949 command_response: CommandResponse::Command,
950 };
951 let frame = Frame::make_mux_command(Role::Initiator, mux_command);
952
953 let mut buf = vec![0; frame.encoded_len()];
954 assert!(frame.encode(&mut buf[..]).is_ok());
955 let expected = vec![
956 0b00000011, 0b11101111, 0b00001001, 0b11100011, 0b00000101, 0b00010111, 0b10001101, 0b01110000, ];
965 assert_eq!(buf, expected);
966 }
967
968 #[test]
969 fn encode_mux_command_as_responder() {
970 let mux_command = MuxCommand {
971 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
972 dlci: DLCI::try_from(7).unwrap(),
973 port_values: None,
974 }),
975 command_response: CommandResponse::Command,
976 };
977 let frame = Frame::make_mux_command(Role::Responder, mux_command);
978
979 let mut buf = vec![0; frame.encoded_len()];
980 assert!(frame.encode(&mut buf[..]).is_ok());
981 let expected = vec![
982 0b00000001, 0b11101111, 0b00000111, 0b10010011, 0b00000011, 0b00011111, 0b10101010, ];
990 assert_eq!(buf, expected);
991 }
992
993 #[test]
994 fn encode_mux_response_as_initiator() {
995 let mux_command = MuxCommand {
996 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
997 dlci: DLCI::try_from(13).unwrap(),
998 port_values: None,
999 }),
1000 command_response: CommandResponse::Response,
1001 };
1002 let frame = Frame::make_mux_command(Role::Initiator, mux_command);
1003
1004 let mut buf = vec![0; frame.encoded_len()];
1005 assert!(frame.encode(&mut buf[..]).is_ok());
1006 let expected = vec![
1007 0b00000011, 0b11101111, 0b00000111, 0b10010001, 0b00000011, 0b00110111, 0b01110000, ];
1015 assert_eq!(buf, expected);
1016 }
1017
1018 #[test]
1019 fn encode_mux_response_as_responder() {
1020 let mux_command = MuxCommand {
1021 params: MuxCommandParams::ModemStatus(ModemStatusParams::default(
1022 DLCI::try_from(11).unwrap(),
1023 )),
1024 command_response: CommandResponse::Response,
1025 };
1026 let frame = Frame::make_mux_command(Role::Responder, mux_command);
1027
1028 let mut buf = vec![0; frame.encoded_len()];
1029 assert!(frame.encode(&mut buf[..]).is_ok());
1030 let expected = vec![
1031 0b00000001, 0b11101111, 0b00001001, 0b11100001, 0b00000101, 0b00101111, 0b10001101, 0b10101010, ];
1040 assert_eq!(buf, expected);
1041 }
1042
1043 #[test]
1044 fn test_encode_user_data_with_two_octet_length_succeeds() {
1045 let length = 130;
1046 let mut information = vec![0; length];
1047 let frame = Frame {
1048 role: Role::Initiator,
1049 dlci: DLCI::try_from(5).unwrap(),
1050 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
1051 information: information.clone(),
1052 })),
1053 poll_final: true,
1054 command_response: CommandResponse::Command,
1055 credits: Some(8),
1056 };
1057 let mut buf = vec![0; frame.encoded_len()];
1058 assert!(frame.encode(&mut buf[..]).is_ok());
1059 let mut expected = vec![
1060 0b00010111, 0b11111111, 0b00000100, 0b00000001, 0b00001000, ];
1066 expected.append(&mut information);
1068 expected.push(0b0000_1100);
1070 assert_eq!(buf, expected);
1071 }
1072}