1mod misc;
2
3use mac_parser::MACAddress;
4use macro_bits::{bit, bitfield};
5use scroll::{
6 ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
7 Endian, Pread, Pwrite,
8};
9
10pub use self::misc::{DataPathStats, DataPathChannel, UnicastOptions, ChannelMap};
11
12bitfield! {
13 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
14 pub struct DataPathFlags: u16 {
15 pub infra_bssid_channel_present: bool => bit!(0),
16 pub infra_address_present: bool => bit!(1),
17 pub awdl_address_present: bool => bit!(2),
18 pub rsdb_support: bool => bit!(3),
19 pub is_umi: bool => bit!(4),
20 pub dualband_support: bool => bit!(5),
21 pub airplay_sink: bool => bit!(6),
22 pub follow_channel_sequence: bool => bit!(7),
23 pub country_code_present: bool => bit!(8),
24 pub channel_map_present: bool => bit!(9),
25 pub airplay_solo_mode_support: bool => bit!(10),
26 pub umi_support: bool => bit!(11),
27 pub unicast_options_present: bool => bit!(12),
28 pub is_realtime: bool => bit!(13),
29 pub rangeable: bool => bit!(14),
30 pub extended_flags: bool => bit!(15)
31 }
32}
33bitfield! {
34 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
35 pub struct DataPathExtendedFlags: u16 {
36 pub log_trigger_id_present: bool => bit!(0),
37 pub ranging_discovery_supported: bool => bit!(1),
38 pub rlfc_present: bool => bit!(2),
39 pub is_social_channel_map_supported: bool => bit!(3),
40 pub dynamic_sdb_active: bool => bit!(4),
41 pub stats_present: bool => bit!(5),
42 pub dfs_proxy_support: bool => bit!(6),
43 pub high_efficiency_support: bool => bit!(8),
44 pub is_sidekick_hub: bool => bit!(9),
45 pub fast_discovery_active: bool => bit!(10),
46 pub wifi_six_e_support: bool => bit!(11),
47 pub ultra_low_latency_infra_support: bool => bit!(12),
48 pub pro_mode_active: bool => bit!(13),
49 pub unknown: u8 => bit!(14, 15)
50 }
51}
52
53#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
54pub struct DataPathStateTLV {
55 pub flags: DataPathFlags,
56 pub country_code: Option<[char; 2]>,
57 pub channel_map: Option<DataPathChannel>,
58 pub infra_bssid_channel: Option<(MACAddress, u16)>,
59 pub infra_address: Option<MACAddress>,
60 pub awdl_address: Option<MACAddress>,
61 pub unicast_options: Option<UnicastOptions>,
62 pub unicast_options_ext: Option<u32>,
63
64 pub extended_flags: Option<DataPathExtendedFlags>,
65 pub rlfc: Option<u32>,
66 pub log_trigger_id: Option<u16>,
67 pub stats: Option<DataPathStats>,
68}
69impl DataPathStateTLV {
70 pub const fn size_in_bytes(&self) -> usize {
71 let mut size = 2;
72 if self.country_code.is_some() {
73 size += 3;
74 }
75 if self.channel_map.is_some() {
76 size += 2;
77 }
78 if self.infra_bssid_channel.is_some() {
79 size += 8;
80 }
81 if self.infra_address.is_some() {
82 size += 6;
83 }
84 if self.awdl_address.is_some() {
85 size += 6;
86 }
87 if self.unicast_options.is_some() {
88 size += 6;
89 }
90 if self.unicast_options_ext.is_some() {
91 size += 4;
92 }
93 if self.extended_flags.is_some() {
94 size += 2;
95 }
96 if self.rlfc.is_some() {
97 size += 4;
98 }
99 if self.log_trigger_id.is_some() {
100 size += 2;
101 }
102 if self.stats.is_some() {
103 size += 12;
104 }
105 size
106 }
107}
108impl MeasureWith<()> for DataPathStateTLV {
109 fn measure_with(&self, _ctx: &()) -> usize {
110 self.size_in_bytes()
111 }
112}
113impl<'a> TryFromCtx<'a> for DataPathStateTLV {
114 type Error = scroll::Error;
115 fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
116 let mut offset = 0;
117 let flags =
118 DataPathFlags::from_bits(from.gread_with(&mut offset, Endian::Little)?);
119 let country_code = flags
120 .country_code_present
121 .then(|| {
122 let country_code = from.gread::<[u8; 2]>(&mut offset)?.map(|x| x as char);
123 offset += 1;
124 Ok::<[char; 2], scroll::Error>(country_code)
125 })
126 .transpose()?;
127 let channel_map = flags
128 .channel_map_present
129 .then(|| {
130 Ok::<DataPathChannel, scroll::Error>(DataPathChannel::from_u16(
131 from.gread_with(&mut offset, Endian::Little)?,
132 ))
133 })
134 .transpose()?;
135 let infra_bssid_channel = flags
136 .infra_bssid_channel_present
137 .then(|| {
138 Ok::<(MACAddress, u16), scroll::Error>((
139 from.gread(&mut offset)?,
140 from.gread(&mut offset)?,
141 ))
142 })
143 .transpose()?;
144 let infra_address = flags
145 .infra_address_present
146 .then(|| from.gread(&mut offset))
147 .transpose()?;
148 let awdl_address = flags
149 .awdl_address_present
150 .then(|| from.gread(&mut offset))
151 .transpose()?;
152 let (unicast_options, unicast_options_ext) = flags
153 .unicast_options_present
154 .then(|| {
155 Ok({
156 let unicast_options_length =
157 from.gread_with::<u16>(&mut offset, Endian::Little)?;
158 match unicast_options_length {
159 4 => (
160 Some(UnicastOptions::from_bits(
161 from.gread_with(&mut offset, Endian::Little)?,
162 )),
163 None,
164 ),
165 8 => (
166 Some(UnicastOptions::from_bits(
167 from.gread_with(&mut offset, Endian::Little)?,
168 )),
169 Some(from.gread_with(&mut offset, Endian::Little)?),
170 ),
171 _ => {
172 return Err(scroll::Error::BadInput {
173 size: offset,
174 msg: "Invalid unicast options length.",
175 })
176 }
177 }
178 })
179 })
180 .transpose()?
181 .unwrap_or_default();
182 let (extended_flags, log_trigger_id, rlfc, stats) = flags
184 .extended_flags
185 .then(|| {
186 Ok::<
187 (
188 Option<DataPathExtendedFlags>,
189 Option<u16>,
190 Option<u32>,
191 Option<DataPathStats>,
192 ),
193 scroll::Error,
194 >({
195 let extended_flags = DataPathExtendedFlags::from_bits(
196 from.gread_with(&mut offset, Endian::Little)?,
197 );
198 let log_trigger_id = extended_flags
199 .log_trigger_id_present
200 .then(|| from.gread_with(&mut offset, Endian::Little))
201 .transpose()?;
202 let rlfc = extended_flags
203 .rlfc_present
204 .then(|| from.gread_with(&mut offset, Endian::Little))
205 .transpose()?;
206 let stats = extended_flags
207 .stats_present
208 .then(|| from.gread(&mut offset))
209 .transpose()?;
210 (Some(extended_flags), log_trigger_id, rlfc, stats)
211 })
212 })
213 .transpose()?
214 .unwrap_or_default();
215 Ok((
216 DataPathStateTLV {
217 flags,
218 country_code,
219 channel_map,
220 infra_bssid_channel,
221 infra_address,
222 awdl_address,
223 unicast_options,
224 unicast_options_ext,
225 extended_flags,
226 log_trigger_id,
227 rlfc,
228 stats,
229 },
230 offset,
231 ))
232 }
233}
234impl TryIntoCtx for DataPathStateTLV {
235 type Error = scroll::Error;
236 fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
237 let mut offset = 0;
238
239 let log_trigger_id_present = self.log_trigger_id.is_some();
240 let rlfc_present = self.rlfc.is_some();
241 let stats_present = self.stats.is_some();
242 let extended_flags = if log_trigger_id_present || rlfc_present || stats_present {
243 let mut extended_flags = self.extended_flags.unwrap_or_default();
244
245 extended_flags.log_trigger_id_present = log_trigger_id_present;
246 extended_flags.rlfc_present = rlfc_present;
247 extended_flags.stats_present = stats_present;
248 Some(extended_flags)
249 } else {
250 self.extended_flags
251 };
252
253 buf.gwrite_with(
254 {
255 let mut flags = self.flags;
256
257 flags.country_code_present = self.country_code.is_some();
258 flags.channel_map_present = self.channel_map.is_some();
259 flags.infra_bssid_channel_present = self.infra_bssid_channel.is_some();
260 flags.infra_address_present = self.infra_address.is_some();
261 flags.awdl_address_present = self.awdl_address.is_some();
262 flags.unicast_options_present = self.unicast_options.is_some();
263 flags.extended_flags = extended_flags.is_some();
264
265 flags.into_bits()
266 },
267 &mut offset,
268 Endian::Little,
269 )?;
270
271 if let Some(country_code) = self.country_code {
272 buf.gwrite(country_code.map(|x| x as u8), &mut offset)?;
273 buf.gwrite(0u8, &mut offset)?;
274 }
275 if let Some(channel_map) = self.channel_map {
276 buf.gwrite_with(channel_map.as_u16(), &mut offset, Endian::Little)?;
277 }
278 if let Some((infra_bssid, channel)) = self.infra_bssid_channel {
279 buf.gwrite(infra_bssid, &mut offset)?;
280 buf.gwrite(channel, &mut offset)?;
281 }
282 if let Some(infra_address) = self.infra_address {
283 buf.gwrite(infra_address, &mut offset)?;
284 }
285 if let Some(awdl_address) = self.awdl_address {
286 buf.gwrite(awdl_address, &mut offset)?;
287 }
288 match (self.unicast_options, self.unicast_options_ext) {
289 (Some(unicast_options), None) => {
290 buf.gwrite(4u16, &mut offset)?;
291 buf.gwrite_with(
292 unicast_options.into_bits(),
293 &mut offset,
294 Endian::Little,
295 )?;
296 }
297 (Some(unicast_options), Some(unicast_options_ext)) => {
298 buf.gwrite(8u16, &mut offset)?;
299 buf.gwrite_with(
300 unicast_options.into_bits(),
301 &mut offset,
302 Endian::Little,
303 )?;
304 buf.gwrite_with(unicast_options_ext, &mut offset, Endian::Little)?;
305 }
306 (None, Some(unicast_options_ext)) => {
307 buf.gwrite(8u16, &mut offset)?;
308 buf.gwrite_with(0u32, &mut offset, Endian::Little)?;
309 buf.gwrite_with(unicast_options_ext, &mut offset, Endian::Little)?;
310 }
311 _ => {}
312 }
313 if let Some(extended_flags) = extended_flags {
314 buf.gwrite_with(
315 extended_flags.into_bits(),
316 &mut offset,
317 Endian::Little,
318 )?;
319 if let Some(log_trigger_id) = self.log_trigger_id {
320 buf.gwrite_with(log_trigger_id, &mut offset, Endian::Little)?;
321 }
322 if let Some(rlfc) = self.rlfc {
323 buf.gwrite_with(rlfc, &mut offset, Endian::Little)?;
324 }
325 if let Some(stats) = self.stats {
326 buf.gwrite(stats, &mut offset)?;
327 }
328 }
329
330 Ok(offset)
331 }
332}
333
334#[test]
335fn test_data_path_state_tlv() {
336 use self::misc::ChannelMap;
337 use alloc::vec;
338 use mac_parser::ZERO;
339
340 let bytes = include_bytes!("../../../../test_bins/data_path_state_tlv.bin");
341 let data_path_state = bytes.pread::<DataPathStateTLV>(0).unwrap();
342 assert_eq!(
343 data_path_state,
344 DataPathStateTLV {
345 flags: DataPathFlags {
346 infra_bssid_channel_present: true,
347 infra_address_present: true,
348 dualband_support: true,
349 country_code_present: true,
350 channel_map_present: true,
351 airplay_solo_mode_support: true,
352 umi_support: true,
353 unicast_options_present: true,
354 extended_flags: true,
355 ..Default::default()
356 },
357 country_code: Some(['D', 'E']),
358 channel_map: Some(DataPathChannel::ChannelMap(ChannelMap {
359 channel_6: true,
360 channel_44: true,
361 channel_149: false
362 })),
363 infra_bssid_channel: Some((ZERO, 0)),
364 infra_address: Some(MACAddress::new([0xbe, 0x45, 0xa1, 0xd1, 0x49, 0xb6])),
365 awdl_address: None,
366 unicast_options: Some(UnicastOptions {
367 ..Default::default()
368 },),
369 unicast_options_ext: None,
370 extended_flags: Some(DataPathExtendedFlags {
371 log_trigger_id_present: true,
372 rlfc_present: true,
373 is_social_channel_map_supported: true,
374 stats_present: true,
375 dfs_proxy_support: true,
376 ..Default::default()
377 }),
378 rlfc: Some(10836),
379 log_trigger_id: Some(0x00),
380 stats: Some(DataPathStats {
381 msec_since_activation: 183,
382 aw_seq_counter: 0,
383 pay_update_coutner: 32641,
384 }),
385 }
386 );
387 let mut buf = vec![0x00u8; data_path_state.size_in_bytes()];
388 buf.pwrite(data_path_state, 0).unwrap();
389 assert_eq!(bytes, buf.as_slice());
390}