1use alloc::vec::Vec;
4
5use crate::types::EtherType;
6use crate::util::read_u16be;
7
8pub const VLAN_HEADER_LEN: usize = 4;
10
11const MAX_VLAN_DEPTH: usize = 2;
13
14#[derive(Debug, Clone)]
18pub struct VlanPacket<'a> {
19 buf: &'a [u8],
20}
21
22impl<'a> VlanPacket<'a> {
23 pub fn new(buf: &'a [u8]) -> Option<Self> {
27 if buf.len() < VLAN_HEADER_LEN {
28 return None;
29 }
30 Some(Self { buf })
31 }
32
33 #[inline]
35 pub fn pcp(&self) -> u8 {
36 self.buf[0] >> 5
37 }
38
39 #[inline]
41 pub fn dei(&self) -> bool {
42 self.buf[0] & 0x10 != 0
43 }
44
45 #[inline]
47 pub fn vid(&self) -> u16 {
48 read_u16be(&self.buf[..2]) & 0x0FFF
49 }
50
51 #[inline]
53 pub fn tpid(&self) -> EtherType {
54 EtherType::Unknown(read_u16be(&self.buf[..2]))
55 }
56
57 #[inline]
59 pub fn ethertype(&self) -> EtherType {
60 EtherType::from(read_u16be(&self.buf[2..4]))
61 }
62
63 #[inline]
65 pub fn raw_ethertype(&self) -> u16 {
66 read_u16be(&self.buf[2..4])
67 }
68
69 #[inline]
71 pub fn inner(&self) -> &'a [u8] {
72 &self.buf[VLAN_HEADER_LEN..]
73 }
74}
75
76pub fn parse_vlan_chain(buf: &[u8]) -> Option<(Vec<VlanPacket<'_>>, EtherType, &[u8])> {
81 let mut tags = Vec::new();
82 let mut remaining = buf;
83
84 for _ in 0..MAX_VLAN_DEPTH {
85 let vlan = VlanPacket::new(remaining)?;
86 let inner_et = vlan.raw_ethertype();
87 tags.push(vlan);
88 remaining = &remaining[VLAN_HEADER_LEN..];
89
90 if inner_et != 0x8100 && inner_et != 0x88A8 {
92 return Some((tags, EtherType::from(inner_et), remaining));
93 }
94 }
95 if tags.is_empty() {
97 None
98 } else {
99 let last_et = tags.last().unwrap().raw_ethertype();
100 Some((tags, EtherType::from(last_et), remaining))
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn parse_single_vlan_tag() {
110 let data = [
112 0x60 | 0x10 | 0x00, 0x64, 0x08, 0x00, ];
115 let vlan = VlanPacket::new(&data).unwrap();
116 assert_eq!(vlan.pcp(), 3);
117 assert!(vlan.dei());
118 assert_eq!(vlan.vid(), 100);
119 assert_eq!(vlan.ethertype(), EtherType::Ipv4);
120 }
121
122 #[test]
123 fn parse_vlan_tag_no_dei() {
124 let data = [
125 0x20, 0x0A, 0x08, 0x06, ];
128 let vlan = VlanPacket::new(&data).unwrap();
129 assert_eq!(vlan.pcp(), 1);
130 assert!(!vlan.dei());
131 assert_eq!(vlan.vid(), 10);
132 assert_eq!(vlan.ethertype(), EtherType::Arp);
133 }
134
135 #[test]
136 fn vlan_too_short() {
137 assert!(VlanPacket::new(&[]).is_none());
138 assert!(VlanPacket::new(&[0u8; 3]).is_none());
139 }
140
141 #[test]
142 fn vlan_chain_single() {
143 let data = [
145 0x00, 0x64, 0x08, 0x00, 0x45, ];
149 let (tags, final_et, payload) = parse_vlan_chain(&data).unwrap();
150 assert_eq!(tags.len(), 1);
151 assert_eq!(tags[0].vid(), 100);
152 assert_eq!(final_et, EtherType::Ipv4);
153 assert_eq!(payload, &[0x45]);
154 }
155}