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
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
229fn is_two_octet_length(length: usize) -> bool {
231 length > MAX_SINGLE_OCTET_LENGTH
232}
233
234fn cr_bit_for_non_uih_frame(role: Role, command_response: CommandResponse) -> bool {
236 match (role, command_response) {
238 (Role::Initiator, CommandResponse::Command)
239 | (Role::Responder, CommandResponse::Response) => true,
240 _ => false,
241 }
242}
243
244fn cr_bit_for_uih_frame(role: Role) -> bool {
247 match role {
249 Role::Initiator => true,
250 _ => false,
251 }
252}
253
254#[derive(Clone, Debug, PartialEq)]
256pub struct Frame {
257 pub role: Role,
259 pub dlci: DLCI,
261 pub data: FrameData,
263 pub poll_final: bool,
266 pub command_response: CommandResponse,
268 pub credits: Option<u8>,
271}
272
273impl Frame {
274 pub fn parse(role: Role, credit_based_flow: bool, buf: &[u8]) -> Result<Self, FrameParseError> {
280 if buf.len() < MIN_FRAME_SIZE {
281 return Err(FrameParseError::BufferTooSmall);
282 }
283
284 let address_field = AddressField(buf[FRAME_ADDRESS_IDX]);
286 let dlci: DLCI = address_field.dlci()?;
287 let cr_bit: bool = address_field.cr_bit();
288
289 let control_field = ControlField(buf[FRAME_CONTROL_IDX]);
291 let frame_type: FrameTypeMarker = control_field.frame_type()?;
292 let poll_final = control_field.poll_final();
293
294 if !role.is_multiplexer_started() && !frame_type.is_mux_startup(&dlci) {
297 return Err(FrameParseError::InvalidFrame);
298 }
299
300 let command_response = CommandResponse::classify(role, frame_type, cr_bit)?;
303
304 let information_field = InformationField(buf[FRAME_INFORMATION_IDX]);
307 let is_two_octet_length = !information_field.ea_bit();
308 let mut length = information_field.length() as u16;
309 if is_two_octet_length {
310 length |= (buf[FRAME_INFORMATION_IDX + 1] as u16) << INFORMATION_SECOND_OCTET_SHIFT;
311 }
312
313 let mut header_size = 2 + if is_two_octet_length { 2 } else { 1 };
316 let mut credits = None;
317 if frame_type.has_credit_octet(credit_based_flow, poll_final, dlci) {
318 if buf.len() < header_size {
319 return Err(FrameParseError::BufferTooSmall);
320 }
321 credits = Some(buf[header_size]);
322 header_size += 1;
323 }
324
325 let fcs_index = header_size + usize::from(length);
327 if buf.len() <= fcs_index {
328 return Err(FrameParseError::BufferTooSmall);
329 }
330 let fcs = buf[fcs_index];
331 if !verify_fcs(fcs, &buf[..frame_type.fcs_octets()]) {
332 return Err(FrameParseError::FCSCheckFailed);
333 }
334
335 let data = &buf[header_size..fcs_index];
336 let data = FrameData::decode(&frame_type, &dlci, data)?;
337
338 Ok(Self { role, dlci, data, poll_final, command_response, credits })
339 }
340
341 pub fn make_sabm_command(role: Role, dlci: DLCI) -> Self {
342 Self {
343 role,
344 dlci,
345 data: FrameData::SetAsynchronousBalancedMode,
346 poll_final: true, command_response: CommandResponse::Command,
348 credits: None,
349 }
350 }
351
352 pub fn make_dm_response(role: Role, dlci: DLCI) -> Self {
353 Self {
354 role,
355 dlci,
356 data: FrameData::DisconnectedMode,
357 poll_final: true, command_response: CommandResponse::Response,
359 credits: None,
360 }
361 }
362
363 pub fn make_ua_response(role: Role, dlci: DLCI) -> Self {
364 Self {
365 role,
366 dlci,
367 data: FrameData::UnnumberedAcknowledgement,
368 poll_final: true, command_response: CommandResponse::Response,
370 credits: None,
371 }
372 }
373
374 pub fn make_mux_command(role: Role, data: MuxCommand) -> Self {
375 let command_response = data.command_response;
376 Self {
377 role,
378 dlci: DLCI::MUX_CONTROL_DLCI,
379 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::Mux(data)),
380 poll_final: false, command_response,
382 credits: None,
383 }
384 }
385
386 pub fn make_user_data_frame(
387 role: Role,
388 dlci: DLCI,
389 user_data: UserData,
390 credits: Option<u8>,
391 ) -> Self {
392 Self {
396 role,
397 dlci,
398 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(user_data)),
399 poll_final: credits.is_some(),
400 command_response: CommandResponse::Command,
401 credits,
402 }
403 }
404
405 pub fn make_disc_command(role: Role, dlci: DLCI) -> Self {
406 Self {
407 role,
408 dlci,
409 data: FrameData::Disconnect,
410 poll_final: true, command_response: CommandResponse::Command,
412 credits: None,
413 }
414 }
415}
416
417impl Encodable for Frame {
418 type Error = FrameParseError;
419
420 fn encoded_len(&self) -> usize {
421 3 + self.credits.map_or(0, |_| 1)
423 + if is_two_octet_length(self.data.encoded_len()) { 2 } else { 1 }
424 + self.data.encoded_len()
425 }
426
427 fn encode(&self, buf: &mut [u8]) -> Result<(), FrameParseError> {
428 if buf.len() != self.encoded_len() {
429 return Err(FrameParseError::BufferTooSmall);
430 }
431
432 let assumed_role = if !self.role.is_multiplexer_started() {
433 if !self.data.marker().is_mux_startup(&self.dlci) {
434 return Err(FrameParseError::InvalidFrame);
435 }
436 if self.data.marker() == FrameTypeMarker::SetAsynchronousBalancedMode {
439 Role::Initiator
440 } else {
441 Role::Responder
442 }
443 } else {
444 self.role
445 };
446 let cr_bit = if self.data.marker() == FrameTypeMarker::UnnumberedInfoHeaderCheck {
450 cr_bit_for_uih_frame(assumed_role)
451 } else {
452 cr_bit_for_non_uih_frame(assumed_role, self.command_response)
453 };
454
455 let mut address_field = AddressField(0);
457 address_field.set_ea_bit(true);
458 address_field.set_cr_bit(cr_bit);
459 address_field.set_dlci(u8::from(self.dlci));
460 buf[FRAME_ADDRESS_IDX] = address_field.0;
461
462 let mut control_field = ControlField(0);
464 control_field.set_frame_type(u8::from(&self.data.marker()));
465 control_field.set_poll_final(self.poll_final);
466 buf[FRAME_CONTROL_IDX] = control_field.0;
467
468 let data_length = self.data.encoded_len();
470 let is_two_octet_length = is_two_octet_length(data_length);
471 let mut first_octet_length = InformationField(0);
472 first_octet_length.set_length(data_length as u8);
473 first_octet_length.set_ea_bit(!is_two_octet_length);
474 buf[FRAME_INFORMATION_IDX] = first_octet_length.0;
475 if is_two_octet_length {
477 let second_octet_length = (data_length >> INFORMATION_SECOND_OCTET_SHIFT) as u8;
478 buf[FRAME_INFORMATION_IDX + 1] = second_octet_length;
479 }
480
481 let mut header_size = 2 + if is_two_octet_length { 2 } else { 1 };
483
484 let credit_based_flow = self.credits.is_some();
486 if self.data.marker().has_credit_octet(credit_based_flow, self.poll_final, self.dlci) {
487 buf[header_size] = self.credits.unwrap();
488 header_size += 1;
489 }
490
491 let fcs_idx = header_size + data_length as usize;
492
493 self.data.encode(&mut buf[header_size..fcs_idx])?;
495
496 buf[fcs_idx] = calculate_fcs(&buf[..self.data.marker().fcs_octets()]);
498
499 Ok(())
500 }
501}
502
503#[cfg(test)]
504mod tests {
505 use crate::frame::mux_commands::ModemStatusParams;
506
507 use super::*;
508
509 use assert_matches::assert_matches;
510 use mux_commands::{MuxCommandParams, RemotePortNegotiationParams};
511
512 #[test]
513 fn test_is_mux_startup_frame() {
514 let control_dlci = DLCI::try_from(0).unwrap();
515 let user_dlci = DLCI::try_from(5).unwrap();
516
517 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
518 assert!(frame_type.is_mux_startup(&control_dlci));
519 assert!(!frame_type.is_mux_startup(&user_dlci));
520
521 let frame_type = FrameTypeMarker::UnnumberedAcknowledgement;
522 assert!(frame_type.is_mux_startup(&control_dlci));
523 assert!(!frame_type.is_mux_startup(&user_dlci));
524
525 let frame_type = FrameTypeMarker::DisconnectedMode;
526 assert!(frame_type.is_mux_startup(&control_dlci));
527 assert!(!frame_type.is_mux_startup(&user_dlci));
528
529 let frame_type = FrameTypeMarker::Disconnect;
530 assert!(!frame_type.is_mux_startup(&control_dlci));
531 assert!(!frame_type.is_mux_startup(&user_dlci));
532 }
533
534 #[test]
535 fn test_has_credit_octet() {
536 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
537 let pf = true;
538 let credit_based_flow = true;
539 let dlci = DLCI::try_from(3).unwrap();
540 assert!(frame_type.has_credit_octet(credit_based_flow, pf, dlci));
541
542 let pf = false;
543 let credit_based_flow = true;
544 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
545
546 let pf = true;
547 let credit_based_flow = false;
548 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
549
550 let pf = true;
551 let credit_based_flow = true;
552 let dlci = DLCI::try_from(0).unwrap(); assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
554
555 let pf = false;
556 let credit_based_flow = false;
557 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
558
559 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
560 let pf = true;
561 let credit_based_flow = true;
562 let dlci = DLCI::try_from(5).unwrap();
563 assert!(!frame_type.has_credit_octet(credit_based_flow, pf, dlci));
564 }
565
566 #[test]
567 fn test_parse_too_small_frame() {
568 let role = Role::Unassigned;
569 let buf: &[u8] = &[0x00];
570 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::BufferTooSmall));
571 }
572
573 #[test]
574 fn test_parse_invalid_dlci() {
575 let role = Role::Unassigned;
576 let buf: &[u8] = &[
577 0b00000101, 0b00101111, 0b00000001, 0x00, ];
582 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::InvalidDLCI(1)));
583 }
584
585 #[test]
588 fn test_parse_invalid_frame_type() {
589 let role = Role::Unassigned;
590 let buf: &[u8] = &[
591 0b00000001, 0b10101010, 0b00000001, 0x00, ];
596 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::UnsupportedFrameType));
597 }
598
599 #[test]
602 fn test_parse_invalid_frame_type_sent_before_mux_startup() {
603 let role = Role::Unassigned;
604 let buf: &[u8] = &[
605 0b00000001, 0b11101111, 0b00000001, 0x00, ];
610 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::InvalidFrame));
611 }
612
613 #[test]
614 fn test_parse_invalid_frame_missing_fcs() {
615 let role = Role::Unassigned;
616 let buf: &[u8] = &[
617 0b00000011, 0b00101111, 0b00000000, 0b00000001, ];
623 assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::BufferTooSmall));
624 }
625
626 #[test]
627 fn test_parse_valid_frame_over_mux_dlci() {
628 let role = Role::Unassigned;
629 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
630 let mut buf = vec![
631 0b00000011, 0b00101111, 0b00000001, ];
635 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
637 buf.push(fcs);
638
639 let res = Frame::parse(role, false, &buf[..]).unwrap();
640 let expected_frame = Frame {
641 role,
642 dlci: DLCI::try_from(0).unwrap(),
643 data: FrameData::SetAsynchronousBalancedMode,
644 poll_final: false,
645 command_response: CommandResponse::Command,
646 credits: None,
647 };
648 assert_eq!(res, expected_frame);
649 }
650
651 #[test]
652 fn test_parse_valid_frame_over_user_dlci() {
653 let role = Role::Responder;
654 let frame_type = FrameTypeMarker::SetAsynchronousBalancedMode;
655 let mut buf = vec![
656 0b00001111, 0b00101111, 0b00000001, ];
660 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
662 buf.push(fcs);
663
664 let res = Frame::parse(role, false, &buf[..]).unwrap();
665 let expected_frame = Frame {
666 role,
667 dlci: DLCI::try_from(3).unwrap(),
668 data: FrameData::SetAsynchronousBalancedMode,
669 poll_final: false,
670 command_response: CommandResponse::Response,
671 credits: None,
672 };
673 assert_eq!(res, expected_frame);
674 }
675
676 #[test]
677 fn test_parse_frame_with_information_length_invalid_buf_size() {
678 let role = Role::Responder;
679 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
680 let mut buf = vec![
681 0b00001111, 0b11101111, 0b00000111, 0b00000000, ];
686 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
688 buf.push(fcs);
689
690 assert_matches!(Frame::parse(role, false, &buf[..]), Err(FrameParseError::BufferTooSmall));
691 }
692
693 #[test]
694 fn test_parse_valid_frame_with_information_length() {
695 let role = Role::Responder;
696 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
697 let mut buf = vec![
698 0b00001101, 0b11101111, 0b00000101, 0b00000000, 0b00000000, ];
704 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
706 buf.push(fcs);
707
708 let res = Frame::parse(role, false, &buf[..]).unwrap();
709 let expected_frame = Frame {
710 role,
711 dlci: DLCI::try_from(3).unwrap(),
712 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
713 information: vec![
714 0b00000000, 0b00000000, ],
717 })),
718 poll_final: false,
719 command_response: CommandResponse::Response,
720 credits: None,
721 };
722 assert_eq!(res, expected_frame);
723 }
724
725 #[test]
726 fn test_parse_valid_frame_with_two_octet_information_length() {
727 let role = Role::Responder;
728 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
729 let length = 129;
730 let length_data = vec![0; length];
731
732 let buf = vec![
734 0b00001101, 0b11101111, 0b00000010, 0b00000001, ];
739 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
741 let buf = [buf, length_data.clone(), vec![fcs]].concat();
742
743 let res = Frame::parse(role, false, &buf[..]).unwrap();
744 let expected_frame = Frame {
745 role,
746 dlci: DLCI::try_from(3).unwrap(),
747 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
748 information: length_data,
749 })),
750 poll_final: false,
751 command_response: CommandResponse::Response,
752 credits: None,
753 };
754 assert_eq!(res, expected_frame);
755 }
756
757 #[test]
758 fn test_parse_uih_frame_with_mux_command() {
759 let role = Role::Responder;
760 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
761 let mut buf = vec![
762 0b00000001, 0b11111111, 0b00000111, 0b10010001, 0b00000011, 0b00011111, ];
769 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
771 buf.push(fcs);
772
773 let res = Frame::parse(role, false, &buf[..]).unwrap();
774 let expected_mux_command = MuxCommand {
775 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
776 dlci: DLCI::try_from(7).unwrap(),
777 port_values: None,
778 }),
779 command_response: CommandResponse::Response,
780 };
781 let expected_frame = Frame {
782 role,
783 dlci: DLCI::try_from(0).unwrap(),
784 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::Mux(expected_mux_command)),
785 poll_final: true,
786 command_response: CommandResponse::Response,
787 credits: None,
788 };
789 assert_eq!(res, expected_frame);
790 }
791
792 #[test]
793 fn test_parse_uih_frame_with_credits() {
794 let role = Role::Initiator;
795 let frame_type = FrameTypeMarker::UnnumberedInfoHeaderCheck;
796 let credit_based_flow = true;
797 let mut buf = vec![
798 0b00011111, 0b11111111, 0b00000111, 0b00000101, 0b00000000, 0b00000001, 0b00000010, ];
806 let fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
808 buf.push(fcs);
809
810 let res = Frame::parse(role, credit_based_flow, &buf[..]).unwrap();
811 let expected_user_data = UserData { information: vec![0x00, 0x01, 0x02] };
812 let expected_frame = Frame {
813 role,
814 dlci: DLCI::try_from(7).unwrap(),
815 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(expected_user_data)),
816 poll_final: true,
817 command_response: CommandResponse::Command,
818 credits: Some(5),
819 };
820 assert_eq!(res, expected_frame);
821 }
822
823 #[test]
824 fn test_encode_frame_invalid_buf() {
825 let frame = Frame {
826 role: Role::Unassigned,
827 dlci: DLCI::try_from(0).unwrap(),
828 data: FrameData::SetAsynchronousBalancedMode,
829 poll_final: false,
830 command_response: CommandResponse::Command,
831 credits: None,
832 };
833 let mut buf = [];
834 assert_matches!(frame.encode(&mut buf[..]), Err(FrameParseError::BufferTooSmall));
835 }
836
837 #[test]
839 fn test_encode_mux_startup_frame_over_user_dlci_fails() {
840 let frame = Frame {
841 role: Role::Unassigned,
842 dlci: DLCI::try_from(3).unwrap(),
843 data: FrameData::SetAsynchronousBalancedMode,
844 poll_final: false,
845 command_response: CommandResponse::Command,
846 credits: None,
847 };
848 let mut buf = vec![0; frame.encoded_len()];
849 assert_matches!(frame.encode(&mut buf[..]), Err(FrameParseError::InvalidFrame));
850 }
851
852 #[test]
853 fn encode_mux_startup_command_succeeds() {
854 let frame = Frame {
855 role: Role::Unassigned,
856 dlci: DLCI::try_from(0).unwrap(),
857 data: FrameData::SetAsynchronousBalancedMode,
858 poll_final: true,
859 command_response: CommandResponse::Command,
860 credits: None,
861 };
862 let mut buf = vec![0; frame.encoded_len()];
863 assert!(frame.encode(&mut buf[..]).is_ok());
864 let expected = vec![
865 0b00000011, 0b00111111, 0b00000001, 0b00011100, ];
870 assert_eq!(buf, expected);
871 }
872
873 #[test]
874 fn encode_mux_startup_response_succeeds() {
875 let frame = Frame::make_ua_response(Role::Unassigned, DLCI::try_from(0).unwrap());
876 let mut buf = vec![0; frame.encoded_len()];
877 assert!(frame.encode(&mut buf[..]).is_ok());
878 let expected = vec![
879 0b00000011, 0b01110011, 0b00000001, 0b11010111, ];
884 assert_eq!(buf, expected);
885 }
886
887 #[test]
888 fn encode_user_data_as_initiator_succeeds() {
889 let frame = Frame::make_user_data_frame(
890 Role::Initiator,
891 DLCI::try_from(3).unwrap(),
892 UserData {
893 information: vec![
894 0b00000001, 0b00000010, ],
897 },
898 Some(8),
899 );
900 let mut buf = vec![0; frame.encoded_len()];
901 assert!(frame.encode(&mut buf[..]).is_ok());
902 let expected = vec![
903 0b00001111, 0b11111111, 0b00000101, 0b00001000, 0b00000001, 0b00000010, 0b11110011, ];
911 assert_eq!(buf, expected);
912 }
913
914 #[test]
915 fn test_encode_user_data_as_responder_succeeds() {
916 let frame = Frame::make_user_data_frame(
917 Role::Responder,
918 DLCI::try_from(9).unwrap(),
919 UserData {
920 information: vec![
921 0b00000001, ],
923 },
924 Some(10),
925 );
926 let mut buf = vec![0; frame.encoded_len()];
927 assert!(frame.encode(&mut buf[..]).is_ok());
928 let expected = vec![
929 0b00100101, 0b11111111, 0b00000011, 0b00001010, 0b00000001, 0b11101001, ];
936 assert_eq!(buf, expected);
937 }
938
939 #[test]
940 fn encode_mux_command_as_initiator() {
941 let mux_command = MuxCommand {
942 params: MuxCommandParams::ModemStatus(ModemStatusParams::default(
943 DLCI::try_from(5).unwrap(),
944 )),
945 command_response: CommandResponse::Command,
946 };
947 let frame = Frame::make_mux_command(Role::Initiator, mux_command);
948
949 let mut buf = vec![0; frame.encoded_len()];
950 assert!(frame.encode(&mut buf[..]).is_ok());
951 let expected = vec![
952 0b00000011, 0b11101111, 0b00001001, 0b11100011, 0b00000101, 0b00010111, 0b10001101, 0b01110000, ];
961 assert_eq!(buf, expected);
962 }
963
964 #[test]
965 fn encode_mux_command_as_responder() {
966 let mux_command = MuxCommand {
967 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
968 dlci: DLCI::try_from(7).unwrap(),
969 port_values: None,
970 }),
971 command_response: CommandResponse::Command,
972 };
973 let frame = Frame::make_mux_command(Role::Responder, mux_command);
974
975 let mut buf = vec![0; frame.encoded_len()];
976 assert!(frame.encode(&mut buf[..]).is_ok());
977 let expected = vec![
978 0b00000001, 0b11101111, 0b00000111, 0b10010011, 0b00000011, 0b00011111, 0b10101010, ];
986 assert_eq!(buf, expected);
987 }
988
989 #[test]
990 fn encode_mux_response_as_initiator() {
991 let mux_command = MuxCommand {
992 params: MuxCommandParams::RemotePortNegotiation(RemotePortNegotiationParams {
993 dlci: DLCI::try_from(13).unwrap(),
994 port_values: None,
995 }),
996 command_response: CommandResponse::Response,
997 };
998 let frame = Frame::make_mux_command(Role::Initiator, mux_command);
999
1000 let mut buf = vec![0; frame.encoded_len()];
1001 assert!(frame.encode(&mut buf[..]).is_ok());
1002 let expected = vec![
1003 0b00000011, 0b11101111, 0b00000111, 0b10010001, 0b00000011, 0b00110111, 0b01110000, ];
1011 assert_eq!(buf, expected);
1012 }
1013
1014 #[test]
1015 fn encode_mux_response_as_responder() {
1016 let mux_command = MuxCommand {
1017 params: MuxCommandParams::ModemStatus(ModemStatusParams::default(
1018 DLCI::try_from(11).unwrap(),
1019 )),
1020 command_response: CommandResponse::Response,
1021 };
1022 let frame = Frame::make_mux_command(Role::Responder, mux_command);
1023
1024 let mut buf = vec![0; frame.encoded_len()];
1025 assert!(frame.encode(&mut buf[..]).is_ok());
1026 let expected = vec![
1027 0b00000001, 0b11101111, 0b00001001, 0b11100001, 0b00000101, 0b00101111, 0b10001101, 0b10101010, ];
1036 assert_eq!(buf, expected);
1037 }
1038
1039 #[test]
1040 fn test_encode_user_data_with_two_octet_length_succeeds() {
1041 let length = 130;
1042 let mut information = vec![0; length];
1043 let frame = Frame {
1044 role: Role::Initiator,
1045 dlci: DLCI::try_from(5).unwrap(),
1046 data: FrameData::UnnumberedInfoHeaderCheck(UIHData::User(UserData {
1047 information: information.clone(),
1048 })),
1049 poll_final: true,
1050 command_response: CommandResponse::Command,
1051 credits: Some(8),
1052 };
1053 let mut buf = vec![0; frame.encoded_len()];
1054 assert!(frame.encode(&mut buf[..]).is_ok());
1055 let mut expected = vec![
1056 0b00010111, 0b11111111, 0b00000100, 0b00000001, 0b00001000, ];
1062 expected.append(&mut information);
1064 expected.push(0b0000_1100);
1066 assert_eq!(buf, expected);
1067 }
1068}