1#![allow(dead_code)]
11
12#[cfg(feature = "alloc")]
13use alloc::collections::BTreeMap;
14#[cfg(feature = "alloc")]
15use alloc::vec::Vec;
16
17use crate::error::KernelError;
18
19pub const CID_SIGNALING: u16 = 0x0001;
25
26pub const CID_CONNECTIONLESS: u16 = 0x0002;
28
29pub const CID_ATT: u16 = 0x0004;
31
32pub const CID_LE_SIGNALING: u16 = 0x0005;
34
35pub const CID_SMP: u16 = 0x0006;
37
38pub const CID_DYNAMIC_START: u16 = 0x0040;
40
41pub const CID_DYNAMIC_END: u16 = 0xFFFF;
43
44pub const PSM_SDP: u16 = 0x0001;
50
51pub const PSM_RFCOMM: u16 = 0x0003;
53
54pub const PSM_BNEP: u16 = 0x000F;
56
57pub const PSM_HID_CONTROL: u16 = 0x0011;
59
60pub const PSM_HID_INTERRUPT: u16 = 0x0013;
62
63pub const PSM_AVCTP: u16 = 0x0017;
65
66pub const PSM_AVDTP: u16 = 0x0019;
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75#[repr(u8)]
76pub enum SignalingCode {
77 CommandReject = 0x01,
79 ConnectionReq = 0x02,
81 ConnectionResp = 0x03,
83 ConfigReq = 0x04,
85 ConfigResp = 0x05,
87 DisconnReq = 0x06,
89 DisconnResp = 0x07,
91 EchoReq = 0x08,
93 EchoResp = 0x09,
95 InfoReq = 0x0A,
97 InfoResp = 0x0B,
99}
100
101impl SignalingCode {
102 pub fn from_u8(val: u8) -> Option<Self> {
104 match val {
105 0x01 => Some(Self::CommandReject),
106 0x02 => Some(Self::ConnectionReq),
107 0x03 => Some(Self::ConnectionResp),
108 0x04 => Some(Self::ConfigReq),
109 0x05 => Some(Self::ConfigResp),
110 0x06 => Some(Self::DisconnReq),
111 0x07 => Some(Self::DisconnResp),
112 0x08 => Some(Self::EchoReq),
113 0x09 => Some(Self::EchoResp),
114 0x0A => Some(Self::InfoReq),
115 0x0B => Some(Self::InfoResp),
116 _ => None,
117 }
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127#[repr(u16)]
128pub enum ConnectionResult {
129 Success = 0x0000,
131 Pending = 0x0001,
133 PsmNotSupported = 0x0002,
135 SecurityBlock = 0x0003,
137 NoResources = 0x0004,
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143#[repr(u16)]
144pub enum ConfigResult {
145 Success = 0x0000,
147 UnacceptableParams = 0x0001,
149 Rejected = 0x0002,
151 UnknownOptions = 0x0003,
153}
154
155pub const L2CAP_MAX_PAYLOAD: usize = 65535;
161
162pub const L2CAP_DEFAULT_MTU: u16 = 672;
164
165pub const L2CAP_MIN_MTU: u16 = 48;
167
168pub const L2CAP_HEADER_SIZE: usize = 4;
170
171#[derive(Debug, Clone)]
173pub struct L2capPdu {
174 pub length: u16,
176 pub channel_id: u16,
178 #[cfg(feature = "alloc")]
180 pub payload: Vec<u8>,
181 #[cfg(not(feature = "alloc"))]
182 pub payload: [u8; L2CAP_DEFAULT_MTU as usize],
183 #[cfg(not(feature = "alloc"))]
184 pub payload_len: usize,
185}
186
187impl L2capPdu {
188 #[cfg(feature = "alloc")]
190 pub fn new(channel_id: u16, data: &[u8]) -> Self {
191 Self {
192 length: data.len() as u16,
193 channel_id,
194 payload: Vec::from(data),
195 }
196 }
197
198 #[cfg(not(feature = "alloc"))]
200 pub fn new(channel_id: u16, data: &[u8]) -> Self {
201 let copy_len = data.len().min(L2CAP_DEFAULT_MTU as usize);
202 let mut payload = [0u8; L2CAP_DEFAULT_MTU as usize];
203 payload[..copy_len].copy_from_slice(&data[..copy_len]);
204 Self {
205 length: copy_len as u16,
206 channel_id,
207 payload,
208 payload_len: copy_len,
209 }
210 }
211
212 pub fn serialize(&self, buf: &mut [u8]) -> Result<usize, KernelError> {
214 let total = L2CAP_HEADER_SIZE + self.length as usize;
215 if buf.len() < total {
216 return Err(KernelError::InvalidArgument {
217 name: "buffer",
218 value: "too small for L2CAP PDU",
219 });
220 }
221 buf[0..2].copy_from_slice(&self.length.to_le_bytes());
222 buf[2..4].copy_from_slice(&self.channel_id.to_le_bytes());
223 #[cfg(feature = "alloc")]
224 {
225 buf[4..4 + self.length as usize].copy_from_slice(&self.payload[..self.length as usize]);
226 }
227 #[cfg(not(feature = "alloc"))]
228 {
229 buf[4..4 + self.length as usize].copy_from_slice(&self.payload[..self.length as usize]);
230 }
231 Ok(total)
232 }
233
234 #[cfg(feature = "alloc")]
236 pub fn parse(buf: &[u8]) -> Result<Self, KernelError> {
237 if buf.len() < L2CAP_HEADER_SIZE {
238 return Err(KernelError::InvalidArgument {
239 name: "buffer",
240 value: "too short for L2CAP header",
241 });
242 }
243 let length = u16::from_le_bytes([buf[0], buf[1]]);
244 let channel_id = u16::from_le_bytes([buf[2], buf[3]]);
245 if buf.len() < L2CAP_HEADER_SIZE + length as usize {
246 return Err(KernelError::InvalidArgument {
247 name: "buffer",
248 value: "truncated L2CAP payload",
249 });
250 }
251 let payload = Vec::from(&buf[4..4 + length as usize]);
252 Ok(Self {
253 length,
254 channel_id,
255 payload,
256 })
257 }
258}
259
260#[derive(Debug, Clone)]
266pub struct SignalingCommand {
267 pub code: u8,
269 pub identifier: u8,
271 pub data_length: u16,
273 #[cfg(feature = "alloc")]
275 pub data: Vec<u8>,
276 #[cfg(not(feature = "alloc"))]
277 pub data: [u8; 64],
278 #[cfg(not(feature = "alloc"))]
279 pub data_len: usize,
280}
281
282impl SignalingCommand {
283 #[cfg(feature = "alloc")]
285 pub fn new(code: u8, identifier: u8, data: &[u8]) -> Self {
286 Self {
287 code,
288 identifier,
289 data_length: data.len() as u16,
290 data: Vec::from(data),
291 }
292 }
293
294 #[cfg(feature = "alloc")]
296 pub fn connection_request(identifier: u8, psm: u16, source_cid: u16) -> Self {
297 let mut data = [0u8; 4];
298 data[0..2].copy_from_slice(&psm.to_le_bytes());
299 data[2..4].copy_from_slice(&source_cid.to_le_bytes());
300 Self::new(SignalingCode::ConnectionReq as u8, identifier, &data)
301 }
302
303 #[cfg(feature = "alloc")]
305 pub fn connection_response(
306 identifier: u8,
307 dest_cid: u16,
308 source_cid: u16,
309 result: ConnectionResult,
310 status: u16,
311 ) -> Self {
312 let mut data = [0u8; 8];
313 data[0..2].copy_from_slice(&dest_cid.to_le_bytes());
314 data[2..4].copy_from_slice(&source_cid.to_le_bytes());
315 data[4..6].copy_from_slice(&(result as u16).to_le_bytes());
316 data[6..8].copy_from_slice(&status.to_le_bytes());
317 Self::new(SignalingCode::ConnectionResp as u8, identifier, &data)
318 }
319
320 #[cfg(feature = "alloc")]
322 pub fn config_request(identifier: u8, dest_cid: u16, mtu: u16) -> Self {
323 let mut data = [0u8; 8];
325 data[0..2].copy_from_slice(&dest_cid.to_le_bytes());
326 data[2..4].copy_from_slice(&0u16.to_le_bytes()); data[4] = 0x01; data[5] = 0x02; data[6..8].copy_from_slice(&mtu.to_le_bytes());
330 Self::new(SignalingCode::ConfigReq as u8, identifier, &data)
331 }
332
333 #[cfg(feature = "alloc")]
335 pub fn disconnection_request(identifier: u8, dest_cid: u16, source_cid: u16) -> Self {
336 let mut data = [0u8; 4];
337 data[0..2].copy_from_slice(&dest_cid.to_le_bytes());
338 data[2..4].copy_from_slice(&source_cid.to_le_bytes());
339 Self::new(SignalingCode::DisconnReq as u8, identifier, &data)
340 }
341
342 pub fn serialize(&self, buf: &mut [u8]) -> Result<usize, KernelError> {
344 let total = 4 + self.data_length as usize;
345 if buf.len() < total {
346 return Err(KernelError::InvalidArgument {
347 name: "buffer",
348 value: "too small for signaling command",
349 });
350 }
351 buf[0] = self.code;
352 buf[1] = self.identifier;
353 buf[2..4].copy_from_slice(&self.data_length.to_le_bytes());
354 #[cfg(feature = "alloc")]
355 {
356 buf[4..4 + self.data_length as usize]
357 .copy_from_slice(&self.data[..self.data_length as usize]);
358 }
359 #[cfg(not(feature = "alloc"))]
360 {
361 buf[4..4 + self.data_length as usize]
362 .copy_from_slice(&self.data[..self.data_length as usize]);
363 }
364 Ok(total)
365 }
366
367 #[cfg(feature = "alloc")]
369 pub fn parse(buf: &[u8]) -> Result<Self, KernelError> {
370 if buf.len() < 4 {
371 return Err(KernelError::InvalidArgument {
372 name: "buffer",
373 value: "too short for signaling command header",
374 });
375 }
376 let code = buf[0];
377 let identifier = buf[1];
378 let data_length = u16::from_le_bytes([buf[2], buf[3]]);
379 if buf.len() < 4 + data_length as usize {
380 return Err(KernelError::InvalidArgument {
381 name: "buffer",
382 value: "truncated signaling command data",
383 });
384 }
385 let data = Vec::from(&buf[4..4 + data_length as usize]);
386 Ok(Self {
387 code,
388 identifier,
389 data_length,
390 data,
391 })
392 }
393}
394
395#[derive(Debug, Clone, Copy, PartialEq, Eq)]
401pub enum ChannelState {
402 Closed,
404 WaitConnect,
406 WaitConnectRsp,
408 Config,
410 Open,
412 WaitDisconnect,
414}
415
416#[derive(Debug, Clone)]
422pub struct L2capChannel {
423 pub local_cid: u16,
425 pub remote_cid: u16,
427 pub state: ChannelState,
429 pub psm: u16,
431 pub mtu: u16,
433 pub remote_mtu: u16,
435 pub flush_timeout: u16,
437 pub local_config_done: bool,
439 pub remote_config_done: bool,
441 pub hci_handle: u16,
443 #[cfg(feature = "alloc")]
445 pub reassembly_buf: Vec<u8>,
446 pub reassembly_expected: u16,
448}
449
450impl L2capChannel {
451 pub fn new(local_cid: u16, psm: u16, hci_handle: u16) -> Self {
453 Self {
454 local_cid,
455 remote_cid: 0,
456 state: ChannelState::Closed,
457 psm,
458 mtu: L2CAP_DEFAULT_MTU,
459 remote_mtu: L2CAP_DEFAULT_MTU,
460 flush_timeout: 0xFFFF,
461 local_config_done: false,
462 remote_config_done: false,
463 hci_handle,
464 #[cfg(feature = "alloc")]
465 reassembly_buf: Vec::new(),
466 reassembly_expected: 0,
467 }
468 }
469
470 pub fn is_open(&self) -> bool {
472 self.state == ChannelState::Open
473 }
474
475 pub fn is_configured(&self) -> bool {
477 self.local_config_done && self.remote_config_done
478 }
479}
480
481#[derive(Debug, Clone)]
487pub struct SarFragment {
488 pub is_first: bool,
490 #[cfg(feature = "alloc")]
492 pub data: Vec<u8>,
493 #[cfg(not(feature = "alloc"))]
494 pub data: [u8; L2CAP_DEFAULT_MTU as usize],
495 #[cfg(not(feature = "alloc"))]
496 pub data_len: usize,
497}
498
499#[cfg(feature = "alloc")]
504pub fn segment_data(channel_id: u16, data: &[u8], mtu: u16) -> Vec<SarFragment> {
505 let mut fragments = Vec::new();
506 let effective_mtu = mtu as usize;
507
508 if data.is_empty() {
509 let mut hdr = [0u8; L2CAP_HEADER_SIZE];
511 hdr[0..2].copy_from_slice(&0u16.to_le_bytes());
512 hdr[2..4].copy_from_slice(&channel_id.to_le_bytes());
513 fragments.push(SarFragment {
514 is_first: true,
515 data: Vec::from(&hdr[..]),
516 });
517 return fragments;
518 }
519
520 let total_length = data.len() as u16;
522 let first_data_len = effective_mtu
523 .saturating_sub(L2CAP_HEADER_SIZE)
524 .min(data.len());
525 let mut first = Vec::with_capacity(L2CAP_HEADER_SIZE + first_data_len);
526 first.extend_from_slice(&total_length.to_le_bytes());
527 first.extend_from_slice(&channel_id.to_le_bytes());
528 first.extend_from_slice(&data[..first_data_len]);
529 fragments.push(SarFragment {
530 is_first: true,
531 data: first,
532 });
533
534 let mut offset = first_data_len;
536 while offset < data.len() {
537 let chunk_len = effective_mtu.min(data.len() - offset);
538 fragments.push(SarFragment {
539 is_first: false,
540 data: Vec::from(&data[offset..offset + chunk_len]),
541 });
542 offset += chunk_len;
543 }
544
545 fragments
546}
547
548#[cfg(feature = "alloc")]
550pub fn reassemble_fragments(fragments: &[SarFragment]) -> Result<Vec<u8>, KernelError> {
551 if fragments.is_empty() {
552 return Err(KernelError::InvalidArgument {
553 name: "fragments",
554 value: "empty fragment list",
555 });
556 }
557 if !fragments[0].is_first {
558 return Err(KernelError::InvalidArgument {
559 name: "fragments",
560 value: "first fragment not marked as first",
561 });
562 }
563
564 let first = &fragments[0].data;
566 if first.len() < L2CAP_HEADER_SIZE {
567 return Err(KernelError::InvalidArgument {
568 name: "first_fragment",
569 value: "too short for L2CAP header",
570 });
571 }
572 let total_length = u16::from_le_bytes([first[0], first[1]]) as usize;
573
574 let mut result = Vec::with_capacity(total_length);
575 result.extend_from_slice(&first[L2CAP_HEADER_SIZE..]);
577
578 for frag in &fragments[1..] {
580 result.extend_from_slice(&frag.data);
581 }
582
583 if result.len() < total_length {
584 return Err(KernelError::InvalidArgument {
585 name: "fragments",
586 value: "insufficient data for declared length",
587 });
588 }
589
590 result.truncate(total_length);
591 Ok(result)
592}
593
594#[cfg(feature = "alloc")]
600pub struct L2capManager {
601 channels: BTreeMap<u16, L2capChannel>,
603 next_cid: u16,
605 next_identifier: u8,
607}
608
609#[cfg(feature = "alloc")]
610impl Default for L2capManager {
611 fn default() -> Self {
612 Self::new()
613 }
614}
615
616#[cfg(feature = "alloc")]
617impl L2capManager {
618 pub fn new() -> Self {
620 Self {
621 channels: BTreeMap::new(),
622 next_cid: CID_DYNAMIC_START,
623 next_identifier: 1,
624 }
625 }
626
627 fn alloc_cid(&mut self) -> Result<u16, KernelError> {
629 let start = self.next_cid;
630 loop {
631 let cid = self.next_cid;
632 self.next_cid = if cid == CID_DYNAMIC_END {
633 CID_DYNAMIC_START
634 } else {
635 cid + 1
636 };
637 if !self.channels.contains_key(&cid) {
638 return Ok(cid);
639 }
640 if self.next_cid == start {
642 return Err(KernelError::ResourceExhausted {
643 resource: "L2CAP CIDs",
644 });
645 }
646 }
647 }
648
649 fn alloc_identifier(&mut self) -> u8 {
651 let id = self.next_identifier;
652 self.next_identifier = self.next_identifier.wrapping_add(1);
653 if self.next_identifier == 0 {
654 self.next_identifier = 1; }
656 id
657 }
658
659 pub fn channel_count(&self) -> usize {
661 self.channels.len()
662 }
663
664 pub fn get_channel(&self, local_cid: u16) -> Option<&L2capChannel> {
666 self.channels.get(&local_cid)
667 }
668
669 pub fn get_channel_mut(&mut self, local_cid: u16) -> Option<&mut L2capChannel> {
671 self.channels.get_mut(&local_cid)
672 }
673
674 pub fn open_channel(
678 &mut self,
679 psm: u16,
680 hci_handle: u16,
681 ) -> Result<(u16, SignalingCommand), KernelError> {
682 let local_cid = self.alloc_cid()?;
683 let mut channel = L2capChannel::new(local_cid, psm, hci_handle);
684 channel.state = ChannelState::WaitConnectRsp;
685
686 let identifier = self.alloc_identifier();
687 let cmd = SignalingCommand::connection_request(identifier, psm, local_cid);
688
689 self.channels.insert(local_cid, channel);
690 Ok((local_cid, cmd))
691 }
692
693 pub fn close_channel(&mut self, local_cid: u16) -> Result<SignalingCommand, KernelError> {
697 let channel = self
698 .channels
699 .get_mut(&local_cid)
700 .ok_or(KernelError::InvalidArgument {
701 name: "local_cid",
702 value: "channel not found",
703 })?;
704
705 if channel.state == ChannelState::Closed {
706 return Err(KernelError::InvalidState {
707 expected: "not Closed",
708 actual: "Closed",
709 });
710 }
711
712 let remote_cid = channel.remote_cid;
713 channel.state = ChannelState::WaitDisconnect;
714 let identifier = self.alloc_identifier();
715
716 Ok(SignalingCommand::disconnection_request(
717 identifier, remote_cid, local_cid,
718 ))
719 }
720
721 pub fn remove_channel(&mut self, local_cid: u16) -> Option<L2capChannel> {
723 self.channels.remove(&local_cid)
724 }
725
726 pub fn send_data(&self, local_cid: u16, data: &[u8]) -> Result<Vec<SarFragment>, KernelError> {
730 let channel = self
731 .channels
732 .get(&local_cid)
733 .ok_or(KernelError::InvalidArgument {
734 name: "local_cid",
735 value: "channel not found",
736 })?;
737
738 if channel.state != ChannelState::Open {
739 return Err(KernelError::InvalidState {
740 expected: "Open",
741 actual: "not Open",
742 });
743 }
744
745 Ok(segment_data(channel.remote_cid, data, channel.remote_mtu))
747 }
748
749 pub fn receive_data(
754 &mut self,
755 local_cid: u16,
756 fragment: &[u8],
757 is_first: bool,
758 ) -> Result<Option<Vec<u8>>, KernelError> {
759 let channel = self
760 .channels
761 .get_mut(&local_cid)
762 .ok_or(KernelError::InvalidArgument {
763 name: "local_cid",
764 value: "channel not found",
765 })?;
766
767 if channel.state != ChannelState::Open {
768 return Err(KernelError::InvalidState {
769 expected: "Open",
770 actual: "not Open",
771 });
772 }
773
774 if is_first {
775 if fragment.len() < L2CAP_HEADER_SIZE {
777 return Err(KernelError::InvalidArgument {
778 name: "fragment",
779 value: "first fragment too short for L2CAP header",
780 });
781 }
782 let total_length = u16::from_le_bytes([fragment[0], fragment[1]]);
783 channel.reassembly_expected = total_length;
784 channel.reassembly_buf.clear();
785 channel
786 .reassembly_buf
787 .extend_from_slice(&fragment[L2CAP_HEADER_SIZE..]);
788 } else {
789 channel.reassembly_buf.extend_from_slice(fragment);
791 }
792
793 if channel.reassembly_buf.len() >= channel.reassembly_expected as usize {
795 let mut result = Vec::new();
796 core::mem::swap(&mut result, &mut channel.reassembly_buf);
797 result.truncate(channel.reassembly_expected as usize);
798 channel.reassembly_expected = 0;
799 Ok(Some(result))
800 } else {
801 Ok(None)
802 }
803 }
804
805 pub fn process_signaling(
809 &mut self,
810 cmd: &SignalingCommand,
811 ) -> Result<Option<SignalingCommand>, KernelError> {
812 let code = SignalingCode::from_u8(cmd.code);
813
814 match code {
815 Some(SignalingCode::ConnectionReq) => self.handle_connection_request(cmd),
816 Some(SignalingCode::ConnectionResp) => self.handle_connection_response(cmd),
817 Some(SignalingCode::ConfigReq) => self.handle_config_request(cmd),
818 Some(SignalingCode::ConfigResp) => self.handle_config_response(cmd),
819 Some(SignalingCode::DisconnReq) => self.handle_disconnection_request(cmd),
820 Some(SignalingCode::DisconnResp) => self.handle_disconnection_response(cmd),
821 Some(SignalingCode::EchoReq) => {
822 Ok(Some(SignalingCommand::new(
824 SignalingCode::EchoResp as u8,
825 cmd.identifier,
826 &cmd.data,
827 )))
828 }
829 Some(SignalingCode::InfoReq) => {
830 let mut data = [0u8; 4];
832 if cmd.data.len() >= 2 {
834 data[0..2].copy_from_slice(&cmd.data[0..2]);
835 }
836 data[2..4].copy_from_slice(&0x0001u16.to_le_bytes()); Ok(Some(SignalingCommand::new(
838 SignalingCode::InfoResp as u8,
839 cmd.identifier,
840 &data,
841 )))
842 }
843 _ => {
844 let mut data = [0u8; 2];
846 data[0..2].copy_from_slice(&0x0000u16.to_le_bytes()); Ok(Some(SignalingCommand::new(
848 SignalingCode::CommandReject as u8,
849 cmd.identifier,
850 &data,
851 )))
852 }
853 }
854 }
855
856 fn handle_connection_request(
858 &mut self,
859 cmd: &SignalingCommand,
860 ) -> Result<Option<SignalingCommand>, KernelError> {
861 if cmd.data.len() < 4 {
862 return Err(KernelError::InvalidArgument {
863 name: "connection_request",
864 value: "data too short",
865 });
866 }
867 let psm = u16::from_le_bytes([cmd.data[0], cmd.data[1]]);
868 let source_cid = u16::from_le_bytes([cmd.data[2], cmd.data[3]]);
869
870 match self.alloc_cid() {
872 Ok(local_cid) => {
873 let mut channel = L2capChannel::new(local_cid, psm, 0);
874 channel.remote_cid = source_cid;
875 channel.state = ChannelState::Config;
876 self.channels.insert(local_cid, channel);
877
878 Ok(Some(SignalingCommand::connection_response(
879 cmd.identifier,
880 local_cid,
881 source_cid,
882 ConnectionResult::Success,
883 0,
884 )))
885 }
886 Err(_) => Ok(Some(SignalingCommand::connection_response(
887 cmd.identifier,
888 0,
889 source_cid,
890 ConnectionResult::NoResources,
891 0,
892 ))),
893 }
894 }
895
896 fn handle_connection_response(
898 &mut self,
899 cmd: &SignalingCommand,
900 ) -> Result<Option<SignalingCommand>, KernelError> {
901 if cmd.data.len() < 8 {
902 return Err(KernelError::InvalidArgument {
903 name: "connection_response",
904 value: "data too short",
905 });
906 }
907 let dest_cid = u16::from_le_bytes([cmd.data[0], cmd.data[1]]);
908 let source_cid = u16::from_le_bytes([cmd.data[2], cmd.data[3]]);
909 let result = u16::from_le_bytes([cmd.data[4], cmd.data[5]]);
910
911 let channel_mtu = if let Some(channel) = self.channels.get_mut(&source_cid) {
913 if result == ConnectionResult::Success as u16 {
914 channel.remote_cid = dest_cid;
915 channel.state = ChannelState::Config;
916 Some(channel.mtu)
917 } else {
918 channel.state = ChannelState::Closed;
919 None
920 }
921 } else {
922 None
923 };
924
925 if let Some(mtu) = channel_mtu {
926 let id = self.alloc_identifier();
927 return Ok(Some(SignalingCommand::config_request(id, dest_cid, mtu)));
928 }
929 Ok(None)
930 }
931
932 fn handle_config_request(
934 &mut self,
935 cmd: &SignalingCommand,
936 ) -> Result<Option<SignalingCommand>, KernelError> {
937 if cmd.data.len() < 4 {
938 return Err(KernelError::InvalidArgument {
939 name: "config_request",
940 value: "data too short",
941 });
942 }
943 let dest_cid = u16::from_le_bytes([cmd.data[0], cmd.data[1]]);
944 let mut remote_mtu = L2CAP_DEFAULT_MTU;
948 if cmd.data.len() >= 8 && cmd.data[4] == 0x01 && cmd.data[5] == 0x02 {
949 remote_mtu = u16::from_le_bytes([cmd.data[6], cmd.data[7]]);
950 if remote_mtu < L2CAP_MIN_MTU {
951 remote_mtu = L2CAP_MIN_MTU;
952 }
953 }
954
955 if let Some(channel) = self.channels.get_mut(&dest_cid) {
956 channel.remote_mtu = remote_mtu;
957 channel.remote_config_done = true;
958
959 if channel.local_config_done && channel.remote_config_done {
961 channel.state = ChannelState::Open;
962 }
963
964 let mut resp_data = [0u8; 6];
966 resp_data[0..2].copy_from_slice(&channel.remote_cid.to_le_bytes());
967 resp_data[2..4].copy_from_slice(&0u16.to_le_bytes()); resp_data[4..6].copy_from_slice(&(ConfigResult::Success as u16).to_le_bytes());
969 Ok(Some(SignalingCommand::new(
970 SignalingCode::ConfigResp as u8,
971 cmd.identifier,
972 &resp_data,
973 )))
974 } else {
975 Ok(None)
976 }
977 }
978
979 fn handle_config_response(
981 &mut self,
982 cmd: &SignalingCommand,
983 ) -> Result<Option<SignalingCommand>, KernelError> {
984 if cmd.data.len() < 6 {
985 return Err(KernelError::InvalidArgument {
986 name: "config_response",
987 value: "data too short",
988 });
989 }
990 let source_cid = u16::from_le_bytes([cmd.data[0], cmd.data[1]]);
991 let result = u16::from_le_bytes([cmd.data[4], cmd.data[5]]);
993
994 for channel in self.channels.values_mut() {
996 if channel.remote_cid == source_cid {
997 if result == ConfigResult::Success as u16 {
998 channel.local_config_done = true;
999 if channel.local_config_done && channel.remote_config_done {
1000 channel.state = ChannelState::Open;
1001 }
1002 }
1003 break;
1004 }
1005 }
1006 Ok(None)
1007 }
1008
1009 fn handle_disconnection_request(
1011 &mut self,
1012 cmd: &SignalingCommand,
1013 ) -> Result<Option<SignalingCommand>, KernelError> {
1014 if cmd.data.len() < 4 {
1015 return Err(KernelError::InvalidArgument {
1016 name: "disconnection_request",
1017 value: "data too short",
1018 });
1019 }
1020 let dest_cid = u16::from_le_bytes([cmd.data[0], cmd.data[1]]);
1021 let source_cid = u16::from_le_bytes([cmd.data[2], cmd.data[3]]);
1022
1023 if let Some(channel) = self.channels.get_mut(&dest_cid) {
1024 channel.state = ChannelState::Closed;
1025 }
1026
1027 let mut resp_data = [0u8; 4];
1029 resp_data[0..2].copy_from_slice(&dest_cid.to_le_bytes());
1030 resp_data[2..4].copy_from_slice(&source_cid.to_le_bytes());
1031 Ok(Some(SignalingCommand::new(
1032 SignalingCode::DisconnResp as u8,
1033 cmd.identifier,
1034 &resp_data,
1035 )))
1036 }
1037
1038 fn handle_disconnection_response(
1040 &mut self,
1041 cmd: &SignalingCommand,
1042 ) -> Result<Option<SignalingCommand>, KernelError> {
1043 if cmd.data.len() < 4 {
1044 return Err(KernelError::InvalidArgument {
1045 name: "disconnection_response",
1046 value: "data too short",
1047 });
1048 }
1049 let dest_cid = u16::from_le_bytes([cmd.data[0], cmd.data[1]]);
1050
1051 if let Some(channel) = self.channels.get_mut(&dest_cid) {
1052 channel.state = ChannelState::Closed;
1053 }
1054 Ok(None)
1055 }
1056
1057 pub fn configure_channel(
1059 &mut self,
1060 local_cid: u16,
1061 mtu: u16,
1062 flush_timeout: u16,
1063 ) -> Result<(), KernelError> {
1064 let channel = self
1065 .channels
1066 .get_mut(&local_cid)
1067 .ok_or(KernelError::InvalidArgument {
1068 name: "local_cid",
1069 value: "channel not found",
1070 })?;
1071
1072 if mtu < L2CAP_MIN_MTU {
1073 return Err(KernelError::InvalidArgument {
1074 name: "mtu",
1075 value: "below minimum L2CAP MTU (48)",
1076 });
1077 }
1078
1079 channel.mtu = mtu;
1080 channel.flush_timeout = flush_timeout;
1081 Ok(())
1082 }
1083}
1084
1085#[cfg(test)]
1090mod tests {
1091 #[cfg(feature = "alloc")]
1092 #[allow(unused_imports)]
1093 use alloc::vec;
1094
1095 use super::*;
1096
1097 #[test]
1098 fn test_signaling_code_roundtrip() {
1099 assert_eq!(
1100 SignalingCode::from_u8(0x02),
1101 Some(SignalingCode::ConnectionReq)
1102 );
1103 assert_eq!(
1104 SignalingCode::from_u8(0x03),
1105 Some(SignalingCode::ConnectionResp)
1106 );
1107 assert_eq!(SignalingCode::from_u8(0x04), Some(SignalingCode::ConfigReq));
1108 assert_eq!(
1109 SignalingCode::from_u8(0x05),
1110 Some(SignalingCode::ConfigResp)
1111 );
1112 assert_eq!(
1113 SignalingCode::from_u8(0x06),
1114 Some(SignalingCode::DisconnReq)
1115 );
1116 assert_eq!(
1117 SignalingCode::from_u8(0x07),
1118 Some(SignalingCode::DisconnResp)
1119 );
1120 assert_eq!(SignalingCode::from_u8(0x0A), Some(SignalingCode::InfoReq));
1121 assert_eq!(SignalingCode::from_u8(0x0B), Some(SignalingCode::InfoResp));
1122 assert_eq!(SignalingCode::from_u8(0xFF), None);
1123 }
1124
1125 #[test]
1126 fn test_channel_state_defaults() {
1127 let ch = L2capChannel::new(0x0040, PSM_RFCOMM, 1);
1128 assert_eq!(ch.state, ChannelState::Closed);
1129 assert_eq!(ch.mtu, L2CAP_DEFAULT_MTU);
1130 assert_eq!(ch.flush_timeout, 0xFFFF);
1131 assert!(!ch.is_open());
1132 assert!(!ch.is_configured());
1133 }
1134
1135 #[test]
1136 fn test_pdu_serialize_parse() {
1137 let data = [0x01, 0x02, 0x03, 0x04];
1138 let pdu = L2capPdu::new(0x0040, &data);
1139 assert_eq!(pdu.length, 4);
1140 assert_eq!(pdu.channel_id, 0x0040);
1141
1142 let mut buf = [0u8; 32];
1143 let written = pdu.serialize(&mut buf).unwrap();
1144 assert_eq!(written, 8); assert_eq!(u16::from_le_bytes([buf[0], buf[1]]), 4);
1146 assert_eq!(u16::from_le_bytes([buf[2], buf[3]]), 0x0040);
1147 }
1148
1149 #[cfg(feature = "alloc")]
1150 #[test]
1151 fn test_pdu_parse_roundtrip() {
1152 let data = [0xAA, 0xBB, 0xCC];
1153 let pdu = L2capPdu::new(0x0041, &data);
1154 let mut buf = [0u8; 32];
1155 let written = pdu.serialize(&mut buf).unwrap();
1156 let parsed = L2capPdu::parse(&buf[..written]).unwrap();
1157 assert_eq!(parsed.length, 3);
1158 assert_eq!(parsed.channel_id, 0x0041);
1159 assert_eq!(parsed.payload, data);
1160 }
1161
1162 #[test]
1163 fn test_pdu_serialize_buffer_too_small() {
1164 let data = [0u8; 10];
1165 let pdu = L2capPdu::new(0x0040, &data);
1166 let mut buf = [0u8; 8]; assert!(pdu.serialize(&mut buf).is_err());
1168 }
1169
1170 #[cfg(feature = "alloc")]
1171 #[test]
1172 fn test_signaling_command_serialize_parse() {
1173 let cmd = SignalingCommand::connection_request(1, PSM_RFCOMM, 0x0040);
1174 let mut buf = [0u8; 32];
1175 let written = cmd.serialize(&mut buf).unwrap();
1176 assert_eq!(written, 8); let parsed = SignalingCommand::parse(&buf[..written]).unwrap();
1179 assert_eq!(parsed.code, SignalingCode::ConnectionReq as u8);
1180 assert_eq!(parsed.identifier, 1);
1181 assert_eq!(parsed.data_length, 4);
1182 }
1183
1184 #[cfg(feature = "alloc")]
1185 #[test]
1186 fn test_segment_small_data() {
1187 let data = [0x01, 0x02, 0x03];
1188 let fragments = segment_data(0x0040, &data, 672);
1189 assert_eq!(fragments.len(), 1);
1190 assert!(fragments[0].is_first);
1191 assert_eq!(fragments[0].data.len(), 7);
1193 }
1194
1195 #[cfg(feature = "alloc")]
1196 #[test]
1197 fn test_segment_large_data() {
1198 let mtu = 10u16;
1200 let data = [0xAA; 20];
1201 let fragments = segment_data(0x0040, &data, mtu);
1202 assert!(fragments.len() > 1);
1203 assert!(fragments[0].is_first);
1204 for frag in &fragments[1..] {
1205 assert!(!frag.is_first);
1206 }
1207 }
1208
1209 #[cfg(feature = "alloc")]
1210 #[test]
1211 fn test_segment_empty_data() {
1212 let fragments = segment_data(0x0040, &[], 672);
1213 assert_eq!(fragments.len(), 1);
1214 assert!(fragments[0].is_first);
1215 assert_eq!(fragments[0].data.len(), 4); }
1217
1218 #[cfg(feature = "alloc")]
1219 #[test]
1220 fn test_reassemble_single_fragment() {
1221 let data = [0x01, 0x02, 0x03];
1222 let fragments = segment_data(0x0040, &data, 672);
1223 let result = reassemble_fragments(&fragments).unwrap();
1224 assert_eq!(result, data);
1225 }
1226
1227 #[cfg(feature = "alloc")]
1228 #[test]
1229 fn test_reassemble_multiple_fragments() {
1230 let data = [0xAA; 20];
1231 let fragments = segment_data(0x0040, &data, 10);
1232 let result = reassemble_fragments(&fragments).unwrap();
1233 assert_eq!(result, data);
1234 }
1235
1236 #[cfg(feature = "alloc")]
1237 #[test]
1238 fn test_manager_open_close_channel() {
1239 let mut mgr = L2capManager::new();
1240 let (cid, cmd) = mgr.open_channel(PSM_RFCOMM, 1).unwrap();
1241 assert!(cid >= CID_DYNAMIC_START);
1242 assert_eq!(cmd.code, SignalingCode::ConnectionReq as u8);
1243 assert_eq!(mgr.channel_count(), 1);
1244
1245 let channel = mgr.get_channel(cid).unwrap();
1246 assert_eq!(channel.state, ChannelState::WaitConnectRsp);
1247 assert_eq!(channel.psm, PSM_RFCOMM);
1248
1249 let disc_cmd = mgr.close_channel(cid).unwrap();
1251 assert_eq!(disc_cmd.code, SignalingCode::DisconnReq as u8);
1252 }
1253
1254 #[cfg(feature = "alloc")]
1255 #[test]
1256 fn test_manager_configure_channel() {
1257 let mut mgr = L2capManager::new();
1258 let (cid, _) = mgr.open_channel(PSM_SDP, 1).unwrap();
1259
1260 mgr.configure_channel(cid, 1024, 5000).unwrap();
1261 let ch = mgr.get_channel(cid).unwrap();
1262 assert_eq!(ch.mtu, 1024);
1263 assert_eq!(ch.flush_timeout, 5000);
1264 }
1265
1266 #[cfg(feature = "alloc")]
1267 #[test]
1268 fn test_manager_configure_mtu_too_small() {
1269 let mut mgr = L2capManager::new();
1270 let (cid, _) = mgr.open_channel(PSM_SDP, 1).unwrap();
1271 assert!(mgr.configure_channel(cid, 10, 0xFFFF).is_err());
1272 }
1273
1274 #[cfg(feature = "alloc")]
1275 #[test]
1276 fn test_manager_process_echo_request() {
1277 let mut mgr = L2capManager::new();
1278 let echo = SignalingCommand::new(SignalingCode::EchoReq as u8, 5, &[0x01, 0x02]);
1279 let resp = mgr.process_signaling(&echo).unwrap().unwrap();
1280 assert_eq!(resp.code, SignalingCode::EchoResp as u8);
1281 assert_eq!(resp.identifier, 5);
1282 assert_eq!(resp.data, echo.data);
1283 }
1284}