Skip to main content

bt_rfcomm/frame/
mod.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use packet_encoding::{Decodable, Encodable, decodable_enum};
6
7/// The command or response classification used when parsing an RFCOMM frame.
8mod command_response;
9pub use command_response::CommandResponse;
10/// Errors associated with parsing an RFCOMM frame.
11mod error;
12pub use error::FrameParseError;
13/// Frame Check Sequence calculations.
14mod fcs;
15/// Field definitions for an RFCOMM frame.
16mod field;
17/// Definitions for multiplexer command frames.
18pub 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    /// The type of frame provided in the Control field.
27    /// The P/F bit is set to 0 for all frame types.
28    /// See table 2, GSM 07.10 Section 5.2.1.3 and RFCOMM 4.2.
29    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    /// Returns true if the frame type is a valid multiplexer start-up frame.
40    //
41    /// These are the only frames which are allowed to be sent before the multiplexer starts, and
42    /// must be sent over the Mux Control Channel.
43    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    /// Returns the number of octets needed when calculating the FCS.
51    fn fcs_octets(&self) -> usize {
52        // For UIH frames, the first 2 bytes of the buffer are used to calculate the FCS.
53        // Otherwise, the first 3. Defined in RFCOMM 5.1.1.
54        if *self == FrameTypeMarker::UnnumberedInfoHeaderCheck { 2 } else { 3 }
55    }
56
57    /// Returns true if the `frame_type` is expected to contain a credit octet.
58    ///
59    /// `credit_based_flow` indicates whether credit flow control is enabled for the session.
60    /// `poll_final` is the P/F bit associated with the Control Field of the frame.
61    /// `dlci` is the DLCI associated with the frame.
62    ///
63    /// RFCOMM 6.5.2 describes the RFCOMM specifics for credit-based flow control. Namely,
64    /// "...It does not apply to DLCI 0 or to non-UIH frames."
65    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/// A UIH Frame that contains user data.
74#[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/// The data associated with a UIH Frame.
114#[derive(Clone, Debug, PartialEq)]
115pub enum UIHData {
116    /// A UIH Frame with user data.
117    User(UserData),
118    /// A UIH Frame with a Mux Command.
119    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/// The types of frames supported in RFCOMM.
145/// See RFCOMM 4.2 for the supported frame types.
146#[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
217/// The minimum frame size (bytes) for an RFCOMM Frame - Address, Control, Length, FCS.
218/// See RFCOMM 5.1.
219const MIN_FRAME_SIZE: usize = 4;
220
221/// The maximum size (bytes) of an RFCOMM header in a packet.
222/// Address (1 byte), Control (1 byte), Length (2 bytes), Credits (1 byte), FCS (1 byte)
223/// See RFCOMM 5.1.
224pub const MAX_RFCOMM_HEADER_SIZE: usize = 6;
225
226/// The maximum length that can be represented in a single E/A padded octet.
227const MAX_SINGLE_OCTET_LENGTH: usize = 127;
228
229/// Maximum length (in bytes) for an RFCOMM frame payload.
230/// GSM 07.10 Section 5.2.1.4 limits length indicators to 15 bits.
231pub const MAX_INFORMATION_LENGTH: usize = 32767;
232
233/// Returns true if the provided `length` needs to be represented as 2 octets.
234fn is_two_octet_length(length: usize) -> bool {
235    length > MAX_SINGLE_OCTET_LENGTH
236}
237
238/// Returns the C/R bit for a non-UIH frame.
239fn cr_bit_for_non_uih_frame(role: Role, command_response: CommandResponse) -> bool {
240    // Defined in GSM Section 5.2.1.2 Table 1.
241    match (role, command_response) {
242        (Role::Initiator, CommandResponse::Command)
243        | (Role::Responder, CommandResponse::Response) => true,
244        _ => false,
245    }
246}
247
248/// Returns the C/R bit for a UIH frame.
249/// This must only be used on frames sent after multiplexer startup.
250fn cr_bit_for_uih_frame(role: Role) -> bool {
251    // The C/R bit is based on subclause 5.4.3.1 and matches the role of the device.
252    match role {
253        Role::Initiator => true,
254        _ => false,
255    }
256}
257
258/// The highest-level unit of data that is passed around in RFCOMM.
259#[derive(Clone, Debug, PartialEq)]
260pub struct Frame {
261    /// The role of the device associated with this frame.
262    pub role: Role,
263    /// The DLCI associated with this frame.
264    pub dlci: DLCI,
265    /// The data associated with this frame.
266    pub data: FrameData,
267    /// The P/F bit for this frame. See RFCOMM 5.2.1 which describes the usages
268    /// of the P/F bit in RFCOMM.
269    pub poll_final: bool,
270    /// Whether this frame is a Command or Response frame.
271    pub command_response: CommandResponse,
272    /// The credits associated with this frame. Credits are only applicable to UIH frames
273    /// when credit-based flow control is enabled. See RFCOMM 6.5.
274    pub credits: Option<u8>,
275}
276
277impl Frame {
278    /// Attempts to parse the provided `buf` into a Frame.
279    ///
280    /// `role` is the current Role of the RFCOMM Session.
281    /// `credit_based_flow` indicates whether credit-based flow control is turned on for this
282    /// Session.
283    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        // Parse the Address Field of the frame.
289        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        // Parse the Control Field of the frame.
294        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 the Session multiplexer hasn't started, then the `frame_type` must be a
299        // multiplexer startup frame.
300        if !role.is_multiplexer_started() && !frame_type.is_mux_startup(&dlci) {
301            return Err(FrameParseError::InvalidFrame);
302        }
303
304        // Classify the frame as either a Command or Response depending on the role, type of frame,
305        // and the C/R bit of the Address Field.
306        let command_response = CommandResponse::classify(role, frame_type, cr_bit)?;
307
308        // Parse the Information field of the Frame. If the EA bit is 0, then we need to construct
309        // the InformationLength using two bytes.
310        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        // The header size depends on the Information Length size and the (optional) credits octet.
318        // Address (1) + Control (1) + Length (1 or 2)
319        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        // Check the FCS before parsing the body of the packet.
330        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, // Always set for SABM.
351            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, // Always set for DM response.
362            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, // Always set for UA response.
373            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, // Always unset for UIH frames, GSM 5.4.3.1.
385            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        // When credit based flow control is supported, the `poll_final` bit is redefined
397        // for UIH frames. See RFCOMM 6.5.2. If credits are provided, then the `poll_final` bit
398        // should be set.
399        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, // Always set for Disconnect.
415            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        // Address + Control + FCS + (optional) Credits + 1 or 2 octets for Length + Frame data.
426        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            // The role is only determined after the multiplexer starts. Per GSM 5.2.1.2, the
441            // initiating side always sends the first SABM.
442            if self.data.marker() == FrameTypeMarker::SetAsynchronousBalancedMode {
443                Role::Initiator
444            } else {
445                Role::Responder
446            }
447        } else {
448            self.role
449        };
450        // The C/R bit of the Address Field depends on the frame type:
451        //   - For UIH frames, the C/R bit is based on GSM Section 5.4.3.1.
452        //   - For other frames, the C/R bit is determined by Table 1 in GSM Section 5.2.1.2.
453        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        // Set the Address Field, E/A = 1 since there is only one octet.
460        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        // Control Field.
467        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        // Information Field.
473        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 the length is two octets, get the upper 8 bits and set the second octet.
483        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        // Address + Control + Information.
489        let mut header_size = 2 + if is_two_octet_length { 2 } else { 1 };
490
491        // Encode the credits for this frame, if applicable.
492        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        // Frame data.
501        self.data.encode(&mut buf[header_size..fcs_idx])?;
502
503        // FCS that is computed based on `frame_type`.
504        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(); // Mux DLCI.
560        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, // Address Field - EA = 1, C/R = 0, DLCI = 1.
585            0b00101111, // Control Field - SABM command with P/F = 0.
586            0b00000001, // Length Field - Bit0 = 1: Indicates one octet length.
587            0x00,       // Random FCS.
588        ];
589        assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::InvalidDLCI(1)));
590    }
591
592    /// It's possible that a remote device sends a packet with an invalid frame.
593    /// In this case, we should error gracefully.
594    #[test]
595    fn test_parse_invalid_frame_type() {
596        let role = Role::Unassigned;
597        let buf: &[u8] = &[
598            0b00000001, // Address Field - EA = 1, C/R = 0, DLCI = 0.
599            0b10101010, // Control Field - Invalid command with P/F = 0.
600            0b00000001, // Length Field - Bit1 = 0 indicates 1 octet length.
601            0x00,       // Random FCS.
602        ];
603        assert_matches!(Frame::parse(role, false, buf), Err(FrameParseError::UnsupportedFrameType));
604    }
605
606    /// It's possible that the remote peer sends a packet for a valid frame, but the session
607    /// multiplexer has not started. In this case, we should error gracefully.
608    #[test]
609    fn test_parse_invalid_frame_type_sent_before_mux_startup() {
610        let role = Role::Unassigned;
611        let buf: &[u8] = &[
612            0b00000001, // Address Field - EA = 1, C/R = 0, DLCI = 0.
613            0b11101111, // Control Field - UnnumberedInfoHeaderCheck with P/F = 0.
614            0b00000001, // Length Field - Bit1 = 0 indicates 1 octet length.
615            0x00,       // Random FCS.
616        ];
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, // Address Field - EA = 1, C/R = 1, DLCI = 0.
625            0b00101111, // Control Field - SABM command with P/F = 0.
626            0b00000000, // Length Field - Bit1 = 0 Indicates two octet length.
627            0b00000001, // Second octet of length.
628                        // Missing FCS.
629        ];
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, // Address Field - EA = 1, C/R = 1, DLCI = 0.
639            0b00101111, // Control Field - SABM command with P/F = 0.
640            0b00000001, // Length Field - Bit1 = 1 Indicates one octet length - no info.
641        ];
642        // Calculate the FCS and tack it on to the end.
643        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, // Address Field - EA = 1, C/R = 1, User DLCI = 3.
664            0b00101111, // Control Field - SABM command with P/F = 0.
665            0b00000001, // Length Field - Bit1 = 1 Indicates one octet length - no info.
666        ];
667        // Calculate the FCS for the first three bytes, since non-UIH frame.
668        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, // Address Field - EA = 1, C/R = 1, User DLCI = 3.
689            0b11101111, // Control Field - UIH command with P/F = 0.
690            0b00000111, // Length Field - Bit1 = 1 Indicates one octet length = 3.
691            0b00000000, // Data octet #1 - missing octets 2,3.
692        ];
693        // Calculate the FCS for the first two bytes, since UIH frame.
694        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, // Address Field - EA = 1, C/R = 0, User DLCI = 3.
706            0b11101111, // Control Field - UIH command with P/F = 0.
707            0b00000101, // Length Field - Bit1 = 1 Indicates one octet length = 2.
708            0b00000000, // Data octet #1,
709            0b00000000, // Data octet #2,
710        ];
711        // Calculate the FCS for the first two bytes, since UIH frame.
712        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, // Data octet #1.
722                    0b00000000, // Data octet #2.
723                ],
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        // Concatenate the header, `length_data` payload, and FCS.
740        let buf = vec![
741            0b00001101, // Address Field - EA = 1, C/R = 0, User DLCI = 3.
742            0b11101111, // Control Field - UIH command with P/F = 0.
743            0b00000010, // Length Field0 - E/A = 0. Length = 1.
744            0b00000001, // Length Field1 - No E/A. Length = 128.
745        ];
746        // Calculate the FCS for the first two bytes, since UIH frame.
747        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, // Address Field - EA = 1, C/R = 0, Mux DLCI = 0.
770            0b11111111, // Control Field - UIH command with P/F = 1.
771            0b00000111, // Length Field - Bit1 = 1 Indicates one octet length = 3.
772            0b10010001, // Data octet #1 - RPN command.
773            0b00000011, // Data octet #2 - RPN Command length = 1.
774            0b00011111, // Data octet #3 - RPN Data, DLCI = 7.
775        ];
776        // Calculate the FCS for the first two bytes, since UIH frame.
777        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, // Address Field - EA = 1, C/R = 1, User DLCI = 7.
806            0b11111111, // Control Field - UIH command with P/F = 1.
807            0b00000111, // Length Field - Bit1 = 1 Indicates one octet length = 3.
808            0b00000101, // Credits Field = 5.
809            0b00000000, // UserData octet #1.
810            0b00000001, // UserData octet #2.
811            0b00000010, // UserData octet #3.
812        ];
813        // Calculate the FCS for the first two bytes, since UIH frame.
814        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    /// Tests that attempting to encode a Mux Startup frame over a user DLCI is rejected.
845    #[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, // Address Field: DLCI = 0, C/R = 1, E/A = 1.
873            0b00111111, // Control Field: SABM, P/F = 1.
874            0b00000001, // Length Field: Length = 0, E/A = 1.
875            0b00011100, // FCS - precomputed.
876        ];
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, // Address Field: DLCI = 0, C/R = 1, E/A = 1.
887            0b01110011, // Control Field: UA, P/F = 1.
888            0b00000001, // Length Field: Length = 0, E/A = 1.
889            0b11010111, // FCS - precomputed.
890        ];
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, // Data octet #1.
902                    0b00000010, // Data octet #2.
903                ],
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, // Address Field: DLCI = 3, C/R = 1, E/A = 1.
911            0b11111111, // Control Field - UIH command with P/F = 1.
912            0b00000101, // Length Field - Bit1 = 1 Indicates one octet, length = 2.
913            0b00001000, // Credit Field - Credits = 8.
914            0b00000001, // Data octet #1.
915            0b00000010, // Data octet #2.
916            0b11110011, // FCS - precomputed.
917        ];
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, // Data octet #1.
929                ],
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, // Address Field: DLCI = 3, C/R = 0, E/A = 1.
937            0b11111111, // Control Field - UIH command with P/F = 1.
938            0b00000011, // Length Field - Bit1 = 1 Indicates one octet, length = 1.
939            0b00001010, // Credit Field - Credits = 10.
940            0b00000001, // Data octet #1.
941            0b11101001, // FCS - precomputed.
942        ];
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, // Address Field: DLCI = 0, C/R = 1, E/A = 1.
960            0b11101111, // Control Field - UIH command with P/F = 1.
961            0b00001001, // Length Field - Bit1 = 1 Indicates one octet, length = 4.
962            0b11100011, // Data octet #1 - MSC response, C/R = 1, E/A = 1.
963            0b00000101, // Data octet #2 - Length = 2, E/A = 1.
964            0b00010111, // Data octet #3 DLCI = 5, E/A = 1, Bit2 = 1 always.
965            0b10001101, // Data octet #4 Signals = default, E/A = 1.
966            0b01110000, // FCS - precomputed.
967        ];
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, // Address Field: DLCI = 0, C/R = 0, E/A = 1.
986            0b11101111, // Control Field - UIH command with P/F = 1.
987            0b00000111, // Length Field - Bit1 = 1 Indicates one octet, length = 3.
988            0b10010011, // Data octet #1 - RPN command, C/R = 1, E/A = 1.
989            0b00000011, // Data octet #2 - RPN Command length = 1.
990            0b00011111, // Data octet #3 - RPN Data, DLCI = 7.
991            0b10101010, // FCS - precomputed.
992        ];
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, // Address Field: DLCI = 0, C/R = 1, E/A = 1.
1011            0b11101111, // Control Field - UIH command with P/F = 1.
1012            0b00000111, // Length Field - Bit1 = 1 Indicates one octet, length = 3.
1013            0b10010001, // Data octet #1 - RPN command, C/R = 0, E/A = 1.
1014            0b00000011, // Data octet #2 - RPN Command length = 1.
1015            0b00110111, // Data octet #3 - RPN Data, DLCI = 7.
1016            0b01110000, // FCS - precomputed.
1017        ];
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, // Address Field: DLCI = 0, C/R = 0, E/A = 1.
1035            0b11101111, // Control Field - UIH command with P/F = 1.
1036            0b00001001, // Length Field - Bit1 = 1 Indicates one octet, length = 4.
1037            0b11100001, // Data octet #1 - MSC response, C/R = 0, E/A = 1.
1038            0b00000101, // Data octet #2 - Length = 2, E/A = 1.
1039            0b00101111, // Data octet #3 DLCI = 11, E/A = 1, Bit2 = 1 always.
1040            0b10001101, // Data octet #4 Signals = default, E/A = 1.
1041            0b10101010, // FCS - precomputed.
1042        ];
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, // Address Field: DLCI = 5, C/R = 1, E/A = 1.
1064            0b11111111, // Control Field - UIH command with P/F = 1.
1065            0b00000100, // Length Field - E/A = 0. Length = 2.
1066            0b00000001, // Length Field2 - 128.
1067            0b00001000, // Credit Field - Credits = 8.
1068        ];
1069        // Add the information.
1070        expected.append(&mut information);
1071        // Add the precomputed FCS.
1072        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, // Address Field - EA = 1, C/R = 1, User DLCI = 3.
1082            0b00101111, // Control Field - SABM command with P/F = 0.
1083            0b00000001, // Length Field - Bit1 = 1 Indicates one octet length - no info.
1084        ];
1085        // Calculate the correct FCS.
1086        let correct_fcs = calculate_fcs(&buf[..frame_type.fcs_octets()]);
1087        // Mutate the FCS to make it invalid.
1088        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}