1use core::mem;
2
3#[repr(C, packed)]
5#[derive(Debug, Copy, Clone)]
6#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
7pub struct LlcHdr {
8 pub dsap: u8,
10 pub ssap: u8,
12 pub ctrl: [u8; 2],
17}
18
19#[derive(Debug, PartialEq, Eq, Copy, Clone)]
21pub enum LlcFrameType {
22 I, S, U, Invalid, }
27
28impl LlcHdr {
29 pub const LEN: usize = mem::size_of::<LlcHdr>();
30
31 #[inline]
33 pub fn dsap_addr(&self) -> u8 {
34 self.dsap >> 1
35 }
36
37 #[inline]
40 pub fn dsap_is_individual_addr(&self) -> bool {
41 self.dsap & 0x01 == 0
42 }
43
44 #[inline]
47 pub fn dsap_is_group_addr(&self) -> bool {
48 self.dsap & 0x01 == 1
49 }
50
51 #[inline]
55 pub fn set_dsap(&mut self, addr: u8, is_group: bool) {
56 self.dsap = ((addr & 0x7F) << 1) | (is_group as u8);
57 }
58
59 #[inline]
61 pub fn ssap_address(&self) -> u8 {
62 self.ssap >> 1
63 }
64
65 #[inline]
68 pub fn ssap_is_command(&self) -> bool {
69 self.ssap & 0x01 == 0
70 }
71
72 #[inline]
75 pub fn ssap_is_response(&self) -> bool {
76 self.ssap & 0x01 == 1
77 }
78
79 #[inline]
83 pub fn set_ssap(&mut self, address: u8, is_response: bool) {
84 self.ssap = ((address & 0x7F) << 1) | (is_response as u8);
85 }
86
87 #[inline]
89 pub fn frame_type(&self) -> LlcFrameType {
90 let su = self.ctrl[0] & 0x03;
91 if (self.ctrl[0] & 0x01) == 0x00 {
92 LlcFrameType::I
93 } else if (su) == 0x01 {
94 LlcFrameType::S
95 } else if (su) == 0x03 {
96 LlcFrameType::U
97 } else {
98 LlcFrameType::Invalid }
100 }
101
102 #[inline]
104 pub fn is_i_format(&self) -> bool {
105 self.frame_type() == LlcFrameType::I
106 }
107
108 #[inline]
110 pub fn is_s_format(&self) -> bool {
111 self.frame_type() == LlcFrameType::S
112 }
113
114 #[inline]
116 pub fn is_u_format(&self) -> bool {
117 self.frame_type() == LlcFrameType::U
118 }
119
120 #[inline]
122 pub fn control_byte0(&self) -> u8 {
123 self.ctrl[0]
124 }
125
126 #[inline]
129 pub fn control_byte1(&self) -> Option<u8> {
130 match self.frame_type() {
131 LlcFrameType::I | LlcFrameType::S => Some(self.ctrl[1]),
132 _ => None,
133 }
134 }
135}
136
137#[cfg(test)]
139mod tests {
140 use super::*;
141
142 fn new_llc() -> LlcHdr {
143 LlcHdr {
144 dsap: 0,
145 ssap: 0,
146 ctrl: [0; 2],
147 }
148 }
149
150 #[test]
151 fn test_dsap_methods() {
152 let mut llc = new_llc();
153
154 llc.set_dsap(0x42, false); assert_eq!(llc.dsap_addr(), 0x42);
157 assert!(!llc.dsap_is_group_addr());
158 assert_eq!(llc.dsap, (0x42 << 1) | 0x00); llc.set_dsap(0x7F, true); assert_eq!(llc.dsap_addr(), 0x7F);
163 assert!(llc.dsap_is_group_addr());
164 assert_eq!(llc.dsap, (0x7F << 1) | 0x01); llc.set_dsap(0xFF, false); assert_eq!(llc.dsap_addr(), 0x7F);
169 assert!(!llc.dsap_is_group_addr());
170 assert_eq!(llc.dsap, (0x7F << 1) | 0x00); }
172
173 #[test]
174 fn test_ssap_methods() {
175 let mut llc = new_llc();
176
177 llc.set_ssap(0x3A, false); assert_eq!(llc.ssap_address(), 0x3A);
180 assert!(!llc.ssap_is_response());
181 assert_eq!(llc.ssap, (0x3A << 1) | 0x00); llc.set_ssap(0x01, true); assert_eq!(llc.ssap_address(), 0x01);
186 assert!(llc.ssap_is_response());
187 assert_eq!(llc.ssap, (0x01 << 1) | 0x01); llc.set_ssap(0b10101010, true); assert_eq!(llc.ssap_address(), 0x2A); assert!(llc.ssap_is_response());
193 assert_eq!(llc.ssap, (0x2A << 1) | 0x01); }
195
196 #[test]
197 fn test_u_format_identification_and_bytes() {
198 let mut llc = new_llc();
199 llc.ctrl[0] = 0x03; llc.ctrl[1] = 0xFF; assert_eq!(llc.frame_type(), LlcFrameType::U);
203 assert!(llc.is_u_format());
204 assert!(!llc.is_i_format());
205 assert!(!llc.is_s_format());
206 assert_eq!(llc.control_byte0(), 0x03);
207 assert_eq!(llc.control_byte1(), None); llc.ctrl[0] = 0x6F; assert_eq!(llc.frame_type(), LlcFrameType::U);
211 assert_eq!(llc.control_byte0(), 0x6F);
212 assert_eq!(llc.control_byte1(), None);
213 }
214
215 #[test]
216 fn test_i_format_identification_and_bytes() {
217 let mut llc = new_llc();
218 llc.ctrl[0] = 0x0A; llc.ctrl[1] = 0x83; assert_eq!(llc.frame_type(), LlcFrameType::I);
223 assert!(llc.is_i_format());
224 assert!(!llc.is_u_format());
225 assert!(!llc.is_s_format());
226 assert_eq!(llc.control_byte0(), 0x0A);
227 assert_eq!(llc.control_byte1(), Some(0x83));
228
229 llc.ctrl[0] = 0xFE; llc.ctrl[1] = 0x42; assert_eq!(llc.frame_type(), LlcFrameType::I);
232 assert_eq!(llc.control_byte0(), 0xFE);
233 assert_eq!(llc.control_byte1(), Some(0x42));
234 }
235
236 #[test]
237 fn test_s_format_identification_and_bytes() {
238 let mut llc = new_llc();
239 llc.ctrl[0] = 0x01; llc.ctrl[1] = 0x07; assert_eq!(llc.frame_type(), LlcFrameType::S);
244 assert!(llc.is_s_format());
245 assert!(!llc.is_u_format());
246 assert!(!llc.is_i_format());
247 assert_eq!(llc.control_byte0(), 0x01);
248 assert_eq!(llc.control_byte1(), Some(0x07));
249
250 llc.ctrl[0] = 0x0D; llc.ctrl[0] = 0x09; llc.ctrl[1] = 0x00;
254 assert_eq!(llc.frame_type(), LlcFrameType::S);
255 assert_eq!(llc.control_byte0(), 0x09);
256 assert_eq!(llc.control_byte1(), Some(0x00));
257 }
258
259 #[test]
260 fn test_frame_type_priority() {
261 let mut llc = new_llc();
263 llc.ctrl[0] = 0b0000_0010; assert_eq!(llc.frame_type(), LlcFrameType::I);
265
266 llc.ctrl[0] = 0b0000_0011;
268 assert_eq!(llc.frame_type(), LlcFrameType::U);
269
270 llc.ctrl[0] = 0b0000_0001;
272 assert_eq!(llc.frame_type(), LlcFrameType::S);
273 }
274
275 #[test]
276 fn test_len_constant() {
277 assert_eq!(LlcHdr::LEN, 1 + 1 + 2);
279 assert_eq!(LlcHdr::LEN, 4);
280 }
281}