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