1use alloc::vec::Vec;
4
5use crate::types::EtherType;
6use crate::util::read_u16be;
7
8pub const VLAN_HEADER_LEN: usize = 4;
10
11pub const 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 crate::parser_new!(VLAN_HEADER_LEN);
24
25 #[inline]
27 pub fn as_bytes(&self) -> &'a [u8] { self.buf }
28
29 #[inline]
31 pub fn pcp(&self) -> u8 {
32 self.buf[0] >> 5
33 }
34
35 #[inline]
37 pub fn dei(&self) -> bool {
38 self.buf[0] & 0x10 != 0
39 }
40
41 #[inline]
43 pub fn vid(&self) -> u16 {
44 read_u16be(&self.buf[..2]) & 0x0FFF
45 }
46
47 #[inline]
49 pub fn tpid(&self) -> EtherType {
50 EtherType::Unknown(read_u16be(&self.buf[..2]))
51 }
52
53 #[inline]
55 pub fn ethertype(&self) -> EtherType {
56 EtherType::from(read_u16be(&self.buf[2..4]))
57 }
58
59 #[inline]
61 pub fn raw_ethertype(&self) -> u16 {
62 read_u16be(&self.buf[2..4])
63 }
64
65 #[inline]
67 pub fn inner(&self) -> &'a [u8] {
68 &self.buf[VLAN_HEADER_LEN..]
69 }
70}
71
72pub fn parse_vlan_chain(buf: &[u8]) -> Option<(Vec<VlanPacket<'_>>, EtherType, &[u8])> {
77 let mut tags = Vec::new();
78 let mut remaining = buf;
79
80 for _ in 0..MAX_VLAN_DEPTH {
81 let vlan = VlanPacket::new(remaining)?;
82 let inner_et = vlan.raw_ethertype();
83 tags.push(vlan);
84 remaining = &remaining[VLAN_HEADER_LEN..];
85
86 if inner_et != 0x8100 && inner_et != 0x88A8 {
88 return Some((tags, EtherType::from(inner_et), remaining));
89 }
90 }
91 if tags.is_empty() {
93 None
94 } else {
95 let last_et = tags.last().unwrap().raw_ethertype();
96 Some((tags, EtherType::from(last_et), remaining))
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn parse_single_vlan_tag() {
106 let data = [
108 0x70, 0x64, 0x08, 0x00, ];
111 let vlan = VlanPacket::new(&data).unwrap();
112 assert_eq!(vlan.pcp(), 3);
113 assert!(vlan.dei());
114 assert_eq!(vlan.vid(), 100);
115 assert_eq!(vlan.ethertype(), EtherType::Ipv4);
116 }
117
118 #[test]
119 fn parse_vlan_tag_no_dei() {
120 let data = [
121 0x20, 0x0A, 0x08, 0x06, ];
124 let vlan = VlanPacket::new(&data).unwrap();
125 assert_eq!(vlan.pcp(), 1);
126 assert!(!vlan.dei());
127 assert_eq!(vlan.vid(), 10);
128 assert_eq!(vlan.ethertype(), EtherType::Arp);
129 }
130
131 #[test]
132 fn vlan_too_short() {
133 assert!(VlanPacket::new(&[]).is_none());
134 assert!(VlanPacket::new(&[0u8; 3]).is_none());
135 }
136
137 #[test]
138 fn vlan_chain_single() {
139 let data = [
141 0x00, 0x64, 0x08, 0x00, 0x45, ];
145 let (tags, final_et, payload) = parse_vlan_chain(&data).unwrap();
146 assert_eq!(tags.len(), 1);
147 assert_eq!(tags[0].vid(), 100);
148 assert_eq!(final_et, EtherType::Ipv4);
149 assert_eq!(payload, &[0x45]);
150 }
151}