1use super::*;
2use crate::wire::Result;
3
4pub(crate) const MAX_DECOMPRESSED_LEN: usize = 1500;
7
8impl Interface {
9 #[cfg(feature = "proto-sixlowpan-fragmentation")]
11 pub(super) fn sixlowpan_egress(&mut self, device: &mut (impl Device + ?Sized)) {
12 if self.fragmenter.finished() {
14 self.fragmenter.reset();
15 }
16
17 if self.fragmenter.is_empty() {
18 return;
19 }
20
21 let pkt = &self.fragmenter;
22 if pkt.packet_len > pkt.sent_bytes
23 && let Some(tx_token) = device.transmit(self.inner.now)
24 {
25 self.inner
26 .dispatch_ieee802154_frag(tx_token, &mut self.fragmenter);
27 }
28 }
29
30 pub fn sixlowpan_address_context(&self) -> &[SixlowpanAddressContext] {
32 &self.inner.sixlowpan_address_context[..]
33 }
34
35 pub fn sixlowpan_address_context_mut(
37 &mut self,
38 ) -> &mut Vec<SixlowpanAddressContext, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT> {
39 &mut self.inner.sixlowpan_address_context
40 }
41}
42
43impl InterfaceInner {
44 #[cfg(feature = "proto-sixlowpan-fragmentation")]
46 fn get_sixlowpan_fragment_tag(&mut self) -> u16 {
47 let tag = self.tag;
48 self.tag = self.tag.wrapping_add(1);
49 tag
50 }
51
52 pub(super) fn process_sixlowpan<'output, 'payload: 'output>(
53 &mut self,
54 sockets: &mut SocketSet,
55 meta: PacketMeta,
56 ieee802154_repr: &Ieee802154Repr,
57 payload: &'payload [u8],
58 f: &'output mut FragmentsBuffer,
59 ) -> Option<Packet<'output>> {
60 let payload = match check!(SixlowpanPacket::dispatch(payload)) {
61 #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
62 SixlowpanPacket::FragmentHeader => {
63 net_debug!(
64 "Fragmentation is not supported, \
65 use the `proto-sixlowpan-fragmentation` feature to add support."
66 );
67 return None;
68 }
69 #[cfg(feature = "proto-sixlowpan-fragmentation")]
70 SixlowpanPacket::FragmentHeader => {
71 self.process_sixlowpan_fragment(ieee802154_repr, payload, f)?
72 }
73 SixlowpanPacket::IphcHeader => {
74 match Self::sixlowpan_to_ipv6(
75 &self.sixlowpan_address_context,
76 ieee802154_repr,
77 payload,
78 None,
79 &mut f.decompress_buf,
80 ) {
81 Ok(len) => &f.decompress_buf[..len],
82 Err(e) => {
83 net_debug!("sixlowpan decompress failed: {:?}", e);
84 return None;
85 }
86 }
87 }
88 };
89
90 self.process_ipv6(
91 sockets,
92 meta,
93 match ieee802154_repr.src_addr {
94 Some(s) => HardwareAddress::Ieee802154(s),
95 None => HardwareAddress::Ieee802154(Ieee802154Address::Absent),
96 },
97 &check!(Ipv6Packet::new_checked(payload)),
98 )
99 }
100
101 #[cfg(feature = "proto-sixlowpan-fragmentation")]
102 fn process_sixlowpan_fragment<'output, 'payload: 'output>(
103 &mut self,
104 ieee802154_repr: &Ieee802154Repr,
105 payload: &'payload [u8],
106 f: &'output mut FragmentsBuffer,
107 ) -> Option<&'output [u8]> {
108 use crate::iface::fragmentation::{AssemblerError, AssemblerFullError};
109
110 let frag = check!(SixlowpanFragPacket::new_checked(payload));
113
114 if frag.datagram_size() < 40 {
119 net_debug!("6LoWPAN: fragment size too small");
120 return None;
121 }
122
123 let key = FragKey::Sixlowpan(frag.get_key(ieee802154_repr));
126
127 let offset = frag.datagram_offset() as usize * 8;
129
130 let frag_slot = match f.assembler.get(&key, self.now + f.reassembly_timeout) {
136 Ok(frag) => frag,
137 Err(AssemblerFullError) => {
138 net_debug!("No available packet assembler for fragmented packet");
139 return None;
140 }
141 };
142
143 if frag.is_first_fragment() {
144 let total_size = frag.datagram_size() as usize;
153 if frag_slot.set_total_size(total_size).is_err() {
154 net_debug!("No available packet assembler for fragmented packet");
155 return None;
156 }
157
158 if let Err(e) = frag_slot.add_with(0, |buffer| {
160 Self::sixlowpan_to_ipv6(
161 &self.sixlowpan_address_context,
162 ieee802154_repr,
163 frag.payload(),
164 Some(total_size),
165 buffer,
166 )
167 .map_err(|_| AssemblerError)
168 }) {
169 net_debug!("fragmentation error: {:?}", e);
170 return None;
171 }
172 } else {
173 if let Err(e) = frag_slot.add(frag.payload(), offset) {
175 net_debug!("fragmentation error: {:?}", e);
176 return None;
177 }
178 }
179
180 match frag_slot.assemble() {
181 Some(payload) => {
182 net_trace!("6LoWPAN: fragmented packet now complete");
183 Some(payload)
184 }
185 None => None,
186 }
187 }
188
189 fn sixlowpan_to_ipv6(
199 address_context: &[SixlowpanAddressContext],
200 ieee802154_repr: &Ieee802154Repr,
201 iphc_payload: &[u8],
202 total_len: Option<usize>,
203 buffer: &mut [u8],
204 ) -> Result<usize> {
205 let iphc = SixlowpanIphcPacket::new_checked(iphc_payload)?;
206 let iphc_repr = SixlowpanIphcRepr::parse(
207 &iphc,
208 ieee802154_repr.src_addr,
209 ieee802154_repr.dst_addr,
210 address_context,
211 )?;
212
213 let (ipv6_buffer, mut buffer) = buffer.split_at_mut(40);
219 let mut ipv6_header = Ipv6Packet::new_unchecked(ipv6_buffer);
220
221 let mut payload_len = 40;
226 let mut decompressed_len = 40;
227
228 let mut next_header = Some(iphc_repr.next_header);
229 let mut data = iphc.payload();
230
231 while let Some(nh) = next_header {
232 match nh {
233 SixlowpanNextHeader::Compressed => match SixlowpanNhcPacket::dispatch(data)? {
234 SixlowpanNhcPacket::ExtHeader => {
235 (buffer, data) = decompress_ext_hdr(
236 data,
237 &mut next_header,
238 buffer,
239 &mut payload_len,
240 &mut decompressed_len,
241 )?;
242 }
243 SixlowpanNhcPacket::UdpHeader => {
244 decompress_udp(
245 data,
246 &iphc_repr,
247 buffer,
248 total_len,
249 &mut payload_len,
250 &mut decompressed_len,
251 )?;
252
253 break;
254 }
255 },
256 SixlowpanNextHeader::Uncompressed(proto) => {
257 match proto {
259 IpProtocol::Tcp | IpProtocol::Udp | IpProtocol::Icmpv6 => {
260 if data.len() > buffer.len() {
265 return Err(Error);
266 }
267 buffer[..data.len()].copy_from_slice(data);
268 payload_len += data.len();
269 decompressed_len += data.len();
270 break;
271 }
272 proto => {
273 net_debug!("Unsupported uncompressed next header: {:?}", proto);
274 return Err(Error);
275 }
276 }
277 }
278 }
279 }
280
281 let ipv6_repr = Ipv6Repr {
282 src_addr: iphc_repr.src_addr,
283 dst_addr: iphc_repr.dst_addr,
284 next_header: decompress_next_header(iphc_repr.next_header, iphc.payload())?,
285 payload_len: total_len.unwrap_or(payload_len) - 40,
286 hop_limit: iphc_repr.hop_limit,
287 };
288 ipv6_repr.emit(&mut ipv6_header);
289
290 Ok(decompressed_len)
291 }
292
293 pub(super) fn dispatch_sixlowpan<Tx: TxToken>(
294 &mut self,
295 mut tx_token: Tx,
296 meta: PacketMeta,
297 packet: Packet,
298 ieee_repr: Ieee802154Repr,
299 frag: &mut Fragmenter,
300 ) {
301 let packet = match packet {
302 #[cfg(feature = "proto-ipv4")]
303 Packet::Ipv4(_) => unreachable!(),
304 Packet::Ipv6(packet) => packet,
305 };
306
307 let (total_size, compressed_size, uncompressed_size) =
310 Self::compressed_packet_size(&packet, &ieee_repr);
311
312 let ieee_len = ieee_repr.buffer_len();
313
314 if total_size + ieee_len > 125 {
316 #[cfg(feature = "proto-sixlowpan-fragmentation")]
317 {
318 let pkt = frag;
328 if pkt.buffer.len() < total_size {
329 net_debug!(
330 "dispatch_ieee802154: dropping, \
331 fragmentation buffer is too small, at least {} needed",
332 total_size
333 );
334 return;
335 }
336
337 let payload_length = packet.header.payload_len;
338
339 Self::ipv6_to_sixlowpan(
340 &self.checksum_caps(),
341 packet,
342 &ieee_repr,
343 &mut pkt.buffer[..],
344 );
345
346 pkt.sixlowpan.ll_dst_addr = ieee_repr.dst_addr.unwrap();
347 pkt.sixlowpan.ll_src_addr = ieee_repr.src_addr.unwrap();
348 pkt.packet_len = total_size;
349
350 pkt.sixlowpan.datagram_size = (payload_length + 40) as u16;
353
354 let tag = self.get_sixlowpan_fragment_tag();
355 pkt.sixlowpan.datagram_tag = tag;
358
359 let frag1 = SixlowpanFragRepr::FirstFragment {
360 size: pkt.sixlowpan.datagram_size,
361 tag,
362 };
363 let fragn = SixlowpanFragRepr::Fragment {
364 size: pkt.sixlowpan.datagram_size,
365 tag,
366 offset: 0,
367 };
368
369 let header_diff = uncompressed_size - compressed_size;
377 let frag1_size =
378 (125 - ieee_len - frag1.buffer_len() + header_diff) / 8 * 8 - header_diff;
379
380 pkt.sixlowpan.fragn_size = (125 - ieee_len - fragn.buffer_len()) / 8 * 8;
381 pkt.sent_bytes = frag1_size;
382 pkt.sixlowpan.datagram_offset = frag1_size + header_diff;
383
384 tx_token.set_meta(meta);
385 tx_token.consume(ieee_len + frag1.buffer_len() + frag1_size, |mut tx_buf| {
386 let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
388 ieee_repr.emit(&mut ieee_packet);
389 tx_buf = &mut tx_buf[ieee_len..];
390
391 let mut frag1_packet = SixlowpanFragPacket::new_unchecked(&mut tx_buf);
393 frag1.emit(&mut frag1_packet);
394 tx_buf = &mut tx_buf[frag1.buffer_len()..];
395
396 tx_buf[..frag1_size].copy_from_slice(&pkt.buffer[..frag1_size]);
398 });
399 }
400
401 #[cfg(not(feature = "proto-sixlowpan-fragmentation"))]
402 {
403 net_debug!(
404 "Enable the `proto-sixlowpan-fragmentation` feature for fragmentation support."
405 );
406 return;
407 }
408 } else {
409 tx_token.set_meta(meta);
410
411 tx_token.consume(total_size + ieee_len, |mut tx_buf| {
413 let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
414 ieee_repr.emit(&mut ieee_packet);
415 tx_buf = &mut tx_buf[ieee_len..];
416
417 Self::ipv6_to_sixlowpan(&self.checksum_caps(), packet, &ieee_repr, tx_buf);
418 });
419 }
420 }
421
422 fn ipv6_to_sixlowpan(
423 checksum_caps: &ChecksumCapabilities,
424 mut packet: PacketV6,
425 ieee_repr: &Ieee802154Repr,
426 mut buffer: &mut [u8],
427 ) {
428 let last_header = packet.payload.as_sixlowpan_next_header();
429 let next_header = last_header;
430
431 #[cfg(feature = "proto-ipv6-hbh")]
432 let next_header = if packet.hop_by_hop.is_some() {
433 SixlowpanNextHeader::Compressed
434 } else {
435 next_header
436 };
437
438 #[cfg(feature = "proto-ipv6-routing")]
439 let next_header = if packet.routing.is_some() {
440 SixlowpanNextHeader::Compressed
441 } else {
442 next_header
443 };
444
445 let iphc_repr = SixlowpanIphcRepr {
446 src_addr: packet.header.src_addr,
447 ll_src_addr: ieee_repr.src_addr,
448 dst_addr: packet.header.dst_addr,
449 ll_dst_addr: ieee_repr.dst_addr,
450 next_header,
451 hop_limit: packet.header.hop_limit,
452 ecn: None,
453 dscp: None,
454 flow_label: None,
455 };
456
457 iphc_repr.emit(&mut SixlowpanIphcPacket::new_unchecked(
458 &mut buffer[..iphc_repr.buffer_len()],
459 ));
460 buffer = &mut buffer[iphc_repr.buffer_len()..];
461
462 #[cfg(feature = "proto-ipv6-hbh")]
464 if let Some(hbh) = packet.hop_by_hop {
465 #[allow(unused)]
466 let next_header = last_header;
467
468 #[cfg(feature = "proto-ipv6-routing")]
469 let next_header = if packet.routing.is_some() {
470 SixlowpanNextHeader::Compressed
471 } else {
472 last_header
473 };
474
475 let ext_hdr = SixlowpanExtHeaderRepr {
476 ext_header_id: SixlowpanExtHeaderId::HopByHopHeader,
477 next_header,
478 length: hbh.options.iter().map(|o| o.buffer_len()).sum::<usize>() as u8,
479 };
480 ext_hdr.emit(&mut SixlowpanExtHeaderPacket::new_unchecked(
481 &mut buffer[..ext_hdr.buffer_len()],
482 ));
483 buffer = &mut buffer[ext_hdr.buffer_len()..];
484
485 for opt in &hbh.options {
486 opt.emit(&mut Ipv6Option::new_unchecked(
487 &mut buffer[..opt.buffer_len()],
488 ));
489
490 buffer = &mut buffer[opt.buffer_len()..];
491 }
492 }
493
494 #[cfg(feature = "proto-ipv6-routing")]
496 if let Some(routing) = &packet.routing {
497 let ext_hdr = SixlowpanExtHeaderRepr {
498 ext_header_id: SixlowpanExtHeaderId::RoutingHeader,
499 next_header,
500 length: routing.buffer_len() as u8,
501 };
502 ext_hdr.emit(&mut SixlowpanExtHeaderPacket::new_unchecked(
503 &mut buffer[..ext_hdr.buffer_len()],
504 ));
505 buffer = &mut buffer[ext_hdr.buffer_len()..];
506
507 routing.emit(&mut Ipv6RoutingHeader::new_unchecked(
508 &mut buffer[..routing.buffer_len()],
509 ));
510 buffer = &mut buffer[routing.buffer_len()..];
511 }
512
513 match &mut packet.payload {
514 IpPayload::Icmpv6(icmp_repr) => {
515 icmp_repr.emit(
516 &packet.header.src_addr,
517 &packet.header.dst_addr,
518 &mut Icmpv6Packet::new_unchecked(&mut buffer[..icmp_repr.buffer_len()]),
519 checksum_caps,
520 );
521 }
522 #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
523 IpPayload::Udp(udp_repr, payload) => {
524 let udp_repr = SixlowpanUdpNhcRepr(*udp_repr);
525 udp_repr.emit(
526 &mut SixlowpanUdpNhcPacket::new_unchecked(
527 &mut buffer[..udp_repr.header_len() + payload.len()],
528 ),
529 &iphc_repr.src_addr,
530 &iphc_repr.dst_addr,
531 payload.len(),
532 |buf| buf.copy_from_slice(payload),
533 checksum_caps,
534 );
535 }
536 #[cfg(feature = "socket-tcp")]
537 IpPayload::Tcp(tcp_repr) => {
538 tcp_repr.emit(
539 &mut TcpPacket::new_unchecked(&mut buffer[..tcp_repr.buffer_len()]),
540 &packet.header.src_addr.into(),
541 &packet.header.dst_addr.into(),
542 checksum_caps,
543 );
544 }
545 #[cfg(feature = "socket-raw")]
546 IpPayload::Raw(_raw) => todo!(),
547
548 #[allow(unreachable_patterns)]
549 _ => unreachable!(),
550 }
551 }
552
553 fn compressed_packet_size(
560 packet: &PacketV6,
561 ieee_repr: &Ieee802154Repr,
562 ) -> (usize, usize, usize) {
563 let last_header = packet.payload.as_sixlowpan_next_header();
564 let next_header = last_header;
565
566 #[cfg(feature = "proto-ipv6-hbh")]
567 let next_header = if packet.hop_by_hop.is_some() {
568 SixlowpanNextHeader::Compressed
569 } else {
570 next_header
571 };
572
573 #[cfg(feature = "proto-ipv6-routing")]
574 let next_header = if packet.routing.is_some() {
575 SixlowpanNextHeader::Compressed
576 } else {
577 next_header
578 };
579
580 let iphc = SixlowpanIphcRepr {
581 src_addr: packet.header.src_addr,
582 ll_src_addr: ieee_repr.src_addr,
583 dst_addr: packet.header.dst_addr,
584 ll_dst_addr: ieee_repr.dst_addr,
585 next_header,
586 hop_limit: packet.header.hop_limit,
587 ecn: None,
588 dscp: None,
589 flow_label: None,
590 };
591
592 let mut total_size = iphc.buffer_len();
593 let mut compressed_hdr_size = iphc.buffer_len();
594 let mut uncompressed_hdr_size = packet.header.buffer_len();
595
596 #[cfg(feature = "proto-ipv6-hbh")]
598 if let Some(hbh) = &packet.hop_by_hop {
599 #[allow(unused)]
600 let next_header = last_header;
601
602 #[cfg(feature = "proto-ipv6-routing")]
603 let next_header = if packet.routing.is_some() {
604 SixlowpanNextHeader::Compressed
605 } else {
606 last_header
607 };
608
609 let options_size = hbh.options.iter().map(|o| o.buffer_len()).sum::<usize>();
610
611 let ext_hdr = SixlowpanExtHeaderRepr {
612 ext_header_id: SixlowpanExtHeaderId::HopByHopHeader,
613 next_header,
614 length: hbh.buffer_len() as u8 + options_size as u8,
615 };
616
617 total_size += ext_hdr.buffer_len() + options_size;
618 compressed_hdr_size += ext_hdr.buffer_len() + options_size;
619 uncompressed_hdr_size += hbh.buffer_len() + options_size;
620 }
621
622 #[cfg(feature = "proto-ipv6-routing")]
624 if let Some(routing) = &packet.routing {
625 let ext_hdr = SixlowpanExtHeaderRepr {
626 ext_header_id: SixlowpanExtHeaderId::RoutingHeader,
627 next_header,
628 length: routing.buffer_len() as u8,
629 };
630 total_size += ext_hdr.buffer_len() + routing.buffer_len();
631 compressed_hdr_size += ext_hdr.buffer_len() + routing.buffer_len();
632 uncompressed_hdr_size += routing.buffer_len();
633 }
634
635 match packet.payload {
636 #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
637 IpPayload::Udp(udp_hdr, payload) => {
638 uncompressed_hdr_size += udp_hdr.header_len();
639
640 let udp_hdr = SixlowpanUdpNhcRepr(udp_hdr);
641 compressed_hdr_size += udp_hdr.header_len();
642
643 total_size += udp_hdr.header_len() + payload.len();
644 }
645 _ => {
646 total_size += packet.header.payload_len;
647 }
648 }
649
650 (total_size, compressed_hdr_size, uncompressed_hdr_size)
651 }
652
653 #[cfg(feature = "proto-sixlowpan-fragmentation")]
654 pub(super) fn dispatch_sixlowpan_frag<Tx: TxToken>(
655 &mut self,
656 tx_token: Tx,
657 ieee_repr: Ieee802154Repr,
658 frag: &mut Fragmenter,
659 ) {
660 let fragn = SixlowpanFragRepr::Fragment {
662 size: frag.sixlowpan.datagram_size,
663 tag: frag.sixlowpan.datagram_tag,
664 offset: (frag.sixlowpan.datagram_offset / 8) as u8,
665 };
666
667 let ieee_len = ieee_repr.buffer_len();
668 let frag_size = (frag.packet_len - frag.sent_bytes).min(frag.sixlowpan.fragn_size);
669
670 tx_token.consume(
671 ieee_repr.buffer_len() + fragn.buffer_len() + frag_size,
672 |mut tx_buf| {
673 let mut ieee_packet = Ieee802154Frame::new_unchecked(&mut tx_buf[..ieee_len]);
674 ieee_repr.emit(&mut ieee_packet);
675 tx_buf = &mut tx_buf[ieee_len..];
676
677 let mut frag_packet =
678 SixlowpanFragPacket::new_unchecked(&mut tx_buf[..fragn.buffer_len()]);
679 fragn.emit(&mut frag_packet);
680 tx_buf = &mut tx_buf[fragn.buffer_len()..];
681
682 tx_buf[..frag_size].copy_from_slice(&frag.buffer[frag.sent_bytes..][..frag_size]);
684
685 frag.sent_bytes += frag_size;
686 frag.sixlowpan.datagram_offset += frag_size;
687 },
688 );
689 }
690}
691
692#[inline]
694fn decompress_next_header(next_header: SixlowpanNextHeader, payload: &[u8]) -> Result<IpProtocol> {
695 match next_header {
696 SixlowpanNextHeader::Compressed => match SixlowpanNhcPacket::dispatch(payload)? {
697 SixlowpanNhcPacket::ExtHeader => {
698 let ext_hdr = SixlowpanExtHeaderPacket::new_checked(payload)?;
699 Ok(ext_hdr.extension_header_id().into())
700 }
701 SixlowpanNhcPacket::UdpHeader => Ok(IpProtocol::Udp),
702 },
703 SixlowpanNextHeader::Uncompressed(proto) => Ok(proto),
704 }
705}
706
707#[inline(always)]
709fn decompress_ext_hdr<'d>(
710 mut data: &'d [u8],
711 next_header: &mut Option<SixlowpanNextHeader>,
712 mut buffer: &'d mut [u8],
713 payload_len: &mut usize,
714 decompressed_len: &mut usize,
715) -> Result<(&'d mut [u8], &'d [u8])> {
716 let ext_hdr = SixlowpanExtHeaderPacket::new_checked(data)?;
717 let ext_repr = SixlowpanExtHeaderRepr::parse(&ext_hdr)?;
718 let nh = decompress_next_header(
719 ext_repr.next_header,
720 &data[ext_repr.length as usize + ext_repr.buffer_len()..],
721 )?;
722 *next_header = Some(ext_repr.next_header);
723 let ipv6_ext_hdr = Ipv6ExtHeaderRepr {
724 next_header: nh,
725 length: ext_repr.length / 8,
726 data: ext_hdr.payload(),
727 };
728 if ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len() > buffer.len() {
729 return Err(Error);
730 }
731 ipv6_ext_hdr.emit(&mut Ipv6ExtHeader::new_unchecked(
732 &mut buffer[..ipv6_ext_hdr.header_len()],
733 ));
734 buffer[ipv6_ext_hdr.header_len()..][..ipv6_ext_hdr.data.len()]
735 .copy_from_slice(ipv6_ext_hdr.data);
736 buffer = &mut buffer[ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len()..];
737 *payload_len += ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len();
738 *decompressed_len += ipv6_ext_hdr.header_len() + ipv6_ext_hdr.data.len();
739 data = &data[ext_repr.buffer_len() + ext_repr.length as usize..];
740 Ok((buffer, data))
741}
742
743#[inline(always)]
745fn decompress_udp(
746 data: &[u8],
747 iphc_repr: &SixlowpanIphcRepr,
748 buffer: &mut [u8],
749 total_len: Option<usize>,
750 payload_len: &mut usize,
751 decompressed_len: &mut usize,
752) -> Result<()> {
753 let udp_packet = SixlowpanUdpNhcPacket::new_checked(data)?;
754 let payload = udp_packet.payload();
755 let udp_repr = SixlowpanUdpNhcRepr::parse(
756 &udp_packet,
757 &iphc_repr.src_addr,
758 &iphc_repr.dst_addr,
759 &ChecksumCapabilities::ignored(),
760 )?;
761 if udp_repr.header_len() + payload.len() > buffer.len() {
762 return Err(Error);
763 }
764 let udp_payload_len = if let Some(total_len) = total_len {
765 total_len - *payload_len - 8
766 } else {
767 payload.len()
768 };
769 *payload_len += udp_payload_len + 8;
770 *decompressed_len += udp_repr.0.header_len() + payload.len();
771 let mut udp = UdpPacket::new_unchecked(&mut buffer[..payload.len() + 8]);
772 udp_repr.0.emit_header(&mut udp, udp_payload_len);
773 buffer[8..][..payload.len()].copy_from_slice(payload);
774 Ok(())
775}
776
777#[cfg(test)]
778#[cfg(all(feature = "proto-rpl", feature = "proto-ipv6-hbh"))]
779mod tests {
780 use super::*;
781
782 static SIXLOWPAN_COMPRESSED_RPL_DAO: [u8; 99] = [
783 0x61, 0xdc, 0x45, 0xcd, 0xab, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00,
784 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x7e, 0xf7, 0x00, 0xe0, 0x3a, 0x06, 0x63, 0x04, 0x00,
785 0x1e, 0x08, 0x00, 0x9b, 0x02, 0x3e, 0x63, 0x1e, 0x40, 0x00, 0xf1, 0xfd, 0x00, 0x00, 0x00,
786 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x05, 0x12, 0x00,
787 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x03, 0x00, 0x03,
788 0x00, 0x03, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1e, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
789 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
790 ];
791
792 static SIXLOWPAN_UNCOMPRESSED_RPL_DAO: [u8; 114] = [
793 0x60, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x40, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794 0x00, 0x02, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00,
795 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x3a, 0x00, 0x63, 0x04, 0x00,
796 0x1e, 0x08, 0x00, 0x9b, 0x02, 0x3e, 0x63, 0x1e, 0x40, 0x00, 0xf1, 0xfd, 0x00, 0x00, 0x00,
797 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x05, 0x12, 0x00,
798 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x03, 0x00, 0x03,
799 0x00, 0x03, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1e, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
800 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
801 ];
802
803 #[test]
804 fn test_sixlowpan_decompress_hop_by_hop_with_icmpv6() {
805 let address_context = [SixlowpanAddressContext([
806 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
807 ])];
808
809 let ieee_frame = Ieee802154Frame::new_checked(&SIXLOWPAN_COMPRESSED_RPL_DAO).unwrap();
810 let ieee_repr = Ieee802154Repr::parse(&ieee_frame).unwrap();
811
812 let mut buffer = [0u8; 256];
813 let len = InterfaceInner::sixlowpan_to_ipv6(
814 &address_context,
815 &ieee_repr,
816 ieee_frame.payload().unwrap(),
817 None,
818 &mut buffer[..],
819 )
820 .unwrap();
821
822 assert_eq!(&buffer[..len], &SIXLOWPAN_UNCOMPRESSED_RPL_DAO);
823 }
824
825 #[test]
826 fn test_sixlowpan_compress_hop_by_hop_with_icmpv6() {
827 let ieee_repr = Ieee802154Repr {
828 frame_type: Ieee802154FrameType::Data,
829 security_enabled: false,
830 frame_pending: false,
831 ack_request: true,
832 sequence_number: Some(69),
833 pan_id_compression: true,
834 frame_version: Ieee802154FrameVersion::Ieee802154_2006,
835 dst_pan_id: Some(Ieee802154Pan(43981)),
836 dst_addr: Some(Ieee802154Address::Extended([0, 1, 0, 1, 0, 1, 0, 1])),
837 src_pan_id: None,
838 src_addr: Some(Ieee802154Address::Extended([0, 3, 0, 3, 0, 3, 0, 3])),
839 };
840
841 let mut ip_packet = PacketV6 {
842 header: Ipv6Repr {
843 src_addr: Ipv6Address::from_octets([
844 253, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 3, 0, 3, 0, 3,
845 ]),
846 dst_addr: Ipv6Address::from_octets([
847 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
848 ]),
849 next_header: IpProtocol::Icmpv6,
850 payload_len: 66,
851 hop_limit: 64,
852 },
853 #[cfg(feature = "proto-ipv6-hbh")]
854 hop_by_hop: None,
855 #[cfg(feature = "proto-ipv6-fragmentation")]
856 fragment: None,
857 #[cfg(feature = "proto-ipv6-routing")]
858 routing: None,
859 payload: IpPayload::Icmpv6(Icmpv6Repr::Rpl(RplRepr::DestinationAdvertisementObject {
860 rpl_instance_id: RplInstanceId::Global(30),
861 expect_ack: false,
862 sequence: 241,
863 dodag_id: Some(Ipv6Address::from_octets([
864 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
865 ])),
866 options: &[],
867 })),
868 };
869
870 let (total_size, _, _) = InterfaceInner::compressed_packet_size(&mut ip_packet, &ieee_repr);
871 let mut buffer = vec![0u8; total_size];
872
873 InterfaceInner::ipv6_to_sixlowpan(
874 &ChecksumCapabilities::default(),
875 ip_packet,
876 &ieee_repr,
877 &mut buffer[..total_size],
878 );
879
880 let result = [
881 0x7e, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3, 0x0, 0x3, 0x0,
882 0x3, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
883 0xe0, 0x3a, 0x6, 0x63, 0x4, 0x0, 0x1e, 0x3, 0x0, 0x9b, 0x2, 0x3e, 0x63, 0x1e, 0x40,
884 0x0, 0xf1, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0,
885 0x1, 0x5, 0x12, 0x0, 0x80, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3,
886 0x0, 0x3, 0x0, 0x3, 0x6, 0x14, 0x0, 0x0, 0x0, 0x1e, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
887 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
888 ];
889
890 assert_eq!(&result, &result);
891 }
892
893 #[test]
894 fn test_sixlowpan_compress_hop_by_hop_with_udp() {
895 let ieee_repr = Ieee802154Repr {
896 frame_type: Ieee802154FrameType::Data,
897 security_enabled: false,
898 frame_pending: false,
899 ack_request: true,
900 sequence_number: Some(69),
901 pan_id_compression: true,
902 frame_version: Ieee802154FrameVersion::Ieee802154_2006,
903 dst_pan_id: Some(Ieee802154Pan(43981)),
904 dst_addr: Some(Ieee802154Address::Extended([0, 1, 0, 1, 0, 1, 0, 1])),
905 src_pan_id: None,
906 src_addr: Some(Ieee802154Address::Extended([0, 3, 0, 3, 0, 3, 0, 3])),
907 };
908
909 let addr = Ipv6Address::from_octets([253, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 3, 0, 3, 0, 3]);
910 let parent_address =
911 Ipv6Address::from_octets([253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1]);
912
913 let mut hbh_options = heapless::Vec::new();
914 hbh_options
915 .push(Ipv6OptionRepr::Rpl(RplHopByHopRepr {
916 down: false,
917 rank_error: false,
918 forwarding_error: false,
919 instance_id: RplInstanceId::from(0x1e),
920 sender_rank: 0x300,
921 }))
922 .unwrap();
923
924 let mut ip_packet = PacketV6 {
925 header: Ipv6Repr {
926 src_addr: addr,
927 dst_addr: parent_address,
928 next_header: IpProtocol::Icmpv6,
929 payload_len: 66,
930 hop_limit: 64,
931 },
932 #[cfg(feature = "proto-ipv6-hbh")]
933 hop_by_hop: Some(Ipv6HopByHopRepr {
934 options: hbh_options,
935 }),
936 #[cfg(feature = "proto-ipv6-fragmentation")]
937 fragment: None,
938 #[cfg(feature = "proto-ipv6-routing")]
939 routing: None,
940 payload: IpPayload::Icmpv6(Icmpv6Repr::Rpl(RplRepr::DestinationAdvertisementObject {
941 rpl_instance_id: RplInstanceId::Global(30),
942 expect_ack: false,
943 sequence: 241,
944 dodag_id: Some(Ipv6Address::from_octets([
945 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
946 ])),
947 options: &[
948 5, 18, 0, 128, 253, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 3, 0, 3, 0, 3, 6, 20, 0, 0,
949 0, 30, 253, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 1, 0, 1,
950 ],
951 })),
952 };
953
954 let (total_size, _, _) = InterfaceInner::compressed_packet_size(&mut ip_packet, &ieee_repr);
955 let mut buffer = vec![0u8; total_size];
956
957 InterfaceInner::ipv6_to_sixlowpan(
958 &ChecksumCapabilities::default(),
959 ip_packet,
960 &ieee_repr,
961 &mut buffer[..total_size],
962 );
963
964 let result = [
965 0x7e, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3, 0x0, 0x3, 0x0,
966 0x3, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
967 0xe0, 0x3a, 0x6, 0x63, 0x4, 0x0, 0x1e, 0x3, 0x0, 0x9b, 0x2, 0x3e, 0x63, 0x1e, 0x40,
968 0x0, 0xf1, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0,
969 0x1, 0x5, 0x12, 0x0, 0x80, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x0, 0x3,
970 0x0, 0x3, 0x0, 0x3, 0x6, 0x14, 0x0, 0x0, 0x0, 0x1e, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
971 0x0, 0x2, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1,
972 ];
973
974 assert_eq!(&buffer[..total_size], &result);
975 }
976}