1#![allow(dead_code)]
11
12#[cfg(feature = "alloc")]
13use alloc::collections::BTreeMap;
14#[cfg(feature = "alloc")]
15#[allow(unused_imports)]
16use alloc::vec::Vec;
17
18use crate::error::KernelError;
19
20pub const FRAME_SABM: u8 = 0x2F;
26
27pub const FRAME_UA: u8 = 0x63;
29
30pub const FRAME_DM: u8 = 0x0F;
32
33pub const FRAME_DISC: u8 = 0x43;
35
36pub const FRAME_UIH: u8 = 0xEF;
38
39pub const MAX_DLCI: u8 = 30;
45
46pub const DLCI_CONTROL: u8 = 0;
48
49pub const RFCOMM_PSM: u16 = 0x0003;
51
52pub const RFCOMM_DEFAULT_MTU: u16 = 127;
54
55pub const RFCOMM_MAX_MTU: u16 = 32767;
57
58pub const DEFAULT_INITIAL_CREDITS: u8 = 7;
60
61pub const fn encode_address(dlci: u8, cr: bool, ea: bool) -> u8 {
68 ((dlci & 0x3F) << 2) | ((cr as u8) << 1) | (ea as u8)
69}
70
71pub const fn decode_dlci(address: u8) -> u8 {
73 (address >> 2) & 0x3F
74}
75
76pub const fn decode_cr(address: u8) -> bool {
78 (address & 0x02) != 0
79}
80
81const FCS_TABLE: [u8; 256] = generate_fcs_table();
87
88const fn generate_fcs_table() -> [u8; 256] {
90 let mut table = [0u8; 256];
91 let mut i = 0u16;
92 while i < 256 {
93 let mut crc = i as u8;
94 let mut bit = 0;
95 while bit < 8 {
96 if crc & 1 != 0 {
97 crc = (crc >> 1) ^ 0xE0;
98 } else {
99 crc >>= 1;
100 }
101 bit += 1;
102 }
103 table[i as usize] = crc;
104 i += 1;
105 }
106 table
107}
108
109pub fn calculate_fcs(data: &[u8]) -> u8 {
111 let mut fcs = 0xFFu8;
112 for &byte in data {
113 fcs = FCS_TABLE[(fcs ^ byte) as usize];
114 }
115 0xFF - fcs
117}
118
119pub fn verify_fcs(data: &[u8], fcs: u8) -> bool {
121 let mut crc = 0xFFu8;
122 for &byte in data {
123 crc = FCS_TABLE[(crc ^ byte) as usize];
124 }
125 crc = FCS_TABLE[(crc ^ fcs) as usize];
126 crc == 0xCF
127}
128
129pub const RFCOMM_MAX_FRAME_DATA: usize = 512;
135
136#[derive(Debug, Clone)]
138pub struct RfcommFrame {
139 pub address: u8,
141 pub control: u8,
143 pub length: u16,
145 #[cfg(feature = "alloc")]
147 pub data: Vec<u8>,
148 #[cfg(not(feature = "alloc"))]
149 pub data: [u8; RFCOMM_MAX_FRAME_DATA],
150 #[cfg(not(feature = "alloc"))]
151 pub data_len: usize,
152 pub fcs: u8,
154 pub credits: Option<u8>,
157}
158
159impl RfcommFrame {
160 #[cfg(feature = "alloc")]
162 pub fn new(dlci: u8, control: u8, data: &[u8]) -> Self {
163 let address = encode_address(dlci, true, true);
164 let fcs = if control == FRAME_UIH {
167 calculate_fcs(&[address, control])
168 } else {
169 calculate_fcs(&[address, control])
172 };
173 Self {
174 address,
175 control,
176 length: data.len() as u16,
177 data: Vec::from(data),
178 fcs,
179 credits: None,
180 }
181 }
182
183 #[cfg(feature = "alloc")]
185 pub fn sabm(dlci: u8) -> Self {
186 Self::new(dlci, FRAME_SABM, &[])
187 }
188
189 #[cfg(feature = "alloc")]
191 pub fn ua(dlci: u8) -> Self {
192 Self::new(dlci, FRAME_UA, &[])
193 }
194
195 #[cfg(feature = "alloc")]
197 pub fn dm(dlci: u8) -> Self {
198 Self::new(dlci, FRAME_DM, &[])
199 }
200
201 #[cfg(feature = "alloc")]
203 pub fn disc(dlci: u8) -> Self {
204 Self::new(dlci, FRAME_DISC, &[])
205 }
206
207 #[cfg(feature = "alloc")]
209 pub fn uih(dlci: u8, data: &[u8], credits: Option<u8>) -> Self {
210 let mut frame = Self::new(dlci, FRAME_UIH, data);
211 frame.credits = credits;
212 frame
213 }
214
215 pub fn dlci(&self) -> u8 {
217 decode_dlci(self.address)
218 }
219
220 pub fn is_uih(&self) -> bool {
222 self.control == FRAME_UIH
223 }
224
225 pub fn verify_fcs(&self) -> bool {
227 verify_fcs(&[self.address, self.control], self.fcs)
228 }
229
230 #[cfg(feature = "alloc")]
232 pub fn serialize(&self, buf: &mut [u8]) -> Result<usize, KernelError> {
233 let length_bytes = if self.length > 127 { 2 } else { 1 };
235 let credit_bytes = if self.credits.is_some() { 1 } else { 0 };
236 let total = 1 + 1 + length_bytes + self.data.len() + credit_bytes + 1;
237
238 if buf.len() < total {
239 return Err(KernelError::InvalidArgument {
240 name: "buffer",
241 value: "too small for RFCOMM frame",
242 });
243 }
244
245 let mut pos = 0;
246 buf[pos] = self.address;
247 pos += 1;
248 buf[pos] = self.control;
249 pos += 1;
250
251 if self.length <= 127 {
253 buf[pos] = ((self.length as u8) << 1) | 0x01; pos += 1;
255 } else {
256 buf[pos] = (self.length as u8) << 1; pos += 1;
258 buf[pos] = (self.length >> 7) as u8;
259 pos += 1;
260 }
261
262 if let Some(credits) = self.credits {
264 buf[pos] = credits;
265 pos += 1;
266 }
267
268 buf[pos..pos + self.data.len()].copy_from_slice(&self.data);
270 pos += self.data.len();
271
272 buf[pos] = self.fcs;
274 pos += 1;
275
276 Ok(pos)
277 }
278}
279
280#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
286pub struct ModemSignals {
287 pub dtr: bool,
289 pub rts: bool,
291 pub ri: bool,
293 pub dcd: bool,
295}
296
297impl ModemSignals {
298 pub fn to_byte(&self) -> u8 {
303 let mut val = 0x01u8; if self.dtr {
305 val |= 0x04;
306 }
307 if self.rts {
308 val |= 0x08;
309 }
310 if self.ri {
311 val |= 0x40;
312 }
313 if self.dcd {
314 val |= 0x80;
315 }
316 val
317 }
318
319 pub fn from_byte(val: u8) -> Self {
321 Self {
322 dtr: val & 0x04 != 0,
323 rts: val & 0x08 != 0,
324 ri: val & 0x40 != 0,
325 dcd: val & 0x80 != 0,
326 }
327 }
328}
329
330#[derive(Debug, Clone, Copy, PartialEq, Eq)]
336#[repr(u8)]
337pub enum MuxCommandType {
338 ParameterNegotiation = 0x20,
340 ModemStatusCommand = 0x38,
342 RemotePortNegotiation = 0x24,
344 Test = 0x08,
346 FlowControlOn = 0x28,
348 FlowControlOff = 0x18,
350 NonSupported = 0x04,
352}
353
354impl MuxCommandType {
355 pub fn from_u8(val: u8) -> Option<Self> {
357 match val & 0xFC {
358 0x20 => Some(Self::ParameterNegotiation),
359 0x38 => Some(Self::ModemStatusCommand),
360 0x24 => Some(Self::RemotePortNegotiation),
361 0x08 => Some(Self::Test),
362 0x28 => Some(Self::FlowControlOn),
363 0x18 => Some(Self::FlowControlOff),
364 0x04 => Some(Self::NonSupported),
365 _ => None,
366 }
367 }
368}
369
370#[derive(Debug, Clone, Copy)]
376pub struct CreditFlowControl {
377 pub tx_credits: u8,
379 pub rx_credits: u8,
381 pub initial_credits: u8,
383}
384
385impl Default for CreditFlowControl {
386 fn default() -> Self {
387 Self {
388 tx_credits: DEFAULT_INITIAL_CREDITS,
389 rx_credits: DEFAULT_INITIAL_CREDITS,
390 initial_credits: DEFAULT_INITIAL_CREDITS,
391 }
392 }
393}
394
395impl CreditFlowControl {
396 pub fn with_initial(initial: u8) -> Self {
398 Self {
399 tx_credits: initial,
400 rx_credits: initial,
401 initial_credits: initial,
402 }
403 }
404
405 pub fn grant_credits(&mut self, count: u8) {
407 self.rx_credits = self.rx_credits.saturating_add(count);
408 }
409
410 pub fn consume_credit(&mut self) -> bool {
412 if self.tx_credits > 0 {
413 self.tx_credits -= 1;
414 true
415 } else {
416 false
417 }
418 }
419
420 pub fn add_tx_credits(&mut self, count: u8) {
422 self.tx_credits = self.tx_credits.saturating_add(count);
423 }
424
425 pub fn can_send(&self) -> bool {
427 self.tx_credits > 0
428 }
429
430 pub fn needs_replenish(&self) -> bool {
432 self.rx_credits < 2
433 }
434}
435
436#[derive(Debug, Clone, Copy, PartialEq, Eq)]
442pub enum ChannelState {
443 Closed,
445 Opening,
447 Open,
449 Closing,
451}
452
453#[derive(Debug, Clone)]
459pub struct RfcommChannel {
460 pub dlci: u8,
462 pub state: ChannelState,
464 pub flow_control: CreditFlowControl,
466 pub mtu: u16,
468 pub l2cap_cid: u16,
470 pub modem_signals: ModemSignals,
472 pub priority: u8,
474}
475
476impl RfcommChannel {
477 pub fn new(dlci: u8, l2cap_cid: u16) -> Self {
479 Self {
480 dlci,
481 state: ChannelState::Closed,
482 flow_control: CreditFlowControl::default(),
483 mtu: RFCOMM_DEFAULT_MTU,
484 l2cap_cid,
485 modem_signals: ModemSignals::default(),
486 priority: 0,
487 }
488 }
489
490 pub fn is_open(&self) -> bool {
492 self.state == ChannelState::Open
493 }
494}
495
496#[cfg(feature = "alloc")]
502pub struct RfcommMultiplexer {
503 channels: BTreeMap<u8, RfcommChannel>,
505 l2cap_cid: u16,
507 session_open: bool,
509 is_initiator: bool,
511}
512
513#[cfg(feature = "alloc")]
514impl Default for RfcommMultiplexer {
515 fn default() -> Self {
516 Self::new(0)
517 }
518}
519
520#[cfg(feature = "alloc")]
521impl RfcommMultiplexer {
522 pub fn new(l2cap_cid: u16) -> Self {
524 Self {
525 channels: BTreeMap::new(),
526 l2cap_cid,
527 session_open: false,
528 is_initiator: false,
529 }
530 }
531
532 pub fn l2cap_cid(&self) -> u16 {
534 self.l2cap_cid
535 }
536
537 pub fn is_session_open(&self) -> bool {
539 self.session_open
540 }
541
542 pub fn channel_count(&self) -> usize {
544 self.channels.len()
545 }
546
547 pub fn get_channel(&self, dlci: u8) -> Option<&RfcommChannel> {
549 self.channels.get(&dlci)
550 }
551
552 pub fn start_session(&mut self) -> Result<RfcommFrame, KernelError> {
556 if self.session_open {
557 return Err(KernelError::InvalidState {
558 expected: "session closed",
559 actual: "session open",
560 });
561 }
562 self.is_initiator = true;
563 Ok(RfcommFrame::sabm(DLCI_CONTROL))
564 }
565
566 pub fn open_channel(&mut self, dlci: u8) -> Result<RfcommFrame, KernelError> {
570 if !self.session_open {
571 return Err(KernelError::InvalidState {
572 expected: "session open",
573 actual: "session closed",
574 });
575 }
576 if dlci == DLCI_CONTROL || dlci > MAX_DLCI {
577 return Err(KernelError::InvalidArgument {
578 name: "dlci",
579 value: "must be 1-30",
580 });
581 }
582 if self.channels.contains_key(&dlci) {
583 return Err(KernelError::InvalidArgument {
584 name: "dlci",
585 value: "channel already exists",
586 });
587 }
588
589 let mut channel = RfcommChannel::new(dlci, self.l2cap_cid);
590 channel.state = ChannelState::Opening;
591 self.channels.insert(dlci, channel);
592
593 Ok(RfcommFrame::sabm(dlci))
594 }
595
596 pub fn close_channel(&mut self, dlci: u8) -> Result<RfcommFrame, KernelError> {
600 let channel = self
601 .channels
602 .get_mut(&dlci)
603 .ok_or(KernelError::InvalidArgument {
604 name: "dlci",
605 value: "channel not found",
606 })?;
607
608 if channel.state != ChannelState::Open {
609 return Err(KernelError::InvalidState {
610 expected: "Open",
611 actual: "not Open",
612 });
613 }
614
615 channel.state = ChannelState::Closing;
616 Ok(RfcommFrame::disc(dlci))
617 }
618
619 pub fn send(&mut self, dlci: u8, data: &[u8]) -> Result<RfcommFrame, KernelError> {
623 let channel = self
624 .channels
625 .get_mut(&dlci)
626 .ok_or(KernelError::InvalidArgument {
627 name: "dlci",
628 value: "channel not found",
629 })?;
630
631 if channel.state != ChannelState::Open {
632 return Err(KernelError::InvalidState {
633 expected: "Open",
634 actual: "not Open",
635 });
636 }
637
638 if data.len() > channel.mtu as usize {
639 return Err(KernelError::InvalidArgument {
640 name: "data",
641 value: "exceeds channel MTU",
642 });
643 }
644
645 if !channel.flow_control.consume_credit() {
646 return Err(KernelError::ResourceExhausted {
647 resource: "RFCOMM TX credits",
648 });
649 }
650
651 let grant = if channel.flow_control.needs_replenish() {
653 let credits = channel.flow_control.initial_credits;
654 channel.flow_control.grant_credits(credits);
655 Some(credits)
656 } else {
657 None
658 };
659
660 Ok(RfcommFrame::uih(dlci, data, grant))
661 }
662
663 pub fn receive(&mut self, frame: &RfcommFrame) -> Result<Option<RfcommFrame>, KernelError> {
667 let dlci = frame.dlci();
668
669 match frame.control {
670 FRAME_SABM => self.handle_sabm(dlci),
671 FRAME_UA => self.handle_ua(dlci),
672 FRAME_DM => self.handle_dm(dlci),
673 FRAME_DISC => self.handle_disc(dlci),
674 FRAME_UIH => self.handle_uih(dlci, frame),
675 _ => {
676 Ok(Some(RfcommFrame::dm(dlci)))
678 }
679 }
680 }
681
682 fn handle_sabm(&mut self, dlci: u8) -> Result<Option<RfcommFrame>, KernelError> {
684 if dlci == DLCI_CONTROL {
685 self.session_open = true;
687 Ok(Some(RfcommFrame::ua(DLCI_CONTROL)))
688 } else if dlci > MAX_DLCI {
689 Ok(Some(RfcommFrame::dm(dlci)))
690 } else {
691 let mut channel = RfcommChannel::new(dlci, self.l2cap_cid);
693 channel.state = ChannelState::Open;
694 self.channels.insert(dlci, channel);
695 Ok(Some(RfcommFrame::ua(dlci)))
696 }
697 }
698
699 fn handle_ua(&mut self, dlci: u8) -> Result<Option<RfcommFrame>, KernelError> {
701 if dlci == DLCI_CONTROL {
702 self.session_open = true;
703 Ok(None)
704 } else if let Some(channel) = self.channels.get_mut(&dlci) {
705 match channel.state {
706 ChannelState::Opening => {
707 channel.state = ChannelState::Open;
708 }
709 ChannelState::Closing => {
710 channel.state = ChannelState::Closed;
711 }
712 _ => {}
713 }
714 Ok(None)
715 } else {
716 Ok(None)
717 }
718 }
719
720 fn handle_dm(&mut self, dlci: u8) -> Result<Option<RfcommFrame>, KernelError> {
722 if dlci == DLCI_CONTROL {
723 self.session_open = false;
724 } else if let Some(channel) = self.channels.get_mut(&dlci) {
725 channel.state = ChannelState::Closed;
726 }
727 Ok(None)
728 }
729
730 fn handle_disc(&mut self, dlci: u8) -> Result<Option<RfcommFrame>, KernelError> {
732 if dlci == DLCI_CONTROL {
733 self.session_open = false;
735 for channel in self.channels.values_mut() {
736 channel.state = ChannelState::Closed;
737 }
738 Ok(Some(RfcommFrame::ua(DLCI_CONTROL)))
739 } else if let Some(channel) = self.channels.get_mut(&dlci) {
740 channel.state = ChannelState::Closed;
741 Ok(Some(RfcommFrame::ua(dlci)))
742 } else {
743 Ok(Some(RfcommFrame::dm(dlci)))
744 }
745 }
746
747 fn handle_uih(
749 &mut self,
750 dlci: u8,
751 frame: &RfcommFrame,
752 ) -> Result<Option<RfcommFrame>, KernelError> {
753 if dlci == DLCI_CONTROL {
754 return self.process_control(frame);
756 }
757
758 let channel = self
759 .channels
760 .get_mut(&dlci)
761 .ok_or(KernelError::InvalidArgument {
762 name: "dlci",
763 value: "channel not found for UIH data",
764 })?;
765
766 if channel.state != ChannelState::Open {
767 return Err(KernelError::InvalidState {
768 expected: "Open",
769 actual: "not Open",
770 });
771 }
772
773 if let Some(credits) = frame.credits {
775 channel.flow_control.add_tx_credits(credits);
776 }
777
778 Ok(None)
782 }
783
784 fn process_control(&mut self, frame: &RfcommFrame) -> Result<Option<RfcommFrame>, KernelError> {
786 #[cfg(feature = "alloc")]
787 {
788 if frame.data.is_empty() {
789 return Ok(None);
790 }
791
792 let cmd_type_byte = frame.data[0];
793 let cmd_type = MuxCommandType::from_u8(cmd_type_byte);
794
795 match cmd_type {
796 Some(MuxCommandType::ModemStatusCommand) => {
797 if frame.data.len() >= 4 {
799 let msc_dlci = (frame.data[2] >> 2) & 0x3F;
800 let signals = ModemSignals::from_byte(frame.data[3]);
801 if let Some(channel) = self.channels.get_mut(&msc_dlci) {
802 channel.modem_signals = signals;
803 }
804 }
805 let mut resp_data = frame.data.clone();
807 if !resp_data.is_empty() {
808 resp_data[0] ^= 0x02; }
810 Ok(Some(RfcommFrame::uih(DLCI_CONTROL, &resp_data, None)))
811 }
812 Some(MuxCommandType::ParameterNegotiation) => {
813 if frame.data.len() >= 10 {
815 let pn_dlci = frame.data[2] & 0x3F;
816 let pn_mtu = u16::from_le_bytes([frame.data[6], frame.data[7]]);
817
818 if let Some(channel) = self.channels.get_mut(&pn_dlci) {
819 channel.mtu = pn_mtu.min(RFCOMM_MAX_MTU);
821 }
822 }
823 Ok(Some(RfcommFrame::uih(DLCI_CONTROL, &frame.data, None)))
825 }
826 Some(MuxCommandType::Test) => {
827 Ok(Some(RfcommFrame::uih(DLCI_CONTROL, &frame.data, None)))
829 }
830 _ => {
831 let resp = [
833 MuxCommandType::NonSupported as u8 | 0x03, 0x01, cmd_type_byte,
836 ];
837 Ok(Some(RfcommFrame::uih(DLCI_CONTROL, &resp, None)))
838 }
839 }
840 }
841 #[cfg(not(feature = "alloc"))]
842 {
843 let _ = frame;
844 Ok(None)
845 }
846 }
847}
848
849#[cfg(test)]
854mod tests {
855 #[cfg(feature = "alloc")]
856 #[allow(unused_imports)]
857 use alloc::vec;
858
859 use super::*;
860
861 #[test]
862 fn test_encode_decode_address() {
863 let addr = encode_address(5, true, true);
864 assert_eq!(decode_dlci(addr), 5);
865 assert!(decode_cr(addr));
866 }
867
868 #[test]
869 fn test_encode_address_dlci_zero() {
870 let addr = encode_address(0, false, true);
871 assert_eq!(decode_dlci(addr), 0);
872 assert!(!decode_cr(addr));
873 }
874
875 #[test]
876 fn test_fcs_calculation() {
877 let data = [0x03, 0x3F]; let fcs = calculate_fcs(&data);
879 assert!(verify_fcs(&data, fcs));
880 }
881
882 #[test]
883 fn test_fcs_verify_bad() {
884 let data = [0x03, 0x3F];
885 let fcs = calculate_fcs(&data);
886 assert!(!verify_fcs(&data, fcs.wrapping_add(1)));
887 }
888
889 #[test]
890 fn test_modem_signals_roundtrip() {
891 let signals = ModemSignals {
892 dtr: true,
893 rts: true,
894 ri: false,
895 dcd: true,
896 };
897 let byte = signals.to_byte();
898 let decoded = ModemSignals::from_byte(byte);
899 assert_eq!(decoded, signals);
900 }
901
902 #[test]
903 fn test_credit_flow_control() {
904 let mut fc = CreditFlowControl::with_initial(5);
905 assert!(fc.can_send());
906 assert_eq!(fc.tx_credits, 5);
907
908 for _ in 0..5 {
909 assert!(fc.consume_credit());
910 }
911 assert!(!fc.can_send());
912 assert!(!fc.consume_credit());
913
914 fc.add_tx_credits(3);
915 assert!(fc.can_send());
916 assert_eq!(fc.tx_credits, 3);
917 }
918
919 #[test]
920 fn test_credit_grant_and_replenish() {
921 let mut fc = CreditFlowControl::with_initial(3);
922 fc.rx_credits = 1;
923 assert!(fc.needs_replenish());
924 fc.grant_credits(3);
925 assert_eq!(fc.rx_credits, 4);
926 assert!(!fc.needs_replenish());
927 }
928
929 #[test]
930 fn test_mux_command_type_parse() {
931 assert_eq!(
932 MuxCommandType::from_u8(0x23),
933 Some(MuxCommandType::ParameterNegotiation)
934 );
935 assert_eq!(
936 MuxCommandType::from_u8(0x3B),
937 Some(MuxCommandType::ModemStatusCommand)
938 );
939 assert_eq!(MuxCommandType::from_u8(0xFF), None);
940 }
941
942 #[cfg(feature = "alloc")]
943 #[test]
944 fn test_multiplexer_session_lifecycle() {
945 let mut mux = RfcommMultiplexer::new(0x0040);
946 assert!(!mux.is_session_open());
947
948 let sabm = mux.start_session().unwrap();
950 assert_eq!(sabm.dlci(), DLCI_CONTROL);
951 assert_eq!(sabm.control, FRAME_SABM);
952
953 let ua = RfcommFrame::ua(DLCI_CONTROL);
955 mux.receive(&ua).unwrap();
956 assert!(mux.is_session_open());
957 }
958
959 #[cfg(feature = "alloc")]
960 #[test]
961 fn test_multiplexer_channel_open_close() {
962 let mut mux = RfcommMultiplexer::new(0x0040);
963 mux.session_open = true;
964
965 let sabm = mux.open_channel(5).unwrap();
967 assert_eq!(sabm.dlci(), 5);
968 assert_eq!(mux.channel_count(), 1);
969
970 let ua = RfcommFrame::ua(5);
972 mux.receive(&ua).unwrap();
973 assert_eq!(mux.get_channel(5).unwrap().state, ChannelState::Open);
974
975 let disc = mux.close_channel(5).unwrap();
977 assert_eq!(disc.control, FRAME_DISC);
978
979 let ua_close = RfcommFrame::ua(5);
981 mux.receive(&ua_close).unwrap();
982 assert_eq!(mux.get_channel(5).unwrap().state, ChannelState::Closed);
983 }
984}