1use super::{
7 AddressContext, AddressMode, Error, NextHeader, Result, UnresolvedAddress, DISPATCH_IPHC_HEADER,
8};
9use crate::wire::{ieee802154::Address as LlAddress, ipv6, ipv6::AddressExt, IpProtocol};
10use byteorder::{ByteOrder, NetworkEndian};
11
12mod field {
13 use crate::wire::field::*;
14
15 pub const IPHC_FIELD: Field = 0..2;
16}
17
18macro_rules! get_field {
19 ($name:ident, $mask:expr, $shift:expr) => {
20 fn $name(&self) -> u8 {
21 let data = self.buffer.as_ref();
22 let raw = NetworkEndian::read_u16(&data[field::IPHC_FIELD]);
23 ((raw >> $shift) & $mask) as u8
24 }
25 };
26}
27
28macro_rules! set_field {
29 ($name:ident, $mask:expr, $shift:expr) => {
30 fn $name(&mut self, val: u8) {
31 let data = &mut self.buffer.as_mut()[field::IPHC_FIELD];
32 let mut raw = NetworkEndian::read_u16(data);
33
34 raw = (raw & !($mask << $shift)) | ((val as u16) << $shift);
35 NetworkEndian::write_u16(data, raw);
36 }
37 };
38}
39
40#[derive(Debug, Clone)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub struct Packet<T: AsRef<[u8]>> {
74 buffer: T,
75}
76
77impl<T: AsRef<[u8]>> Packet<T> {
78 pub const fn new_unchecked(buffer: T) -> Self {
80 Packet { buffer }
81 }
82
83 pub fn new_checked(buffer: T) -> Result<Self> {
88 let packet = Self::new_unchecked(buffer);
89 packet.check_len()?;
90 Ok(packet)
91 }
92
93 pub fn check_len(&self) -> Result<()> {
96 let buffer = self.buffer.as_ref();
97 if buffer.len() < 2 {
98 return Err(Error);
99 }
100
101 let mut offset = self.ip_fields_start()
102 + self.traffic_class_size()
103 + self.next_header_size()
104 + self.hop_limit_size();
105 offset += self.src_address_size();
106 offset += self.dst_address_size();
107
108 if offset as usize > buffer.len() {
109 return Err(Error);
110 }
111
112 Ok(())
113 }
114
115 pub fn into_inner(self) -> T {
117 self.buffer
118 }
119
120 pub fn next_header(&self) -> NextHeader {
122 let nh = self.nh_field();
123
124 if nh == 1 {
125 NextHeader::Compressed
128 } else {
129 let start = (self.ip_fields_start() + self.traffic_class_size()) as usize;
131
132 let data = self.buffer.as_ref();
133 let nh = data[start..start + 1][0];
134 NextHeader::Uncompressed(IpProtocol::from(nh))
135 }
136 }
137
138 pub fn hop_limit(&self) -> u8 {
140 match self.hlim_field() {
141 0b00 => {
142 let start = (self.ip_fields_start()
143 + self.traffic_class_size()
144 + self.next_header_size()) as usize;
145
146 let data = self.buffer.as_ref();
147 data[start..start + 1][0]
148 }
149 0b01 => 1,
150 0b10 => 64,
151 0b11 => 255,
152 _ => unreachable!(),
153 }
154 }
155
156 pub fn src_context_id(&self) -> Option<u8> {
158 if self.cid_field() == 1 {
159 let data = self.buffer.as_ref();
160 Some(data[2] >> 4)
161 } else {
162 None
163 }
164 }
165
166 pub fn dst_context_id(&self) -> Option<u8> {
168 if self.cid_field() == 1 {
169 let data = self.buffer.as_ref();
170 Some(data[2] & 0x0f)
171 } else {
172 None
173 }
174 }
175
176 pub fn ecn_field(&self) -> Option<u8> {
178 match self.tf_field() {
179 0b00..=0b10 => {
180 let start = self.ip_fields_start() as usize;
181 Some(self.buffer.as_ref()[start..][0] & 0b1100_0000)
182 }
183 0b11 => None,
184 _ => unreachable!(),
185 }
186 }
187
188 pub fn dscp_field(&self) -> Option<u8> {
190 match self.tf_field() {
191 0b00 | 0b10 => {
192 let start = self.ip_fields_start() as usize;
193 Some(self.buffer.as_ref()[start..][0] & 0b111111)
194 }
195 0b01 | 0b11 => None,
196 _ => unreachable!(),
197 }
198 }
199
200 pub fn flow_label_field(&self) -> Option<u16> {
202 match self.tf_field() {
203 0b00 => {
204 let start = self.ip_fields_start() as usize;
205 Some(NetworkEndian::read_u16(
206 &self.buffer.as_ref()[start..][2..4],
207 ))
208 }
209 0b01 => {
210 let start = self.ip_fields_start() as usize;
211 Some(NetworkEndian::read_u16(
212 &self.buffer.as_ref()[start..][1..3],
213 ))
214 }
215 0b10 | 0b11 => None,
216 _ => unreachable!(),
217 }
218 }
219
220 pub fn src_addr(&self) -> Result<UnresolvedAddress> {
222 let start = (self.ip_fields_start()
223 + self.traffic_class_size()
224 + self.next_header_size()
225 + self.hop_limit_size()) as usize;
226
227 let data = self.buffer.as_ref();
228 match (self.sac_field(), self.sam_field()) {
229 (0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
230 &data[start..][..16],
231 ))),
232 (0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
233 AddressMode::InLine64bits(&data[start..][..8]),
234 )),
235 (0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
236 AddressMode::InLine16bits(&data[start..][..2]),
237 )),
238 (0, 0b11) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullyElided)),
239 (1, 0b00) => Ok(UnresolvedAddress::WithContext((
240 0,
241 AddressMode::Unspecified,
242 ))),
243 (1, 0b01) => {
244 if let Some(id) = self.src_context_id() {
245 Ok(UnresolvedAddress::WithContext((
246 id as usize,
247 AddressMode::InLine64bits(&data[start..][..8]),
248 )))
249 } else {
250 Err(Error)
251 }
252 }
253 (1, 0b10) => {
254 if let Some(id) = self.src_context_id() {
255 Ok(UnresolvedAddress::WithContext((
256 id as usize,
257 AddressMode::InLine16bits(&data[start..][..2]),
258 )))
259 } else {
260 Err(Error)
261 }
262 }
263 (1, 0b11) => {
264 if let Some(id) = self.src_context_id() {
265 Ok(UnresolvedAddress::WithContext((
266 id as usize,
267 AddressMode::FullyElided,
268 )))
269 } else {
270 Err(Error)
271 }
272 }
273 _ => Err(Error),
274 }
275 }
276
277 pub fn dst_addr(&self) -> Result<UnresolvedAddress> {
279 let start = (self.ip_fields_start()
280 + self.traffic_class_size()
281 + self.next_header_size()
282 + self.hop_limit_size()
283 + self.src_address_size()) as usize;
284
285 let data = self.buffer.as_ref();
286 match (self.m_field(), self.dac_field(), self.dam_field()) {
287 (0, 0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
288 &data[start..][..16],
289 ))),
290 (0, 0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
291 AddressMode::InLine64bits(&data[start..][..8]),
292 )),
293 (0, 0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
294 AddressMode::InLine16bits(&data[start..][..2]),
295 )),
296 (0, 0, 0b11) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullyElided)),
297 (0, 1, 0b00) => Ok(UnresolvedAddress::Reserved),
298 (0, 1, 0b01) => {
299 if let Some(id) = self.dst_context_id() {
300 Ok(UnresolvedAddress::WithContext((
301 id as usize,
302 AddressMode::InLine64bits(&data[start..][..8]),
303 )))
304 } else {
305 Err(Error)
306 }
307 }
308 (0, 1, 0b10) => {
309 if let Some(id) = self.dst_context_id() {
310 Ok(UnresolvedAddress::WithContext((
311 id as usize,
312 AddressMode::InLine16bits(&data[start..][..2]),
313 )))
314 } else {
315 Err(Error)
316 }
317 }
318 (0, 1, 0b11) => {
319 if let Some(id) = self.dst_context_id() {
320 Ok(UnresolvedAddress::WithContext((
321 id as usize,
322 AddressMode::FullyElided,
323 )))
324 } else {
325 Err(Error)
326 }
327 }
328 (1, 0, 0b00) => Ok(UnresolvedAddress::WithoutContext(AddressMode::FullInline(
329 &data[start..][..16],
330 ))),
331 (1, 0, 0b01) => Ok(UnresolvedAddress::WithoutContext(
332 AddressMode::Multicast48bits(&data[start..][..6]),
333 )),
334 (1, 0, 0b10) => Ok(UnresolvedAddress::WithoutContext(
335 AddressMode::Multicast32bits(&data[start..][..4]),
336 )),
337 (1, 0, 0b11) => Ok(UnresolvedAddress::WithoutContext(
338 AddressMode::Multicast8bits(&data[start..][..1]),
339 )),
340 (1, 1, 0b00) => Ok(UnresolvedAddress::WithContext((
341 0,
342 AddressMode::NotSupported,
343 ))),
344 (1, 1, 0b01..=0b11) => Ok(UnresolvedAddress::Reserved),
345 _ => Err(Error),
346 }
347 }
348
349 get_field!(dispatch_field, 0b111, 13);
350 get_field!(tf_field, 0b11, 11);
351 get_field!(nh_field, 0b1, 10);
352 get_field!(hlim_field, 0b11, 8);
353 get_field!(cid_field, 0b1, 7);
354 get_field!(sac_field, 0b1, 6);
355 get_field!(sam_field, 0b11, 4);
356 get_field!(m_field, 0b1, 3);
357 get_field!(dac_field, 0b1, 2);
358 get_field!(dam_field, 0b11, 0);
359
360 fn ip_fields_start(&self) -> u8 {
362 2 + self.cid_size()
363 }
364
365 fn traffic_class_size(&self) -> u8 {
367 match self.tf_field() {
368 0b00 => 4,
369 0b01 => 3,
370 0b10 => 1,
371 0b11 => 0,
372 _ => unreachable!(),
373 }
374 }
375
376 fn next_header_size(&self) -> u8 {
378 (self.nh_field() != 1) as u8
379 }
380
381 fn hop_limit_size(&self) -> u8 {
383 (self.hlim_field() == 0b00) as u8
384 }
385
386 fn cid_size(&self) -> u8 {
388 (self.cid_field() == 1) as u8
389 }
390
391 fn src_address_size(&self) -> u8 {
393 match (self.sac_field(), self.sam_field()) {
394 (0, 0b00) => 16, (0, 0b01) => 8, (0, 0b10) => 2, (0, 0b11) => 0, (1, 0b00) => 0, (1, 0b01) => 8, (1, 0b10) => 2, (1, 0b11) => 0, _ => unreachable!(),
403 }
404 }
405
406 fn dst_address_size(&self) -> u8 {
408 match (self.m_field(), self.dac_field(), self.dam_field()) {
409 (0, 0, 0b00) => 16, (0, 0, 0b01) => 8, (0, 0, 0b10) => 2, (0, 0, 0b11) => 0, (0, 1, 0b00) => 0, (0, 1, 0b01) => 8, (0, 1, 0b10) => 2, (0, 1, 0b11) => 0, (1, 0, 0b00) => 16, (1, 0, 0b01) => 6, (1, 0, 0b10) => 4, (1, 0, 0b11) => 1, (1, 1, 0b00) => 6, (1, 1, 0b01) => 0, (1, 1, 0b10) => 0, (1, 1, 0b11) => 0, _ => unreachable!(),
426 }
427 }
428
429 pub fn header_len(&self) -> usize {
431 let mut len = self.ip_fields_start();
432 len += self.traffic_class_size();
433 len += self.next_header_size();
434 len += self.hop_limit_size();
435 len += self.src_address_size();
436 len += self.dst_address_size();
437
438 len as usize
439 }
440}
441
442impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
443 pub fn payload(&self) -> &'a [u8] {
445 let mut len = self.ip_fields_start();
446 len += self.traffic_class_size();
447 len += self.next_header_size();
448 len += self.hop_limit_size();
449 len += self.src_address_size();
450 len += self.dst_address_size();
451
452 let len = len as usize;
453
454 let data = self.buffer.as_ref();
455 &data[len..]
456 }
457}
458
459impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
460 fn set_dispatch_field(&mut self) {
462 let data = &mut self.buffer.as_mut()[field::IPHC_FIELD];
463 let mut raw = NetworkEndian::read_u16(data);
464
465 raw = (raw & !(0b111 << 13)) | (0b11 << 13);
466 NetworkEndian::write_u16(data, raw);
467 }
468
469 set_field!(set_tf_field, 0b11, 11);
470 set_field!(set_nh_field, 0b1, 10);
471 set_field!(set_hlim_field, 0b11, 8);
472 set_field!(set_cid_field, 0b1, 7);
473 set_field!(set_sac_field, 0b1, 6);
474 set_field!(set_sam_field, 0b11, 4);
475 set_field!(set_m_field, 0b1, 3);
476 set_field!(set_dac_field, 0b1, 2);
477 set_field!(set_dam_field, 0b11, 0);
478
479 fn set_field(&mut self, idx: usize, value: &[u8]) {
480 let raw = self.buffer.as_mut();
481 raw[idx..idx + value.len()].copy_from_slice(value);
482 }
483
484 fn set_next_header(&mut self, nh: NextHeader, mut idx: usize) -> usize {
488 match nh {
489 NextHeader::Uncompressed(nh) => {
490 self.set_nh_field(0);
491 self.set_field(idx, &[nh.into()]);
492 idx += 1;
493 }
494 NextHeader::Compressed => self.set_nh_field(1),
495 }
496
497 idx
498 }
499
500 fn set_hop_limit(&mut self, hl: u8, mut idx: usize) -> usize {
504 match hl {
505 255 => self.set_hlim_field(0b11),
506 64 => self.set_hlim_field(0b10),
507 1 => self.set_hlim_field(0b01),
508 _ => {
509 self.set_hlim_field(0b00);
510 self.set_field(idx, &[hl]);
511 idx += 1;
512 }
513 }
514
515 idx
516 }
517
518 fn set_src_address(
522 &mut self,
523 src_addr: ipv6::Address,
524 ll_src_addr: Option<LlAddress>,
525 mut idx: usize,
526 ) -> usize {
527 self.set_cid_field(0);
528 self.set_sac_field(0);
529 let src = src_addr.octets();
530 if src_addr == ipv6::Address::UNSPECIFIED {
531 self.set_sac_field(1);
532 self.set_sam_field(0b00);
533 } else if src_addr.is_link_local() {
534 let is_eui_64 = ll_src_addr
539 .map(|addr| {
540 addr.as_eui_64()
541 .map(|addr| addr[..] == src[8..])
542 .unwrap_or(false)
543 })
544 .unwrap_or(false);
545
546 if src[8..14] == [0, 0, 0, 0xff, 0xfe, 0] {
547 let ll = [src[14], src[15]];
548
549 if ll_src_addr == Some(LlAddress::Short(ll)) {
550 self.set_sam_field(0b11);
554 } else {
555 self.set_sam_field(0b10);
558
559 self.set_field(idx, &src[14..]);
560 idx += 2;
561 }
562 } else if is_eui_64 {
563 self.set_sam_field(0b11);
567 } else {
568 self.set_sam_field(0b01);
570
571 self.set_field(idx, &src[8..]);
572 idx += 8;
573 }
574 } else {
575 self.set_sam_field(0b00);
577 self.set_field(idx, &src);
578 idx += 16;
579 }
580
581 idx
582 }
583
584 fn set_dst_address(
588 &mut self,
589 dst_addr: ipv6::Address,
590 ll_dst_addr: Option<LlAddress>,
591 mut idx: usize,
592 ) -> usize {
593 self.set_dac_field(0);
594 self.set_dam_field(0);
595 self.set_m_field(0);
596 let dst = dst_addr.octets();
597 if dst_addr.is_multicast() {
598 self.set_m_field(1);
599
600 if dst[1] == 0x02 && dst[2..15] == [0; 13] {
601 self.set_dam_field(0b11);
602
603 self.set_field(idx, &[dst[15]]);
604 idx += 1;
605 } else if dst[2..13] == [0; 11] {
606 self.set_dam_field(0b10);
607
608 self.set_field(idx, &[dst[1]]);
609 idx += 1;
610 self.set_field(idx, &dst[13..]);
611 idx += 3;
612 } else if dst[2..11] == [0; 9] {
613 self.set_dam_field(0b01);
614
615 self.set_field(idx, &[dst[1]]);
616 idx += 1;
617 self.set_field(idx, &dst[11..]);
618 idx += 5;
619 } else {
620 self.set_dam_field(0b11);
621
622 self.set_field(idx, &dst);
623 idx += 16;
624 }
625 } else if dst_addr.is_link_local() {
626 let is_eui_64 = ll_dst_addr
627 .map(|addr| {
628 addr.as_eui_64()
629 .map(|addr| addr[..] == dst[8..])
630 .unwrap_or(false)
631 })
632 .unwrap_or(false);
633
634 if dst[8..14] == [0, 0, 0, 0xff, 0xfe, 0] {
635 let ll = [dst[14], dst[15]];
636
637 if ll_dst_addr == Some(LlAddress::Short(ll)) {
638 self.set_dam_field(0b11);
639 } else {
640 self.set_dam_field(0b10);
641
642 self.set_field(idx, &dst[14..]);
643 idx += 2;
644 }
645 } else if is_eui_64 {
646 self.set_dam_field(0b11);
647 } else {
648 self.set_dam_field(0b01);
649
650 self.set_field(idx, &dst[8..]);
651 idx += 8;
652 }
653 } else {
654 self.set_dam_field(0b00);
655
656 self.set_field(idx, &dst);
657 idx += 16;
658 }
659
660 idx
661 }
662
663 pub fn payload_mut(&mut self) -> &mut [u8] {
665 let mut len = self.ip_fields_start();
666
667 len += self.traffic_class_size();
668 len += self.next_header_size();
669 len += self.hop_limit_size();
670 len += self.src_address_size();
671 len += self.dst_address_size();
672
673 let len = len as usize;
674
675 let data = self.buffer.as_mut();
676 &mut data[len..]
677 }
678}
679
680#[derive(Debug, PartialEq, Eq, Clone, Copy)]
682pub struct Repr {
683 pub src_addr: ipv6::Address,
684 pub ll_src_addr: Option<LlAddress>,
685 pub dst_addr: ipv6::Address,
686 pub ll_dst_addr: Option<LlAddress>,
687 pub next_header: NextHeader,
688 pub hop_limit: u8,
689 pub ecn: Option<u8>,
691 pub dscp: Option<u8>,
692 pub flow_label: Option<u16>,
693}
694
695impl core::fmt::Display for Repr {
696 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
697 write!(
698 f,
699 "IPHC src={} dst={} nxt-hdr={} hop-limit={}",
700 self.src_addr, self.dst_addr, self.next_header, self.hop_limit
701 )
702 }
703}
704
705#[cfg(feature = "defmt")]
706impl defmt::Format for Repr {
707 fn format(&self, fmt: defmt::Formatter) {
708 defmt::write!(
709 fmt,
710 "IPHC src={} dst={} nxt-hdr={} hop-limit={}",
711 self.src_addr,
712 self.dst_addr,
713 self.next_header,
714 self.hop_limit
715 );
716 }
717}
718
719impl Repr {
720 pub fn parse<T: AsRef<[u8]> + ?Sized>(
725 packet: &Packet<&T>,
726 ll_src_addr: Option<LlAddress>,
727 ll_dst_addr: Option<LlAddress>,
728 addr_context: &[AddressContext],
729 ) -> Result<Self> {
730 packet.check_len()?;
732
733 if packet.dispatch_field() != DISPATCH_IPHC_HEADER {
734 return Err(Error);
736 }
737
738 let src_addr = packet.src_addr()?.resolve(ll_src_addr, addr_context)?;
739 let dst_addr = packet.dst_addr()?.resolve(ll_dst_addr, addr_context)?;
740
741 Ok(Self {
742 src_addr,
743 ll_src_addr,
744 dst_addr,
745 ll_dst_addr,
746 next_header: packet.next_header(),
747 hop_limit: packet.hop_limit(),
748 ecn: packet.ecn_field(),
749 dscp: packet.dscp_field(),
750 flow_label: packet.flow_label_field(),
751 })
752 }
753
754 pub fn buffer_len(&self) -> usize {
756 let mut len = 0;
757 len += 2; len += match self.next_header {
760 NextHeader::Compressed => 0, NextHeader::Uncompressed(_) => 1, };
763
764 len += match self.hop_limit {
766 255 | 64 | 1 => 0, _ => 1,
768 };
769
770 len += if self.src_addr == ipv6::Address::UNSPECIFIED {
772 0
773 } else if self.src_addr.is_link_local() {
774 let src = self.src_addr.octets();
775 let ll = [src[14], src[15]];
776
777 let is_eui_64 = self
778 .ll_src_addr
779 .map(|addr| {
780 addr.as_eui_64()
781 .map(|addr| addr[..] == src[8..])
782 .unwrap_or(false)
783 })
784 .unwrap_or(false);
785
786 if src[8..14] == [0, 0, 0, 0xff, 0xfe, 0] {
787 if self.ll_src_addr == Some(LlAddress::Short(ll)) {
788 0
789 } else {
790 2
791 }
792 } else if is_eui_64 {
793 0
794 } else {
795 8
796 }
797 } else {
798 16
799 };
800
801 let dst = self.dst_addr.octets();
803 len += if self.dst_addr.is_multicast() {
804 if dst[1] == 0x02 && dst[2..15] == [0; 13] {
805 1
806 } else if dst[2..13] == [0; 11] {
807 4
808 } else if dst[2..11] == [0; 9] {
809 6
810 } else {
811 16
812 }
813 } else if self.dst_addr.is_link_local() {
814 let is_eui_64 = self
815 .ll_dst_addr
816 .map(|addr| {
817 addr.as_eui_64()
818 .map(|addr| addr[..] == dst[8..])
819 .unwrap_or(false)
820 })
821 .unwrap_or(false);
822
823 if dst[8..14] == [0, 0, 0, 0xff, 0xfe, 0] {
824 let ll = [dst[14], dst[15]];
825
826 if self.ll_dst_addr == Some(LlAddress::Short(ll)) {
827 0
828 } else {
829 2
830 }
831 } else if is_eui_64 {
832 0
833 } else {
834 8
835 }
836 } else {
837 16
838 };
839
840 len += match (self.ecn, self.dscp, self.flow_label) {
841 (Some(_), Some(_), Some(_)) => 4,
842 (Some(_), None, Some(_)) => 3,
843 (Some(_), Some(_), None) => 1,
844 (None, None, None) => 0,
845 _ => unreachable!(),
846 };
847
848 len
849 }
850
851 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
853 let idx = 2;
854
855 packet.set_dispatch_field();
856
857 packet.set_tf_field(0b11);
859
860 let idx = packet.set_next_header(self.next_header, idx);
861 let idx = packet.set_hop_limit(self.hop_limit, idx);
862 let idx = packet.set_src_address(self.src_addr, self.ll_src_addr, idx);
863 packet.set_dst_address(self.dst_addr, self.ll_dst_addr, idx);
864 }
865}
866
867#[cfg(test)]
868mod test {
869 use super::*;
870
871 #[test]
872 fn iphc_fields() {
873 let bytes = [
874 0x7a, 0x33, 0x3a, ];
877
878 let packet = Packet::new_unchecked(bytes);
879
880 assert_eq!(packet.dispatch_field(), 0b011);
881 assert_eq!(packet.tf_field(), 0b11);
882 assert_eq!(packet.nh_field(), 0b0);
883 assert_eq!(packet.hlim_field(), 0b10);
884 assert_eq!(packet.cid_field(), 0b0);
885 assert_eq!(packet.sac_field(), 0b0);
886 assert_eq!(packet.sam_field(), 0b11);
887 assert_eq!(packet.m_field(), 0b0);
888 assert_eq!(packet.dac_field(), 0b0);
889 assert_eq!(packet.dam_field(), 0b11);
890
891 assert_eq!(
892 packet.next_header(),
893 NextHeader::Uncompressed(IpProtocol::Icmpv6)
894 );
895
896 assert_eq!(packet.src_address_size(), 0);
897 assert_eq!(packet.dst_address_size(), 0);
898 assert_eq!(packet.hop_limit(), 64);
899
900 assert_eq!(
901 packet.src_addr(),
902 Ok(UnresolvedAddress::WithoutContext(AddressMode::FullyElided))
903 );
904 assert_eq!(
905 packet.dst_addr(),
906 Ok(UnresolvedAddress::WithoutContext(AddressMode::FullyElided))
907 );
908
909 let bytes = [
910 0x7e, 0xf7, 0x00, ];
913
914 let packet = Packet::new_unchecked(bytes);
915
916 assert_eq!(packet.dispatch_field(), 0b011);
917 assert_eq!(packet.tf_field(), 0b11);
918 assert_eq!(packet.nh_field(), 0b1);
919 assert_eq!(packet.hlim_field(), 0b10);
920 assert_eq!(packet.cid_field(), 0b1);
921 assert_eq!(packet.sac_field(), 0b1);
922 assert_eq!(packet.sam_field(), 0b11);
923 assert_eq!(packet.m_field(), 0b0);
924 assert_eq!(packet.dac_field(), 0b1);
925 assert_eq!(packet.dam_field(), 0b11);
926
927 assert_eq!(packet.next_header(), NextHeader::Compressed);
928
929 assert_eq!(packet.src_address_size(), 0);
930 assert_eq!(packet.dst_address_size(), 0);
931 assert_eq!(packet.hop_limit(), 64);
932
933 assert_eq!(
934 packet.src_addr(),
935 Ok(UnresolvedAddress::WithContext((
936 0,
937 AddressMode::FullyElided
938 )))
939 );
940 assert_eq!(
941 packet.dst_addr(),
942 Ok(UnresolvedAddress::WithContext((
943 0,
944 AddressMode::FullyElided
945 )))
946 );
947 }
948}