awdl_frame_parser/tlvs/data_path/data_path_state_tlv/
mod.rs

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        // I know, that I'm going to hell for this abomination.
183        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}