1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 use crate::reader::{unpack, Reader};
16 use crate::writer::{pack, Write, Writer};
17
18 /// 5.4.5 ISO Data Packets
19
20 /// Exchange of Isochronous Data between the Host and Controller
21 #[derive(Debug)]
22 pub struct IsoData<'a> {
23 /// Identify the connection
24 pub connection_handle: u16,
25 /// Fragmentation of the packet
26 pub sdu_fragment: IsoSduFragment,
27 /// Payload
28 pub payload: &'a [u8],
29 }
30
31 /// Fragmentation indication of the SDU
32 #[derive(Debug)]
33 pub enum IsoSduFragment {
34 /// First SDU Fragment
35 First {
36 /// SDU Header
37 hdr: IsoSduHeader,
38 /// Last SDU fragment indication
39 is_last: bool,
40 },
41 /// Continuous fragment
42 Continue {
43 /// Last SDU fragment indication
44 is_last: bool,
45 },
46 }
47
48 /// SDU Header information, when ISO Data in a first SDU fragment
49 #[derive(Debug, Default)]
50 pub struct IsoSduHeader {
51 /// Optional timestamp in microseconds
52 pub timestamp: Option<u32>,
53 /// Sequence number of the SDU
54 pub sequence_number: u16,
55 /// Total length of the SDU (sum of all fragments)
56 pub sdu_length: u16,
57 /// Only valid from Controller, indicate valid SDU data when 0
58 pub status: u16,
59 }
60
61 impl<'a> IsoData<'a> {
62 /// Read an HCI ISO Data packet
from_bytes(data: &'a [u8]) -> Option<Self>63 pub fn from_bytes(data: &'a [u8]) -> Option<Self> {
64 Self::parse(&mut Reader::new(data))
65 }
66
67 /// Output the HCI ISO Data packet
to_bytes(&self) -> Vec<u8>68 pub fn to_bytes(&self) -> Vec<u8> {
69 let mut w = Writer::new(Vec::with_capacity(12 + self.payload.len()));
70 w.write(self);
71 w.into_vec()
72 }
73
74 /// New ISO Data packet, including a complete SDU
new(connection_handle: u16, sequence_number: u16, data: &'a [u8]) -> Self75 pub fn new(connection_handle: u16, sequence_number: u16, data: &'a [u8]) -> Self {
76 Self {
77 connection_handle,
78 sdu_fragment: IsoSduFragment::First {
79 hdr: IsoSduHeader {
80 sequence_number,
81 sdu_length: data.len().try_into().unwrap(),
82 ..Default::default()
83 },
84 is_last: true,
85 },
86 payload: data,
87 }
88 }
89
parse(r: &mut Reader<'a>) -> Option<Self>90 fn parse(r: &mut Reader<'a>) -> Option<Self> {
91 let (connection_handle, pb_flag, ts_present) = unpack!(r.read_u16()?, (12, 2, 1));
92 let data_len = unpack!(r.read_u16()?, 14) as usize;
93
94 let sdu_fragment = match pb_flag {
95 0b00 => IsoSduFragment::First {
96 hdr: IsoSduHeader::parse(r, ts_present != 0)?,
97 is_last: false,
98 },
99 0b10 => IsoSduFragment::First {
100 hdr: IsoSduHeader::parse(r, ts_present != 0)?,
101 is_last: true,
102 },
103 0b01 => IsoSduFragment::Continue { is_last: false },
104 0b11 => IsoSduFragment::Continue { is_last: true },
105 _ => unreachable!(),
106 };
107 let sdu_header_len = Self::sdu_header_len(&sdu_fragment);
108 if data_len < sdu_header_len {
109 return None;
110 }
111
112 Some(Self { connection_handle, sdu_fragment, payload: r.get(data_len - sdu_header_len)? })
113 }
114
sdu_header_len(sdu_fragment: &IsoSduFragment) -> usize115 fn sdu_header_len(sdu_fragment: &IsoSduFragment) -> usize {
116 match sdu_fragment {
117 IsoSduFragment::First { ref hdr, .. } => 4 * (1 + hdr.timestamp.is_some() as usize),
118 IsoSduFragment::Continue { .. } => 0,
119 }
120 }
121 }
122
123 impl Write for IsoData<'_> {
write(&self, w: &mut Writer)124 fn write(&self, w: &mut Writer) {
125 let (pb_flag, hdr) = match self.sdu_fragment {
126 IsoSduFragment::First { ref hdr, is_last: false } => (0b00, Some(hdr)),
127 IsoSduFragment::First { ref hdr, is_last: true } => (0b10, Some(hdr)),
128 IsoSduFragment::Continue { is_last: false } => (0b01, None),
129 IsoSduFragment::Continue { is_last: true } => (0b11, None),
130 };
131
132 let ts_present = hdr.is_some() && hdr.unwrap().timestamp.is_some();
133 w.write_u16(pack!((self.connection_handle, 12), (pb_flag, 2), ((ts_present as u16), 1)));
134
135 let packet_len = Self::sdu_header_len(&self.sdu_fragment) + self.payload.len();
136 w.write_u16(pack!(u16::try_from(packet_len).unwrap(), 14));
137
138 if let Some(hdr) = hdr {
139 w.write(hdr);
140 }
141 w.put(self.payload);
142 }
143 }
144
145 impl IsoSduHeader {
parse(r: &mut Reader, ts_present: bool) -> Option<Self>146 fn parse(r: &mut Reader, ts_present: bool) -> Option<Self> {
147 let timestamp = match ts_present {
148 true => Some(r.read_u32::<4>()?),
149 false => None,
150 };
151 let sequence_number = r.read_u16()?;
152 let (sdu_length, _, status) = unpack!(r.read_u16()?, (12, 2, 2));
153 Some(Self { timestamp, sequence_number, sdu_length, status })
154 }
155 }
156
157 impl Write for IsoSduHeader {
write(&self, w: &mut Writer)158 fn write(&self, w: &mut Writer) {
159 if let Some(timestamp) = self.timestamp {
160 w.write_u32::<4>(timestamp);
161 };
162 w.write_u16(self.sequence_number);
163 w.write_u16(pack!((self.sdu_length, 12), (0, 2), (self.status, 2)));
164 }
165 }
166
167 #[test]
test_iso_data()168 fn test_iso_data() {
169 let dump = [
170 0x60, 0x60, 0x80, 0x00, 0x4d, 0xc8, 0xd0, 0x2f, 0x19, 0x03, 0x78, 0x00, 0x00, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04,
179 ];
180 let Some(pkt) = IsoData::from_bytes(&dump) else { panic!() };
181 assert_eq!(pkt.connection_handle, 0x060);
182
183 let IsoSduFragment::First { ref hdr, is_last } = pkt.sdu_fragment else { panic!() };
184 assert_eq!(hdr.timestamp, Some(802_211_917));
185 assert_eq!(hdr.sequence_number, 793);
186 assert_eq!(hdr.sdu_length, 120);
187 assert!(is_last);
188
189 assert_eq!(
190 pkt.payload,
191 &[
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04
201 ]
202 );
203 assert_eq!(pkt.to_bytes(), &dump[..]);
204 }
205