1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use core::{marker::PhantomData, time::Duration};

use scroll::{
    ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
    Endian, Pread, Pwrite,
};

use crate::{
    common::{capabilities::CapabilitiesInformation, Empty, TU},
    elements::{types::SSIDRepr, Elements, SSIDElement},
};

use super::{ManagementFrameBody, ToManagementFrameBody};

#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
pub struct BeaconSubtype;
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
pub struct ProbeResponseSubtype;

#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
/// This is a generic body of a beacon like frame. This includes beacons and probe responses.
pub struct BeaconLikeFrameBody<ElementContainer, Subtype> {
    pub timestamp: u64,
    pub beacon_interval: u16,
    pub capabilities_info: CapabilitiesInformation,
    pub elements: ElementContainer,
    pub _phantom: PhantomData<Subtype>
}
impl<'a, Subtype> BeaconLikeFrameBody<Elements<'a>, Subtype> {
    pub const fn length_in_bytes(&'a self) -> usize {
        8 + // Timestamp
        2 + // Beacon interval
        2 + // Capabilities information
        self.elements.bytes.len()
    }
}
impl<'a, Subtype> BeaconLikeFrameBody<Elements<'a>, Subtype> {
    pub const fn beacon_interval_as_duration(&self) -> Duration {
        Duration::from_micros(self.beacon_interval as u64 * TU.as_micros() as u64)
    }
    /// Extract the SSID from the tlvs.
    pub fn ssid(&'a self) -> Option<&'a str> {
        // SSID should be the first TLV.
        self.elements
            .get_first_element::<SSIDRepr>()
            .map(SSIDElement::take_ssid)
    }
}
impl<ElementContainer: MeasureWith<()>, Subtype> MeasureWith<()> for BeaconLikeFrameBody<ElementContainer, Subtype> {
    fn measure_with(&self, ctx: &()) -> usize {
        12 + self.elements.measure_with(ctx)
    }
}
impl<'a, Subtype: 'a> TryFromCtx<'a> for BeaconLikeFrameBody<Elements<'a>, Subtype> {
    type Error = scroll::Error;
    fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
        let mut offset = 0;

        let timestamp = from.gread_with(&mut offset, Endian::Little)?;
        let beacon_interval = from.gread_with(&mut offset, Endian::Little)?;
        let capabilities_info =
            CapabilitiesInformation::from_bits(from.gread_with(&mut offset, Endian::Little)?);
        let elements = from.gread(&mut offset)?;

        Ok((
            Self {
                timestamp,
                beacon_interval,
                capabilities_info,
                elements,
                _phantom: PhantomData
            },
            offset,
        ))
    }
}
impl<ElementContainer: TryIntoCtx<Error = scroll::Error>, Subtype> TryIntoCtx
    for BeaconLikeFrameBody<ElementContainer, Subtype>
{
    type Error = scroll::Error;
    fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
        let mut offset = 0;

        buf.gwrite_with(self.timestamp, &mut offset, Endian::Little)?;
        buf.gwrite_with(self.beacon_interval, &mut offset, Endian::Little)?;
        buf.gwrite_with(
            self.capabilities_info.into_bits(),
            &mut offset,
            Endian::Little,
        )?;
        buf.gwrite(self.elements, &mut offset)?;

        Ok(offset)
    }
}
impl<'a, ElementContainer: TryIntoCtx<Error = scroll::Error> + MeasureWith<()>>
    ToManagementFrameBody<'a, ElementContainer, Empty> for BeaconLikeFrameBody<ElementContainer, BeaconSubtype>
{
    fn to_management_frame_body(self) -> ManagementFrameBody<'a, ElementContainer, Empty> {
        ManagementFrameBody::Beacon(self)
    }
}
impl<'a, ElementContainer: TryIntoCtx<Error = scroll::Error> + MeasureWith<()>>
    ToManagementFrameBody<'a, ElementContainer, Empty> for BeaconLikeFrameBody<ElementContainer, ProbeResponseSubtype>
{
    fn to_management_frame_body(self) -> ManagementFrameBody<'a, ElementContainer, Empty> {
        ManagementFrameBody::ProbeRespone(self)
    }
}

/// The body of a beacon frame.
/// 
/// This is derived from a [generic type](BeaconLikeFrameBody) over beacon like frames, since Beacons and Probe Responses have exactly the same frame format.
pub type BeaconFrameBody<ElementContainer> = BeaconLikeFrameBody<ElementContainer, BeaconSubtype>;