1use super::{Error, Result};
7use crate::wire::ieee802154::Address as LlAddress;
8use crate::wire::ipv6;
9use crate::wire::ipv6::AddressExt;
10use crate::wire::IpProtocol;
11
12pub mod frag;
13pub mod iphc;
14pub mod nhc;
15
16const ADDRESS_CONTEXT_LENGTH: usize = 8;
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub struct AddressContext(pub [u8; ADDRESS_CONTEXT_LENGTH]);
21
22#[derive(Debug, PartialEq, Eq, Clone, Copy)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub enum UnresolvedAddress<'a> {
28 WithoutContext(AddressMode<'a>),
29 WithContext((usize, AddressMode<'a>)),
30 Reserved,
31}
32
33#[derive(Debug, PartialEq, Eq, Clone, Copy)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum AddressMode<'a> {
36 FullInline(&'a [u8]),
38 InLine64bits(&'a [u8]),
42 InLine16bits(&'a [u8]),
46 FullyElided,
51 Multicast48bits(&'a [u8]),
53 Multicast32bits(&'a [u8]),
55 Multicast8bits(&'a [u8]),
57 Unspecified,
59 NotSupported,
60}
61
62const LINK_LOCAL_PREFIX: [u8; 2] = [0xfe, 0x80];
63const EUI64_MIDDLE_VALUE: [u8; 2] = [0xff, 0xfe];
64
65impl<'a> UnresolvedAddress<'a> {
66 pub fn resolve(
67 self,
68 ll_address: Option<LlAddress>,
69 addr_context: &[AddressContext],
70 ) -> Result<ipv6::Address> {
71 let mut bytes = [0; 16];
72
73 let copy_context = |index: usize, bytes: &mut [u8]| -> Result<()> {
74 if index >= addr_context.len() {
75 return Err(Error);
76 }
77
78 let context = addr_context[index];
79 bytes[..ADDRESS_CONTEXT_LENGTH].copy_from_slice(&context.0);
80
81 Ok(())
82 };
83
84 match self {
85 UnresolvedAddress::WithoutContext(mode) => match mode {
86 AddressMode::FullInline(addr) => Ok(ipv6::Address::from_bytes(addr)),
87 AddressMode::InLine64bits(inline) => {
88 bytes[0..2].copy_from_slice(&LINK_LOCAL_PREFIX[..]);
89 bytes[8..].copy_from_slice(inline);
90 Ok(ipv6::Address::from_bytes(&bytes[..]))
91 }
92 AddressMode::InLine16bits(inline) => {
93 bytes[0..2].copy_from_slice(&LINK_LOCAL_PREFIX[..]);
94 bytes[11..13].copy_from_slice(&EUI64_MIDDLE_VALUE[..]);
95 bytes[14..].copy_from_slice(inline);
96 Ok(ipv6::Address::from_bytes(&bytes[..]))
97 }
98 AddressMode::FullyElided => {
99 bytes[0..2].copy_from_slice(&LINK_LOCAL_PREFIX[..]);
100 match ll_address {
101 Some(LlAddress::Short(ll)) => {
102 bytes[11..13].copy_from_slice(&EUI64_MIDDLE_VALUE[..]);
103 bytes[14..].copy_from_slice(&ll);
104 }
105 Some(addr @ LlAddress::Extended(_)) => match addr.as_eui_64() {
106 Some(addr) => bytes[8..].copy_from_slice(&addr),
107 None => return Err(Error),
108 },
109 Some(LlAddress::Absent) => return Err(Error),
110 None => return Err(Error),
111 }
112 Ok(ipv6::Address::from_bytes(&bytes[..]))
113 }
114 AddressMode::Multicast48bits(inline) => {
115 bytes[0] = 0xff;
116 bytes[1] = inline[0];
117 bytes[11..].copy_from_slice(&inline[1..][..5]);
118 Ok(ipv6::Address::from_bytes(&bytes[..]))
119 }
120 AddressMode::Multicast32bits(inline) => {
121 bytes[0] = 0xff;
122 bytes[1] = inline[0];
123 bytes[13..].copy_from_slice(&inline[1..][..3]);
124 Ok(ipv6::Address::from_bytes(&bytes[..]))
125 }
126 AddressMode::Multicast8bits(inline) => {
127 bytes[0] = 0xff;
128 bytes[1] = 0x02;
129 bytes[15] = inline[0];
130 Ok(ipv6::Address::from_bytes(&bytes[..]))
131 }
132 _ => Err(Error),
133 },
134 UnresolvedAddress::WithContext(mode) => match mode {
135 (_, AddressMode::Unspecified) => Ok(ipv6::Address::UNSPECIFIED),
136 (index, AddressMode::InLine64bits(inline)) => {
137 copy_context(index, &mut bytes[..])?;
138 bytes[16 - inline.len()..].copy_from_slice(inline);
139 Ok(ipv6::Address::from_bytes(&bytes[..]))
140 }
141 (index, AddressMode::InLine16bits(inline)) => {
142 copy_context(index, &mut bytes[..])?;
143 bytes[16 - inline.len()..].copy_from_slice(inline);
144 Ok(ipv6::Address::from_bytes(&bytes[..]))
145 }
146 (index, AddressMode::FullyElided) => {
147 match ll_address {
148 Some(LlAddress::Short(ll)) => {
149 bytes[11..13].copy_from_slice(&EUI64_MIDDLE_VALUE[..]);
150 bytes[14..].copy_from_slice(&ll);
151 }
152 Some(addr @ LlAddress::Extended(_)) => match addr.as_eui_64() {
153 Some(addr) => bytes[8..].copy_from_slice(&addr),
154 None => return Err(Error),
155 },
156 Some(LlAddress::Absent) => return Err(Error),
157 None => return Err(Error),
158 }
159
160 copy_context(index, &mut bytes[..])?;
161
162 Ok(ipv6::Address::from_bytes(&bytes[..]))
163 }
164 _ => Err(Error),
165 },
166 UnresolvedAddress::Reserved => Err(Error),
167 }
168 }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172#[cfg_attr(feature = "defmt", derive(defmt::Format))]
173pub enum SixlowpanPacket {
174 FragmentHeader,
175 IphcHeader,
176}
177
178const DISPATCH_FIRST_FRAGMENT_HEADER: u8 = 0b11000;
179const DISPATCH_FRAGMENT_HEADER: u8 = 0b11100;
180const DISPATCH_IPHC_HEADER: u8 = 0b011;
181const DISPATCH_UDP_HEADER: u8 = 0b11110;
182const DISPATCH_EXT_HEADER: u8 = 0b1110;
183
184impl SixlowpanPacket {
185 pub fn dispatch(buffer: impl AsRef<[u8]>) -> Result<Self> {
192 let raw = buffer.as_ref();
193
194 if raw.is_empty() {
195 return Err(Error);
196 }
197
198 if raw[0] >> 3 == DISPATCH_FIRST_FRAGMENT_HEADER || raw[0] >> 3 == DISPATCH_FRAGMENT_HEADER
199 {
200 Ok(Self::FragmentHeader)
201 } else if raw[0] >> 5 == DISPATCH_IPHC_HEADER {
202 Ok(Self::IphcHeader)
203 } else {
204 Err(Error)
205 }
206 }
207}
208
209#[derive(Debug, PartialEq, Eq, Clone, Copy)]
210pub enum NextHeader {
211 Compressed,
212 Uncompressed(IpProtocol),
213}
214
215impl core::fmt::Display for NextHeader {
216 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
217 match self {
218 NextHeader::Compressed => write!(f, "compressed"),
219 NextHeader::Uncompressed(protocol) => write!(f, "{protocol}"),
220 }
221 }
222}
223
224#[cfg(feature = "defmt")]
225impl defmt::Format for NextHeader {
226 fn format(&self, fmt: defmt::Formatter) {
227 match self {
228 NextHeader::Compressed => defmt::write!(fmt, "compressed"),
229 NextHeader::Uncompressed(protocol) => defmt::write!(fmt, "{}", protocol),
230 }
231 }
232}
233
234#[cfg(test)]
235mod test {
236 use super::*;
237
238 #[test]
239 fn sixlowpan_fragment_emit() {
240 let repr = frag::Repr::FirstFragment {
241 size: 0xff,
242 tag: 0xabcd,
243 };
244 let buffer = [0u8; 4];
245 let mut packet = frag::Packet::new_unchecked(buffer);
246
247 assert_eq!(repr.buffer_len(), 4);
248 repr.emit(&mut packet);
249
250 assert_eq!(packet.datagram_size(), 0xff);
251 assert_eq!(packet.datagram_tag(), 0xabcd);
252 assert_eq!(packet.into_inner(), [0xc0, 0xff, 0xab, 0xcd]);
253
254 let repr = frag::Repr::Fragment {
255 size: 0xff,
256 tag: 0xabcd,
257 offset: 0xcc,
258 };
259 let buffer = [0u8; 5];
260 let mut packet = frag::Packet::new_unchecked(buffer);
261
262 assert_eq!(repr.buffer_len(), 5);
263 repr.emit(&mut packet);
264
265 assert_eq!(packet.datagram_size(), 0xff);
266 assert_eq!(packet.datagram_tag(), 0xabcd);
267 assert_eq!(packet.into_inner(), [0xe0, 0xff, 0xab, 0xcd, 0xcc]);
268 }
269
270 #[test]
271 fn sixlowpan_three_fragments() {
272 use crate::wire::ieee802154::Frame as Ieee802154Frame;
273 use crate::wire::ieee802154::Repr as Ieee802154Repr;
274 use crate::wire::Ieee802154Address;
275
276 let key = frag::Key {
277 ll_src_addr: Ieee802154Address::Extended([50, 147, 130, 47, 40, 8, 62, 217]),
278 ll_dst_addr: Ieee802154Address::Extended([26, 11, 66, 66, 66, 66, 66, 66]),
279 datagram_size: 307,
280 datagram_tag: 63,
281 };
282
283 let frame1: &[u8] = &[
284 0x41, 0xcc, 0x92, 0xef, 0xbe, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0b, 0x1a, 0xd9,
285 0x3e, 0x08, 0x28, 0x2f, 0x82, 0x93, 0x32, 0xc1, 0x33, 0x00, 0x3f, 0x6e, 0x33, 0x02,
286 0x35, 0x3d, 0xf0, 0xd2, 0x5f, 0x1b, 0x39, 0xb4, 0x6b, 0x4c, 0x6f, 0x72, 0x65, 0x6d,
287 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73,
288 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65,
289 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63,
290 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74, 0x2e, 0x20, 0x41, 0x6c, 0x69, 0x71,
291 0x75, 0x61, 0x6d, 0x20, 0x64, 0x75, 0x69, 0x20, 0x6f, 0x64, 0x69, 0x6f, 0x2c, 0x20,
292 0x69, 0x61, 0x63, 0x75, 0x6c, 0x69, 0x73, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x72,
293 ];
294
295 let ieee802154_frame = Ieee802154Frame::new_checked(frame1).unwrap();
296 let ieee802154_repr = Ieee802154Repr::parse(&ieee802154_frame).unwrap();
297
298 let sixlowpan_frame =
299 SixlowpanPacket::dispatch(ieee802154_frame.payload().unwrap()).unwrap();
300
301 let frag = if let SixlowpanPacket::FragmentHeader = sixlowpan_frame {
302 frag::Packet::new_checked(ieee802154_frame.payload().unwrap()).unwrap()
303 } else {
304 unreachable!()
305 };
306
307 assert_eq!(frag.datagram_size(), 307);
308 assert_eq!(frag.datagram_tag(), 0x003f);
309 assert_eq!(frag.datagram_offset(), 0);
310
311 assert_eq!(frag.get_key(&ieee802154_repr), key);
312
313 let frame2: &[u8] = &[
314 0x41, 0xcc, 0x93, 0xef, 0xbe, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0b, 0x1a, 0xd9,
315 0x3e, 0x08, 0x28, 0x2f, 0x82, 0x93, 0x32, 0xe1, 0x33, 0x00, 0x3f, 0x11, 0x75, 0x74,
316 0x72, 0x75, 0x6d, 0x20, 0x61, 0x74, 0x2c, 0x20, 0x74, 0x72, 0x69, 0x73, 0x74, 0x69,
317 0x71, 0x75, 0x65, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75, 0x6e, 0x63, 0x20, 0x65,
318 0x72, 0x61, 0x74, 0x20, 0x63, 0x75, 0x72, 0x61, 0x65, 0x2e, 0x20, 0x4c, 0x6f, 0x72,
319 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72,
320 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e,
321 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69,
322 0x73, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x69, 0x74,
323 ];
324
325 let ieee802154_frame = Ieee802154Frame::new_checked(frame2).unwrap();
326 let ieee802154_repr = Ieee802154Repr::parse(&ieee802154_frame).unwrap();
327
328 let sixlowpan_frame =
329 SixlowpanPacket::dispatch(ieee802154_frame.payload().unwrap()).unwrap();
330
331 let frag = if let SixlowpanPacket::FragmentHeader = sixlowpan_frame {
332 frag::Packet::new_checked(ieee802154_frame.payload().unwrap()).unwrap()
333 } else {
334 unreachable!()
335 };
336
337 assert_eq!(frag.datagram_size(), 307);
338 assert_eq!(frag.datagram_tag(), 0x003f);
339 assert_eq!(frag.datagram_offset(), 136 / 8);
340
341 assert_eq!(frag.get_key(&ieee802154_repr), key);
342
343 let frame3: &[u8] = &[
344 0x41, 0xcc, 0x94, 0xef, 0xbe, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x0b, 0x1a, 0xd9,
345 0x3e, 0x08, 0x28, 0x2f, 0x82, 0x93, 0x32, 0xe1, 0x33, 0x00, 0x3f, 0x1d, 0x2e, 0x20,
346 0x41, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x64, 0x75, 0x69, 0x20, 0x6f, 0x64,
347 0x69, 0x6f, 0x2c, 0x20, 0x69, 0x61, 0x63, 0x75, 0x6c, 0x69, 0x73, 0x20, 0x76, 0x65,
348 0x6c, 0x20, 0x72, 0x75, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x61, 0x74, 0x2c, 0x20, 0x74,
349 0x72, 0x69, 0x73, 0x74, 0x69, 0x71, 0x75, 0x65, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e,
350 0x75, 0x6e, 0x63, 0x20, 0x65, 0x72, 0x61, 0x74, 0x20, 0x63, 0x75, 0x72, 0x61, 0x65,
351 0x2e, 0x20, 0x0a,
352 ];
353
354 let ieee802154_frame = Ieee802154Frame::new_checked(frame3).unwrap();
355 let ieee802154_repr = Ieee802154Repr::parse(&ieee802154_frame).unwrap();
356
357 let sixlowpan_frame =
358 SixlowpanPacket::dispatch(ieee802154_frame.payload().unwrap()).unwrap();
359
360 let frag = if let SixlowpanPacket::FragmentHeader = sixlowpan_frame {
361 frag::Packet::new_checked(ieee802154_frame.payload().unwrap()).unwrap()
362 } else {
363 unreachable!()
364 };
365
366 assert_eq!(frag.datagram_size(), 307);
367 assert_eq!(frag.datagram_tag(), 0x003f);
368 assert_eq!(frag.datagram_offset(), 232 / 8);
369
370 assert_eq!(frag.get_key(&ieee802154_repr), key);
371 }
372}