1use core::mem;
2
3#[repr(C)]
5#[derive(Debug, Copy, Clone)]
6#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
7#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
8pub struct LlcHdr {
9 pub dsap: u8,
11 pub ssap: u8,
13 pub ctrl: [u8; 2],
18}
19
20#[derive(Debug, PartialEq, Eq, Copy, Clone)]
22pub enum LlcFrameType {
23 I, S, U, Invalid, }
28
29impl LlcHdr {
30 pub const LEN: usize = mem::size_of::<LlcHdr>();
31
32 #[inline]
34 pub fn dsap_addr(&self) -> u8 {
35 self.dsap >> 1
36 }
37
38 #[inline]
41 pub fn dsap_is_individual_addr(&self) -> bool {
42 self.dsap & 0x01 == 0
43 }
44
45 #[inline]
48 pub fn dsap_is_group_addr(&self) -> bool {
49 self.dsap & 0x01 == 1
50 }
51
52 #[inline]
56 pub fn set_dsap(&mut self, addr: u8, is_group: bool) {
57 self.dsap = ((addr & 0x7F) << 1) | (is_group as u8);
58 }
59
60 #[inline]
62 pub fn ssap_address(&self) -> u8 {
63 self.ssap >> 1
64 }
65
66 #[inline]
69 pub fn ssap_is_command(&self) -> bool {
70 self.ssap & 0x01 == 0
71 }
72
73 #[inline]
76 pub fn ssap_is_response(&self) -> bool {
77 self.ssap & 0x01 == 1
78 }
79
80 #[inline]
84 pub fn set_ssap(&mut self, address: u8, is_response: bool) {
85 self.ssap = ((address & 0x7F) << 1) | (is_response as u8);
86 }
87
88 #[inline]
90 pub fn frame_type(&self) -> LlcFrameType {
91 let su = self.ctrl[0] & 0x03;
92 if (self.ctrl[0] & 0x01) == 0x00 {
93 LlcFrameType::I
94 } else if (su) == 0x01 {
95 LlcFrameType::S
96 } else if (su) == 0x03 {
97 LlcFrameType::U
98 } else {
99 LlcFrameType::Invalid }
101 }
102
103 #[inline]
105 pub fn is_i_format(&self) -> bool {
106 self.frame_type() == LlcFrameType::I
107 }
108
109 #[inline]
111 pub fn is_s_format(&self) -> bool {
112 self.frame_type() == LlcFrameType::S
113 }
114
115 #[inline]
117 pub fn is_u_format(&self) -> bool {
118 self.frame_type() == LlcFrameType::U
119 }
120
121 #[inline]
123 pub fn control_byte0(&self) -> u8 {
124 self.ctrl[0]
125 }
126
127 #[inline]
130 pub fn control_byte1(&self) -> Option<u8> {
131 match self.frame_type() {
132 LlcFrameType::I | LlcFrameType::S => Some(self.ctrl[1]),
133 _ => None,
134 }
135 }
136}
137
138#[cfg(test)]
140mod tests {
141 use super::*;
142
143 fn new_llc() -> LlcHdr {
144 LlcHdr {
145 dsap: 0,
146 ssap: 0,
147 ctrl: [0; 2],
148 }
149 }
150
151 #[test]
152 fn test_dsap_methods() {
153 let mut llc = new_llc();
154
155 llc.set_dsap(0x42, false); assert_eq!(llc.dsap_addr(), 0x42);
158 assert!(!llc.dsap_is_group_addr());
159 assert_eq!(llc.dsap, 0x42 << 1); llc.set_dsap(0x7F, true); assert_eq!(llc.dsap_addr(), 0x7F);
164 assert!(llc.dsap_is_group_addr());
165 assert_eq!(llc.dsap, (0x7F << 1) | 0x01); llc.set_dsap(0xFF, false); assert_eq!(llc.dsap_addr(), 0x7F);
170 assert!(!llc.dsap_is_group_addr());
171 assert_eq!(llc.dsap, 0x7F << 1); }
173
174 #[test]
175 fn test_ssap_methods() {
176 let mut llc = new_llc();
177
178 llc.set_ssap(0x3A, false); assert_eq!(llc.ssap_address(), 0x3A);
181 assert!(!llc.ssap_is_response());
182 assert_eq!(llc.ssap, 0x3A << 1); llc.set_ssap(0x01, true); assert_eq!(llc.ssap_address(), 0x01);
187 assert!(llc.ssap_is_response());
188 assert_eq!(llc.ssap, (0x01 << 1) | 0x01); llc.set_ssap(0b10101010, true); assert_eq!(llc.ssap_address(), 0x2A); assert!(llc.ssap_is_response());
194 assert_eq!(llc.ssap, (0x2A << 1) | 0x01); }
196
197 #[test]
198 fn test_u_format_identification_and_bytes() {
199 let mut llc = new_llc();
200 llc.ctrl[0] = 0x03; llc.ctrl[1] = 0xFF; assert_eq!(llc.frame_type(), LlcFrameType::U);
204 assert!(llc.is_u_format());
205 assert!(!llc.is_i_format());
206 assert!(!llc.is_s_format());
207 assert_eq!(llc.control_byte0(), 0x03);
208 assert_eq!(llc.control_byte1(), None); llc.ctrl[0] = 0x6F; assert_eq!(llc.frame_type(), LlcFrameType::U);
212 assert_eq!(llc.control_byte0(), 0x6F);
213 assert_eq!(llc.control_byte1(), None);
214 }
215
216 #[test]
217 fn test_i_format_identification_and_bytes() {
218 let mut llc = new_llc();
219 llc.ctrl[0] = 0x0A; llc.ctrl[1] = 0x83; assert_eq!(llc.frame_type(), LlcFrameType::I);
224 assert!(llc.is_i_format());
225 assert!(!llc.is_u_format());
226 assert!(!llc.is_s_format());
227 assert_eq!(llc.control_byte0(), 0x0A);
228 assert_eq!(llc.control_byte1(), Some(0x83));
229
230 llc.ctrl[0] = 0xFE; llc.ctrl[1] = 0x42; assert_eq!(llc.frame_type(), LlcFrameType::I);
233 assert_eq!(llc.control_byte0(), 0xFE);
234 assert_eq!(llc.control_byte1(), Some(0x42));
235 }
236
237 #[test]
238 fn test_s_format_identification_and_bytes() {
239 let mut llc = new_llc();
240 llc.ctrl[0] = 0x01; llc.ctrl[1] = 0x07; assert_eq!(llc.frame_type(), LlcFrameType::S);
245 assert!(llc.is_s_format());
246 assert!(!llc.is_u_format());
247 assert!(!llc.is_i_format());
248 assert_eq!(llc.control_byte0(), 0x01);
249 assert_eq!(llc.control_byte1(), Some(0x07));
250
251 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}