Skip to main content

network_types/
vlan.rs

1use crate::{
2    eth::{EtherType, EthernetError},
3    getter_be,
4};
5use core::mem;
6
7use num_traits::FromPrimitive as _;
8
9/// VLAN tag header structure
10#[repr(C)]
11#[derive(Debug, Copy, Clone)]
12#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
13#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
14pub struct VlanHdr {
15    /// First 2 bytes containing PCP (3 bits), DEI (1 bit), and VLAN ID (12 bits)
16    pub tci: [u8; 2],
17    /// EtherType field indicating the protocol encapsulated in the payload
18    pub ether_type: u16,
19}
20
21impl VlanHdr {
22    pub const LEN: usize = mem::size_of::<VlanHdr>();
23
24    #[inline]
25    fn tci(&self) -> u16 {
26        // SAFETY: Pointer arithmetic in bounds of the struct.
27        unsafe { getter_be!(self, tci, u16) }
28    }
29
30    /// Extract the Priority Code Point (PCP) from the VLAN header
31    #[inline]
32    pub fn pcp(&self) -> u8 {
33        (self.tci() >> 13) as u8
34    }
35
36    /// Extract the Drop Eligible Indicator (DEI) from the VLAN header
37    #[inline]
38    pub fn dei(&self) -> u8 {
39        ((self.tci() >> 12) & 1) as u8
40    }
41
42    /// Extract the VLAN ID from the VLAN header
43    #[inline]
44    pub fn vid(&self) -> u16 {
45        self.tci() & 0xFFF
46    }
47
48    /// Get the EtherType value
49    #[inline]
50    pub fn ether_type(&self) -> Result<EtherType, EthernetError> {
51        EtherType::from_u16(self.ether_type).ok_or(EthernetError::InvalidEtherType(self.ether_type))
52    }
53}