Skip to main content

trippy_packet/
icmpv6.rs

1use crate::buffer::Buffer;
2use crate::error::{Error, Result};
3use std::fmt::{Debug, Formatter};
4
5/// The type of `ICMPv6` packet.
6#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
7pub enum IcmpType {
8    EchoRequest,
9    EchoReply,
10    DestinationUnreachable,
11    TimeExceeded,
12    Other(u8),
13}
14
15impl IcmpType {
16    #[must_use]
17    pub const fn id(&self) -> u8 {
18        match self {
19            Self::EchoRequest => 128,
20            Self::EchoReply => 129,
21            Self::DestinationUnreachable => 1,
22            Self::TimeExceeded => 3,
23            Self::Other(id) => *id,
24        }
25    }
26}
27
28impl From<u8> for IcmpType {
29    fn from(val: u8) -> Self {
30        match val {
31            128 => Self::EchoRequest,
32            129 => Self::EchoReply,
33            1 => Self::DestinationUnreachable,
34            3 => Self::TimeExceeded,
35            id => Self::Other(id),
36        }
37    }
38}
39
40/// The `ICMPv6` code.
41#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
42pub struct IcmpCode(pub u8);
43
44impl From<u8> for IcmpCode {
45    fn from(val: u8) -> Self {
46        Self(val)
47    }
48}
49
50/// The code for `TimeExceeded` `ICMPv6` packet type.
51#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
52pub enum IcmpTimeExceededCode {
53    /// Hop limit exceeded in transit.
54    TtlExpired,
55    /// Fragment reassembly time exceeded.
56    FragmentReassembly,
57    /// An unknown code.
58    Unknown(u8),
59}
60
61impl From<IcmpCode> for IcmpTimeExceededCode {
62    fn from(val: IcmpCode) -> Self {
63        match val {
64            IcmpCode(0) => Self::TtlExpired,
65            IcmpCode(1) => Self::FragmentReassembly,
66            IcmpCode(id) => Self::Unknown(id),
67        }
68    }
69}
70
71const TYPE_OFFSET: usize = 0;
72const CODE_OFFSET: usize = 1;
73const CHECKSUM_OFFSET: usize = 2;
74
75/// Represents an ICMP packet.
76///
77/// The internal representation is held in network byte order (big-endian) and all accessor methods
78/// take and return data in host byte order, converting as necessary for the given architecture.
79pub struct IcmpPacket<'a> {
80    buf: Buffer<'a>,
81}
82
83impl<'a> IcmpPacket<'a> {
84    pub fn new(packet: &'a mut [u8]) -> Result<Self> {
85        if packet.len() >= Self::minimum_packet_size() {
86            Ok(Self {
87                buf: Buffer::Mutable(packet),
88            })
89        } else {
90            Err(Error::InsufficientPacketBuffer(
91                String::from("IcmpPacket"),
92                Self::minimum_packet_size(),
93                packet.len(),
94            ))
95        }
96    }
97
98    pub fn new_view(packet: &'a [u8]) -> Result<Self> {
99        if packet.len() >= Self::minimum_packet_size() {
100            Ok(Self {
101                buf: Buffer::Immutable(packet),
102            })
103        } else {
104            Err(Error::InsufficientPacketBuffer(
105                String::from("IcmpPacket"),
106                Self::minimum_packet_size(),
107                packet.len(),
108            ))
109        }
110    }
111
112    #[must_use]
113    pub const fn minimum_packet_size() -> usize {
114        8
115    }
116
117    #[must_use]
118    pub fn get_icmp_type(&self) -> IcmpType {
119        IcmpType::from(self.buf.read(TYPE_OFFSET))
120    }
121
122    #[must_use]
123    pub fn get_icmp_code(&self) -> IcmpCode {
124        IcmpCode::from(self.buf.read(CODE_OFFSET))
125    }
126
127    #[must_use]
128    pub fn get_checksum(&self) -> u16 {
129        u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
130    }
131
132    pub fn set_icmp_type(&mut self, val: IcmpType) {
133        *self.buf.write(TYPE_OFFSET) = val.id();
134    }
135
136    pub fn set_icmp_code(&mut self, val: IcmpCode) {
137        *self.buf.write(CODE_OFFSET) = val.0;
138    }
139
140    pub fn set_checksum(&mut self, val: u16) {
141        self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
142    }
143
144    #[must_use]
145    pub fn packet(&self) -> &[u8] {
146        self.buf.as_slice()
147    }
148}
149
150impl Debug for IcmpPacket<'_> {
151    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152        f.debug_struct("IcmpPacket")
153            .field("icmp_type", &self.get_icmp_type())
154            .field("icmp_code", &self.get_icmp_code())
155            .field("checksum", &self.get_checksum())
156            .finish()
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn test_icmp_type() {
166        let mut buf = [0_u8; IcmpPacket::minimum_packet_size()];
167        let mut packet = IcmpPacket::new(&mut buf).unwrap();
168        packet.set_icmp_type(IcmpType::EchoRequest);
169        assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
170        assert_eq!([0x80], packet.packet()[0..1]);
171        packet.set_icmp_type(IcmpType::EchoReply);
172        assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
173        assert_eq!([0x81], packet.packet()[0..1]);
174        packet.set_icmp_type(IcmpType::DestinationUnreachable);
175        assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
176        assert_eq!([0x01], packet.packet()[0..1]);
177        packet.set_icmp_type(IcmpType::TimeExceeded);
178        assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
179        assert_eq!([0x03], packet.packet()[0..1]);
180        packet.set_icmp_type(IcmpType::Other(255));
181        assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
182        assert_eq!([0xFF], packet.packet()[0..1]);
183    }
184
185    #[test]
186    fn test_icmp_code() {
187        let mut buf = [0_u8; IcmpPacket::minimum_packet_size()];
188        let mut packet = IcmpPacket::new(&mut buf).unwrap();
189        packet.set_icmp_code(IcmpCode(0));
190        assert_eq!(IcmpCode(0), packet.get_icmp_code());
191        assert_eq!([0x00], packet.packet()[1..2]);
192        packet.set_icmp_code(IcmpCode(5));
193        assert_eq!(IcmpCode(5), packet.get_icmp_code());
194        assert_eq!([0x05], packet.packet()[1..2]);
195        packet.set_icmp_code(IcmpCode(255));
196        assert_eq!(IcmpCode(255), packet.get_icmp_code());
197        assert_eq!([0xFF], packet.packet()[1..2]);
198    }
199
200    #[test]
201    fn test_checksum() {
202        let mut buf = [0_u8; IcmpPacket::minimum_packet_size()];
203        let mut packet = IcmpPacket::new(&mut buf).unwrap();
204        packet.set_checksum(0);
205        assert_eq!(0, packet.get_checksum());
206        assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
207        packet.set_checksum(1999);
208        assert_eq!(1999, packet.get_checksum());
209        assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
210        packet.set_checksum(u16::MAX);
211        assert_eq!(u16::MAX, packet.get_checksum());
212        assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
213    }
214
215    #[test]
216    fn test_new_insufficient_buffer() {
217        const SIZE: usize = IcmpPacket::minimum_packet_size();
218        let mut buf = [0_u8; SIZE - 1];
219        let err = IcmpPacket::new(&mut buf).unwrap_err();
220        assert_eq!(
221            Error::InsufficientPacketBuffer(String::from("IcmpPacket"), SIZE, SIZE - 1),
222            err
223        );
224    }
225
226    #[test]
227    fn test_new_view_insufficient_buffer() {
228        const SIZE: usize = IcmpPacket::minimum_packet_size();
229        let buf = [0_u8; SIZE - 1];
230        let err = IcmpPacket::new_view(&buf).unwrap_err();
231        assert_eq!(
232            Error::InsufficientPacketBuffer(String::from("IcmpPacket"), SIZE, SIZE - 1),
233            err
234        );
235    }
236}
237
238pub mod echo_request {
239    use crate::buffer::Buffer;
240    use crate::error::{Error, Result};
241    use crate::fmt_payload;
242    use crate::icmpv6::{IcmpCode, IcmpType};
243    use std::fmt::{Debug, Formatter};
244
245    const TYPE_OFFSET: usize = 0;
246    const CODE_OFFSET: usize = 1;
247    const CHECKSUM_OFFSET: usize = 2;
248    const IDENTIFIER_OFFSET: usize = 4;
249    const SEQUENCE_OFFSET: usize = 6;
250
251    /// Represents an `ICMPv6` `EchoRequest` packet.
252    ///
253    /// The internal representation is held in network byte order (big-endian) and all accessor
254    /// methods take and return data in host byte order, converting as necessary for the given
255    /// architecture.
256    pub struct EchoRequestPacket<'a> {
257        buf: Buffer<'a>,
258    }
259
260    impl<'a> EchoRequestPacket<'a> {
261        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
262            if packet.len() >= Self::minimum_packet_size() {
263                Ok(Self {
264                    buf: Buffer::Mutable(packet),
265                })
266            } else {
267                Err(Error::InsufficientPacketBuffer(
268                    String::from("EchoRequestPacket"),
269                    Self::minimum_packet_size(),
270                    packet.len(),
271                ))
272            }
273        }
274
275        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
276            if packet.len() >= Self::minimum_packet_size() {
277                Ok(Self {
278                    buf: Buffer::Immutable(packet),
279                })
280            } else {
281                Err(Error::InsufficientPacketBuffer(
282                    String::from("EchoRequestPacket"),
283                    Self::minimum_packet_size(),
284                    packet.len(),
285                ))
286            }
287        }
288
289        #[must_use]
290        pub const fn minimum_packet_size() -> usize {
291            8
292        }
293
294        #[must_use]
295        pub fn get_icmp_type(&self) -> IcmpType {
296            IcmpType::from(self.buf.read(TYPE_OFFSET))
297        }
298
299        #[must_use]
300        pub fn get_icmp_code(&self) -> IcmpCode {
301            IcmpCode::from(self.buf.read(CODE_OFFSET))
302        }
303
304        #[must_use]
305        pub fn get_checksum(&self) -> u16 {
306            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
307        }
308
309        #[must_use]
310        pub fn get_identifier(&self) -> u16 {
311            u16::from_be_bytes(self.buf.get_bytes(IDENTIFIER_OFFSET))
312        }
313
314        #[must_use]
315        pub fn get_sequence(&self) -> u16 {
316            u16::from_be_bytes(self.buf.get_bytes(SEQUENCE_OFFSET))
317        }
318
319        pub fn set_icmp_type(&mut self, val: IcmpType) {
320            *self.buf.write(TYPE_OFFSET) = val.id();
321        }
322
323        pub fn set_icmp_code(&mut self, val: IcmpCode) {
324            *self.buf.write(CODE_OFFSET) = val.0;
325        }
326
327        pub fn set_checksum(&mut self, val: u16) {
328            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
329        }
330
331        pub fn set_identifier(&mut self, val: u16) {
332            self.buf.set_bytes(IDENTIFIER_OFFSET, val.to_be_bytes());
333        }
334
335        pub fn set_sequence(&mut self, val: u16) {
336            self.buf.set_bytes(SEQUENCE_OFFSET, val.to_be_bytes());
337        }
338
339        pub fn set_payload(&mut self, vals: &[u8]) {
340            let current_offset = Self::minimum_packet_size();
341            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
342                .copy_from_slice(vals);
343        }
344
345        #[must_use]
346        pub fn packet(&self) -> &[u8] {
347            self.buf.as_slice()
348        }
349
350        #[must_use]
351        pub fn payload(&self) -> &[u8] {
352            &self.buf.as_slice()[Self::minimum_packet_size()..]
353        }
354    }
355
356    impl Debug for EchoRequestPacket<'_> {
357        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
358            f.debug_struct("EchoRequestPacket")
359                .field("icmp_type", &self.get_icmp_type())
360                .field("icmp_code", &self.get_icmp_code())
361                .field("checksum", &self.get_checksum())
362                .field("identifier", &self.get_identifier())
363                .field("sequence", &self.get_sequence())
364                .field("payload", &fmt_payload(self.payload()))
365                .finish()
366        }
367    }
368
369    #[cfg(test)]
370    mod tests {
371        use super::*;
372
373        #[test]
374        fn test_icmp_type() {
375            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
376            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
377            packet.set_icmp_type(IcmpType::EchoRequest);
378            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
379            assert_eq!([0x80], packet.packet()[0..1]);
380            packet.set_icmp_type(IcmpType::EchoReply);
381            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
382            assert_eq!([0x81], packet.packet()[0..1]);
383            packet.set_icmp_type(IcmpType::DestinationUnreachable);
384            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
385            assert_eq!([0x01], packet.packet()[0..1]);
386            packet.set_icmp_type(IcmpType::TimeExceeded);
387            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
388            assert_eq!([0x03], packet.packet()[0..1]);
389            packet.set_icmp_type(IcmpType::Other(255));
390            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
391            assert_eq!([0xFF], packet.packet()[0..1]);
392        }
393
394        #[test]
395        fn test_icmp_code() {
396            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
397            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
398            packet.set_icmp_code(IcmpCode(0));
399            assert_eq!(IcmpCode(0), packet.get_icmp_code());
400            assert_eq!([0x00], packet.packet()[1..2]);
401            packet.set_icmp_code(IcmpCode(5));
402            assert_eq!(IcmpCode(5), packet.get_icmp_code());
403            assert_eq!([0x05], packet.packet()[1..2]);
404            packet.set_icmp_code(IcmpCode(255));
405            assert_eq!(IcmpCode(255), packet.get_icmp_code());
406            assert_eq!([0xFF], packet.packet()[1..2]);
407        }
408
409        #[test]
410        fn test_checksum() {
411            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
412            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
413            packet.set_checksum(0);
414            assert_eq!(0, packet.get_checksum());
415            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
416            packet.set_checksum(1999);
417            assert_eq!(1999, packet.get_checksum());
418            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
419            packet.set_checksum(u16::MAX);
420            assert_eq!(u16::MAX, packet.get_checksum());
421            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
422        }
423
424        #[test]
425        fn test_identifier() {
426            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
427            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
428            packet.set_identifier(0);
429            assert_eq!(0, packet.get_identifier());
430            assert_eq!([0x00, 0x00], packet.packet()[4..=5]);
431            packet.set_identifier(1999);
432            assert_eq!(1999, packet.get_identifier());
433            assert_eq!([0x07, 0xCF], packet.packet()[4..=5]);
434            packet.set_identifier(u16::MAX);
435            assert_eq!(u16::MAX, packet.get_identifier());
436            assert_eq!([0xFF, 0xFF], packet.packet()[4..=5]);
437        }
438
439        #[test]
440        fn test_sequence() {
441            let mut buf = [0_u8; EchoRequestPacket::minimum_packet_size()];
442            let mut packet = EchoRequestPacket::new(&mut buf).unwrap();
443            packet.set_sequence(0);
444            assert_eq!(0, packet.get_sequence());
445            assert_eq!([0x00, 0x00], packet.packet()[6..=7]);
446            packet.set_sequence(1999);
447            assert_eq!(1999, packet.get_sequence());
448            assert_eq!([0x07, 0xCF], packet.packet()[6..=7]);
449            packet.set_sequence(u16::MAX);
450            assert_eq!(u16::MAX, packet.get_sequence());
451            assert_eq!([0xFF, 0xFF], packet.packet()[6..=7]);
452        }
453
454        #[test]
455        fn test_view() {
456            let buf = [0x80, 0x00, 0x16, 0x7c, 0x60, 0x9b, 0x82, 0x9a];
457            let packet = EchoRequestPacket::new_view(&buf).unwrap();
458            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
459            assert_eq!(IcmpCode(0), packet.get_icmp_code());
460            assert_eq!(5756, packet.get_checksum());
461            assert_eq!(24731, packet.get_identifier());
462            assert_eq!(33434, packet.get_sequence());
463            assert!(packet.payload().is_empty());
464        }
465
466        #[test]
467        fn test_new_insufficient_buffer() {
468            const SIZE: usize = EchoRequestPacket::minimum_packet_size();
469            let mut buf = [0_u8; SIZE - 1];
470            let err = EchoRequestPacket::new(&mut buf).unwrap_err();
471            assert_eq!(
472                Error::InsufficientPacketBuffer(String::from("EchoRequestPacket"), SIZE, SIZE - 1),
473                err
474            );
475        }
476
477        #[test]
478        fn test_new_view_insufficient_buffer() {
479            const SIZE: usize = EchoRequestPacket::minimum_packet_size();
480            let buf = [0_u8; SIZE - 1];
481            let err = EchoRequestPacket::new_view(&buf).unwrap_err();
482            assert_eq!(
483                Error::InsufficientPacketBuffer(String::from("EchoRequestPacket"), SIZE, SIZE - 1),
484                err
485            );
486        }
487    }
488}
489
490pub mod echo_reply {
491    use crate::buffer::Buffer;
492    use crate::error::{Error, Result};
493    use crate::fmt_payload;
494    use crate::icmpv6::{IcmpCode, IcmpType};
495    use std::fmt::{Debug, Formatter};
496
497    const TYPE_OFFSET: usize = 0;
498    const CODE_OFFSET: usize = 1;
499    const CHECKSUM_OFFSET: usize = 2;
500    const IDENTIFIER_OFFSET: usize = 4;
501    const SEQUENCE_OFFSET: usize = 6;
502
503    /// Represents an ICMP `EchoReply` packet.
504    ///
505    /// The internal representation is held in network byte order (big-endian) and all accessor
506    /// methods take and return data in host byte order, converting as necessary for the given
507    /// architecture.
508    pub struct EchoReplyPacket<'a> {
509        buf: Buffer<'a>,
510    }
511
512    impl<'a> EchoReplyPacket<'a> {
513        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
514            if packet.len() >= Self::minimum_packet_size() {
515                Ok(Self {
516                    buf: Buffer::Mutable(packet),
517                })
518            } else {
519                Err(Error::InsufficientPacketBuffer(
520                    String::from("EchoReplyPacket"),
521                    Self::minimum_packet_size(),
522                    packet.len(),
523                ))
524            }
525        }
526
527        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
528            if packet.len() >= Self::minimum_packet_size() {
529                Ok(Self {
530                    buf: Buffer::Immutable(packet),
531                })
532            } else {
533                Err(Error::InsufficientPacketBuffer(
534                    String::from("EchoReplyPacket"),
535                    Self::minimum_packet_size(),
536                    packet.len(),
537                ))
538            }
539        }
540
541        #[must_use]
542        pub const fn minimum_packet_size() -> usize {
543            8
544        }
545
546        #[must_use]
547        pub fn get_icmp_type(&self) -> IcmpType {
548            IcmpType::from(self.buf.read(TYPE_OFFSET))
549        }
550
551        #[must_use]
552        pub fn get_icmp_code(&self) -> IcmpCode {
553            IcmpCode::from(self.buf.read(CODE_OFFSET))
554        }
555
556        #[must_use]
557        pub fn get_checksum(&self) -> u16 {
558            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
559        }
560
561        #[must_use]
562        pub fn get_identifier(&self) -> u16 {
563            u16::from_be_bytes(self.buf.get_bytes(IDENTIFIER_OFFSET))
564        }
565
566        #[must_use]
567        pub fn get_sequence(&self) -> u16 {
568            u16::from_be_bytes(self.buf.get_bytes(SEQUENCE_OFFSET))
569        }
570
571        pub fn set_icmp_type(&mut self, val: IcmpType) {
572            *self.buf.write(TYPE_OFFSET) = val.id();
573        }
574
575        pub fn set_icmp_code(&mut self, val: IcmpCode) {
576            *self.buf.write(CODE_OFFSET) = val.0;
577        }
578
579        pub fn set_checksum(&mut self, val: u16) {
580            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
581        }
582
583        pub fn set_identifier(&mut self, val: u16) {
584            self.buf.set_bytes(IDENTIFIER_OFFSET, val.to_be_bytes());
585        }
586
587        pub fn set_sequence(&mut self, val: u16) {
588            self.buf.set_bytes(SEQUENCE_OFFSET, val.to_be_bytes());
589        }
590
591        pub fn set_payload(&mut self, vals: &[u8]) {
592            let current_offset = Self::minimum_packet_size();
593            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
594                .copy_from_slice(vals);
595        }
596
597        #[must_use]
598        pub fn packet(&self) -> &[u8] {
599            self.buf.as_slice()
600        }
601
602        #[must_use]
603        pub fn payload(&self) -> &[u8] {
604            &self.buf.as_slice()[Self::minimum_packet_size()..]
605        }
606    }
607
608    impl Debug for EchoReplyPacket<'_> {
609        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
610            f.debug_struct("EchoReplyPacket")
611                .field("icmp_type", &self.get_icmp_type())
612                .field("icmp_code", &self.get_icmp_code())
613                .field("checksum", &self.get_checksum())
614                .field("identifier", &self.get_identifier())
615                .field("sequence", &self.get_sequence())
616                .field("payload", &fmt_payload(self.payload()))
617                .finish()
618        }
619    }
620
621    #[cfg(test)]
622    mod tests {
623        use super::*;
624
625        #[test]
626        fn test_icmp_type() {
627            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
628            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
629            packet.set_icmp_type(IcmpType::EchoRequest);
630            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
631            assert_eq!([0x80], packet.packet()[0..1]);
632            packet.set_icmp_type(IcmpType::EchoReply);
633            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
634            assert_eq!([0x81], packet.packet()[0..1]);
635            packet.set_icmp_type(IcmpType::DestinationUnreachable);
636            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
637            assert_eq!([0x01], packet.packet()[0..1]);
638            packet.set_icmp_type(IcmpType::TimeExceeded);
639            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
640            assert_eq!([0x03], packet.packet()[0..1]);
641            packet.set_icmp_type(IcmpType::Other(255));
642            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
643            assert_eq!([0xFF], packet.packet()[0..1]);
644        }
645
646        #[test]
647        fn test_icmp_code() {
648            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
649            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
650            packet.set_icmp_code(IcmpCode(0));
651            assert_eq!(IcmpCode(0), packet.get_icmp_code());
652            assert_eq!([0x00], packet.packet()[1..2]);
653            packet.set_icmp_code(IcmpCode(5));
654            assert_eq!(IcmpCode(5), packet.get_icmp_code());
655            assert_eq!([0x05], packet.packet()[1..2]);
656            packet.set_icmp_code(IcmpCode(255));
657            assert_eq!(IcmpCode(255), packet.get_icmp_code());
658            assert_eq!([0xFF], packet.packet()[1..2]);
659        }
660
661        #[test]
662        fn test_checksum() {
663            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
664            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
665            packet.set_checksum(0);
666            assert_eq!(0, packet.get_checksum());
667            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
668            packet.set_checksum(1999);
669            assert_eq!(1999, packet.get_checksum());
670            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
671            packet.set_checksum(u16::MAX);
672            assert_eq!(u16::MAX, packet.get_checksum());
673            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
674        }
675
676        #[test]
677        fn test_identifier() {
678            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
679            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
680            packet.set_identifier(0);
681            assert_eq!(0, packet.get_identifier());
682            assert_eq!([0x00, 0x00], packet.packet()[4..=5]);
683            packet.set_identifier(1999);
684            assert_eq!(1999, packet.get_identifier());
685            assert_eq!([0x07, 0xCF], packet.packet()[4..=5]);
686            packet.set_identifier(u16::MAX);
687            assert_eq!(u16::MAX, packet.get_identifier());
688            assert_eq!([0xFF, 0xFF], packet.packet()[4..=5]);
689        }
690
691        #[test]
692        fn test_sequence() {
693            let mut buf = [0_u8; EchoReplyPacket::minimum_packet_size()];
694            let mut packet = EchoReplyPacket::new(&mut buf).unwrap();
695            packet.set_sequence(0);
696            assert_eq!(0, packet.get_sequence());
697            assert_eq!([0x00, 0x00], packet.packet()[6..=7]);
698            packet.set_sequence(1999);
699            assert_eq!(1999, packet.get_sequence());
700            assert_eq!([0x07, 0xCF], packet.packet()[6..=7]);
701            packet.set_sequence(u16::MAX);
702            assert_eq!(u16::MAX, packet.get_sequence());
703            assert_eq!([0xFF, 0xFF], packet.packet()[6..=7]);
704        }
705
706        #[test]
707        fn test_view() {
708            let buf = [0x81, 0x00, 0x1e, 0x70, 0x60, 0x9b, 0x80, 0xf4];
709            let packet = EchoReplyPacket::new_view(&buf).unwrap();
710            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
711            assert_eq!(IcmpCode(0), packet.get_icmp_code());
712            assert_eq!(7792, packet.get_checksum());
713            assert_eq!(24731, packet.get_identifier());
714            assert_eq!(33012, packet.get_sequence());
715            assert!(packet.payload().is_empty());
716        }
717
718        #[test]
719        fn test_new_insufficient_buffer() {
720            const SIZE: usize = EchoReplyPacket::minimum_packet_size();
721            let mut buf = [0_u8; SIZE - 1];
722            let err = EchoReplyPacket::new(&mut buf).unwrap_err();
723            assert_eq!(
724                Error::InsufficientPacketBuffer(String::from("EchoReplyPacket"), SIZE, SIZE - 1),
725                err
726            );
727        }
728
729        #[test]
730        fn test_new_view_insufficient_buffer() {
731            const SIZE: usize = EchoReplyPacket::minimum_packet_size();
732            let buf = [0_u8; SIZE - 1];
733            let err = EchoReplyPacket::new_view(&buf).unwrap_err();
734            assert_eq!(
735                Error::InsufficientPacketBuffer(String::from("EchoReplyPacket"), SIZE, SIZE - 1),
736                err
737            );
738        }
739    }
740}
741
742pub mod time_exceeded {
743    use crate::buffer::Buffer;
744    use crate::error::{Error, Result};
745    use crate::fmt_payload;
746    use crate::icmp_extension::extension_splitter::split;
747    use crate::icmpv6::{IcmpCode, IcmpType};
748    use std::fmt::{Debug, Formatter};
749
750    const TYPE_OFFSET: usize = 0;
751    const CODE_OFFSET: usize = 1;
752    const CHECKSUM_OFFSET: usize = 2;
753    const LENGTH_OFFSET: usize = 4;
754
755    /// Represents an ICMP `TimeExceeded` packet.
756    ///
757    /// The internal representation is held in network byte order (big-endian) and all accessor
758    /// methods take and return data in host byte order, converting as necessary for the given
759    /// architecture.
760    pub struct TimeExceededPacket<'a> {
761        buf: Buffer<'a>,
762    }
763
764    impl<'a> TimeExceededPacket<'a> {
765        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
766            if packet.len() >= Self::minimum_packet_size() {
767                Ok(Self {
768                    buf: Buffer::Mutable(packet),
769                })
770            } else {
771                Err(Error::InsufficientPacketBuffer(
772                    String::from("TimeExceededPacket"),
773                    Self::minimum_packet_size(),
774                    packet.len(),
775                ))
776            }
777        }
778
779        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
780            if packet.len() >= Self::minimum_packet_size() {
781                Ok(Self {
782                    buf: Buffer::Immutable(packet),
783                })
784            } else {
785                Err(Error::InsufficientPacketBuffer(
786                    String::from("TimeExceededPacket"),
787                    Self::minimum_packet_size(),
788                    packet.len(),
789                ))
790            }
791        }
792
793        #[must_use]
794        pub const fn minimum_packet_size() -> usize {
795            8
796        }
797
798        #[must_use]
799        pub fn get_icmp_type(&self) -> IcmpType {
800            IcmpType::from(self.buf.read(TYPE_OFFSET))
801        }
802
803        #[must_use]
804        pub fn get_icmp_code(&self) -> IcmpCode {
805            IcmpCode::from(self.buf.read(CODE_OFFSET))
806        }
807
808        #[must_use]
809        pub fn get_checksum(&self) -> u16 {
810            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
811        }
812
813        #[must_use]
814        pub fn get_length(&self) -> u8 {
815            self.buf.read(LENGTH_OFFSET)
816        }
817
818        pub fn set_icmp_type(&mut self, val: IcmpType) {
819            *self.buf.write(TYPE_OFFSET) = val.id();
820        }
821
822        pub fn set_icmp_code(&mut self, val: IcmpCode) {
823            *self.buf.write(CODE_OFFSET) = val.0;
824        }
825
826        pub fn set_checksum(&mut self, val: u16) {
827            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
828        }
829
830        pub fn set_length(&mut self, val: u8) {
831            *self.buf.write(LENGTH_OFFSET) = val;
832        }
833
834        pub fn set_payload(&mut self, vals: &[u8]) {
835            let current_offset = Self::minimum_packet_size();
836            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
837                .copy_from_slice(vals);
838        }
839
840        #[must_use]
841        pub fn packet(&self) -> &[u8] {
842            self.buf.as_slice()
843        }
844
845        #[must_use]
846        pub fn payload(&self) -> &[u8] {
847            let (payload, _) = self.split_payload_extension();
848            payload
849        }
850
851        #[must_use]
852        pub fn payload_raw(&self) -> &[u8] {
853            &self.buf.as_slice()[Self::minimum_packet_size()..]
854        }
855
856        #[must_use]
857        pub fn extension(&self) -> Option<&[u8]> {
858            let (_, extension) = self.split_payload_extension();
859            extension
860        }
861
862        fn split_payload_extension(&self) -> (&[u8], Option<&[u8]>) {
863            let length = usize::from(self.get_length()) * 8;
864            let icmp_payload = &self.buf.as_slice()[Self::minimum_packet_size()..];
865            split(length, icmp_payload)
866        }
867    }
868
869    impl Debug for TimeExceededPacket<'_> {
870        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
871            f.debug_struct("TimeExceededPacket")
872                .field("icmp_type", &self.get_icmp_type())
873                .field("icmp_code", &self.get_icmp_code())
874                .field("checksum", &self.get_checksum())
875                .field("length", &self.get_length())
876                .field("payload", &fmt_payload(self.payload()))
877                .finish()
878        }
879    }
880
881    #[cfg(test)]
882    mod tests {
883        use super::*;
884
885        #[test]
886        fn test_icmp_type() {
887            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
888            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
889            packet.set_icmp_type(IcmpType::EchoRequest);
890            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
891            assert_eq!([0x80], packet.packet()[0..1]);
892            packet.set_icmp_type(IcmpType::EchoReply);
893            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
894            assert_eq!([0x81], packet.packet()[0..1]);
895            packet.set_icmp_type(IcmpType::DestinationUnreachable);
896            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
897            assert_eq!([0x01], packet.packet()[0..1]);
898            packet.set_icmp_type(IcmpType::TimeExceeded);
899            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
900            assert_eq!([0x03], packet.packet()[0..1]);
901            packet.set_icmp_type(IcmpType::Other(255));
902            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
903            assert_eq!([0xFF], packet.packet()[0..1]);
904        }
905
906        #[test]
907        fn test_icmp_code() {
908            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
909            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
910            packet.set_icmp_code(IcmpCode(0));
911            assert_eq!(IcmpCode(0), packet.get_icmp_code());
912            assert_eq!([0x00], packet.packet()[1..2]);
913            packet.set_icmp_code(IcmpCode(5));
914            assert_eq!(IcmpCode(5), packet.get_icmp_code());
915            assert_eq!([0x05], packet.packet()[1..2]);
916            packet.set_icmp_code(IcmpCode(255));
917            assert_eq!(IcmpCode(255), packet.get_icmp_code());
918            assert_eq!([0xFF], packet.packet()[1..2]);
919        }
920
921        #[test]
922        fn test_checksum() {
923            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
924            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
925            packet.set_checksum(0);
926            assert_eq!(0, packet.get_checksum());
927            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
928            packet.set_checksum(1999);
929            assert_eq!(1999, packet.get_checksum());
930            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
931            packet.set_checksum(u16::MAX);
932            assert_eq!(u16::MAX, packet.get_checksum());
933            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
934        }
935
936        #[test]
937        fn test_length() {
938            let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
939            let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
940            packet.set_length(0);
941            assert_eq!(0, packet.get_length());
942            assert_eq!([0x00], packet.packet()[4..5]);
943            packet.set_length(8);
944            assert_eq!(8, packet.get_length());
945            assert_eq!([0x08], packet.packet()[4..5]);
946            packet.set_length(u8::MAX);
947            assert_eq!(u8::MAX, packet.get_length());
948            assert_eq!([0xFF], packet.packet()[4..5]);
949        }
950
951        #[test]
952        fn test_view() {
953            let buf = [0x03, 0x00, 0xf4, 0xee, 0x11, 0x00, 0x00, 0x00];
954            let packet = TimeExceededPacket::new_view(&buf).unwrap();
955            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
956            assert_eq!(IcmpCode(0), packet.get_icmp_code());
957            assert_eq!(62702, packet.get_checksum());
958            assert_eq!(17, packet.get_length());
959            assert!(packet.payload().is_empty());
960        }
961
962        #[test]
963        fn test_view_large() {
964            let mut buf = [0x0_u8; 128];
965            buf[..8].copy_from_slice(&[0x03, 0x00, 0xf4, 0xee, 0x20, 0x00, 0x00, 0x00]);
966            let packet = TimeExceededPacket::new_view(&buf).unwrap();
967            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
968            assert_eq!(IcmpCode(0), packet.get_icmp_code());
969            assert_eq!(62702, packet.get_checksum());
970            assert_eq!(32, packet.get_length());
971            assert_eq!(&[0x0_u8; 120], packet.payload());
972            assert_eq!(None, packet.extension());
973        }
974
975        #[test]
976        fn test_new_insufficient_buffer() {
977            const SIZE: usize = TimeExceededPacket::minimum_packet_size();
978            let mut buf = [0_u8; SIZE - 1];
979            let err = TimeExceededPacket::new(&mut buf).unwrap_err();
980            assert_eq!(
981                Error::InsufficientPacketBuffer(String::from("TimeExceededPacket"), SIZE, SIZE - 1),
982                err
983            );
984        }
985
986        #[test]
987        fn test_new_view_insufficient_buffer() {
988            const SIZE: usize = TimeExceededPacket::minimum_packet_size();
989            let buf = [0_u8; SIZE - 1];
990            let err = TimeExceededPacket::new_view(&buf).unwrap_err();
991            assert_eq!(
992                Error::InsufficientPacketBuffer(String::from("TimeExceededPacket"), SIZE, SIZE - 1),
993                err
994            );
995        }
996    }
997}
998
999pub mod destination_unreachable {
1000    use crate::buffer::Buffer;
1001    use crate::error::{Error, Result};
1002    use crate::fmt_payload;
1003    use crate::icmp_extension::extension_splitter::split;
1004    use crate::icmpv6::{IcmpCode, IcmpType};
1005    use std::fmt::{Debug, Formatter};
1006
1007    const TYPE_OFFSET: usize = 0;
1008    const CODE_OFFSET: usize = 1;
1009    const CHECKSUM_OFFSET: usize = 2;
1010    const LENGTH_OFFSET: usize = 4;
1011    const NEXT_HOP_MTU_OFFSET: usize = 6;
1012
1013    /// Represents an ICMP `DestinationUnreachable` packet.
1014    ///
1015    /// The internal representation is held in network byte order (big-endian) and all accessor
1016    /// methods take and return data in host byte order, converting as necessary for the given
1017    /// architecture.
1018    pub struct DestinationUnreachablePacket<'a> {
1019        buf: Buffer<'a>,
1020    }
1021
1022    impl<'a> DestinationUnreachablePacket<'a> {
1023        pub fn new(packet: &'a mut [u8]) -> Result<Self> {
1024            if packet.len() >= Self::minimum_packet_size() {
1025                Ok(Self {
1026                    buf: Buffer::Mutable(packet),
1027                })
1028            } else {
1029                Err(Error::InsufficientPacketBuffer(
1030                    String::from("DestinationUnreachablePacket"),
1031                    Self::minimum_packet_size(),
1032                    packet.len(),
1033                ))
1034            }
1035        }
1036
1037        pub fn new_view(packet: &'a [u8]) -> Result<Self> {
1038            if packet.len() >= Self::minimum_packet_size() {
1039                Ok(Self {
1040                    buf: Buffer::Immutable(packet),
1041                })
1042            } else {
1043                Err(Error::InsufficientPacketBuffer(
1044                    String::from("DestinationUnreachablePacket"),
1045                    Self::minimum_packet_size(),
1046                    packet.len(),
1047                ))
1048            }
1049        }
1050
1051        #[must_use]
1052        pub const fn minimum_packet_size() -> usize {
1053            8
1054        }
1055
1056        #[must_use]
1057        pub fn get_icmp_type(&self) -> IcmpType {
1058            IcmpType::from(self.buf.read(TYPE_OFFSET))
1059        }
1060
1061        #[must_use]
1062        pub fn get_icmp_code(&self) -> IcmpCode {
1063            IcmpCode::from(self.buf.read(CODE_OFFSET))
1064        }
1065
1066        #[must_use]
1067        pub fn get_checksum(&self) -> u16 {
1068            u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
1069        }
1070
1071        #[must_use]
1072        pub fn get_length(&self) -> u8 {
1073            self.buf.read(LENGTH_OFFSET)
1074        }
1075
1076        #[must_use]
1077        pub fn get_next_hop_mtu(&self) -> u16 {
1078            u16::from_be_bytes(self.buf.get_bytes(NEXT_HOP_MTU_OFFSET))
1079        }
1080
1081        pub fn set_icmp_type(&mut self, val: IcmpType) {
1082            *self.buf.write(TYPE_OFFSET) = val.id();
1083        }
1084
1085        pub fn set_icmp_code(&mut self, val: IcmpCode) {
1086            *self.buf.write(CODE_OFFSET) = val.0;
1087        }
1088
1089        pub fn set_checksum(&mut self, val: u16) {
1090            self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
1091        }
1092
1093        pub fn set_length(&mut self, val: u8) {
1094            *self.buf.write(LENGTH_OFFSET) = val;
1095        }
1096
1097        pub fn set_next_hop_mtu(&mut self, val: u16) {
1098            self.buf.set_bytes(NEXT_HOP_MTU_OFFSET, val.to_be_bytes());
1099        }
1100
1101        pub fn set_payload(&mut self, vals: &[u8]) {
1102            let current_offset = Self::minimum_packet_size();
1103            self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
1104                .copy_from_slice(vals);
1105        }
1106
1107        #[must_use]
1108        pub fn packet(&self) -> &[u8] {
1109            self.buf.as_slice()
1110        }
1111
1112        #[must_use]
1113        pub fn payload(&self) -> &[u8] {
1114            let (payload, _) = self.split_payload_extension();
1115            payload
1116        }
1117
1118        #[must_use]
1119        pub fn payload_raw(&self) -> &[u8] {
1120            &self.buf.as_slice()[Self::minimum_packet_size()..]
1121        }
1122
1123        #[must_use]
1124        pub fn extension(&self) -> Option<&[u8]> {
1125            let (_, extension) = self.split_payload_extension();
1126            extension
1127        }
1128
1129        fn split_payload_extension(&self) -> (&[u8], Option<&[u8]>) {
1130            // From rfc4884:
1131            //
1132            // "For ICMPv6 messages, the length attribute represents 64-bit words"
1133            let length = usize::from(self.get_length()) * 8;
1134            let icmp_payload = &self.buf.as_slice()[Self::minimum_packet_size()..];
1135            split(length, icmp_payload)
1136        }
1137    }
1138
1139    impl Debug for DestinationUnreachablePacket<'_> {
1140        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1141            f.debug_struct("DestinationUnreachablePacket")
1142                .field("icmp_type", &self.get_icmp_type())
1143                .field("icmp_code", &self.get_icmp_code())
1144                .field("checksum", &self.get_checksum())
1145                .field("length", &self.get_length())
1146                .field("next_hop_mtu", &self.get_next_hop_mtu())
1147                .field("payload", &fmt_payload(self.payload()))
1148                .finish()
1149        }
1150    }
1151
1152    #[cfg(test)]
1153    mod tests {
1154        use super::*;
1155
1156        #[test]
1157        fn test_icmp_type() {
1158            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1159            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1160            packet.set_icmp_type(IcmpType::EchoRequest);
1161            assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
1162            assert_eq!([0x80], packet.packet()[0..1]);
1163            packet.set_icmp_type(IcmpType::EchoReply);
1164            assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
1165            assert_eq!([0x81], packet.packet()[0..1]);
1166            packet.set_icmp_type(IcmpType::DestinationUnreachable);
1167            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
1168            assert_eq!([0x01], packet.packet()[0..1]);
1169            packet.set_icmp_type(IcmpType::TimeExceeded);
1170            assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
1171            assert_eq!([0x03], packet.packet()[0..1]);
1172            packet.set_icmp_type(IcmpType::Other(255));
1173            assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
1174            assert_eq!([0xFF], packet.packet()[0..1]);
1175        }
1176
1177        #[test]
1178        fn test_icmp_code() {
1179            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1180            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1181            packet.set_icmp_code(IcmpCode(0));
1182            assert_eq!(IcmpCode(0), packet.get_icmp_code());
1183            assert_eq!([0x00], packet.packet()[1..2]);
1184            packet.set_icmp_code(IcmpCode(5));
1185            assert_eq!(IcmpCode(5), packet.get_icmp_code());
1186            assert_eq!([0x05], packet.packet()[1..2]);
1187            packet.set_icmp_code(IcmpCode(255));
1188            assert_eq!(IcmpCode(255), packet.get_icmp_code());
1189            assert_eq!([0xFF], packet.packet()[1..2]);
1190        }
1191
1192        #[test]
1193        fn test_checksum() {
1194            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1195            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1196            packet.set_checksum(0);
1197            assert_eq!(0, packet.get_checksum());
1198            assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
1199            packet.set_checksum(1999);
1200            assert_eq!(1999, packet.get_checksum());
1201            assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
1202            packet.set_checksum(u16::MAX);
1203            assert_eq!(u16::MAX, packet.get_checksum());
1204            assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
1205        }
1206
1207        #[test]
1208        fn test_length() {
1209            let mut buf = [0_u8; DestinationUnreachablePacket::minimum_packet_size()];
1210            let mut packet = DestinationUnreachablePacket::new(&mut buf).unwrap();
1211            packet.set_length(0);
1212            assert_eq!(0, packet.get_length());
1213            assert_eq!([0x00], packet.packet()[4..5]);
1214            packet.set_length(8);
1215            assert_eq!(8, packet.get_length());
1216            assert_eq!([0x08], packet.packet()[4..5]);
1217            packet.set_length(u8::MAX);
1218            assert_eq!(u8::MAX, packet.get_length());
1219            assert_eq!([0xFF], packet.packet()[4..5]);
1220        }
1221
1222        #[test]
1223        fn test_view() {
1224            let buf = [0x01, 0x03, 0xdf, 0xdc, 0x00, 0x00, 0x00, 0x00];
1225            let packet = DestinationUnreachablePacket::new_view(&buf).unwrap();
1226            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
1227            assert_eq!(IcmpCode(3), packet.get_icmp_code());
1228            assert_eq!(57308, packet.get_checksum());
1229            assert_eq!(0, packet.get_length());
1230            assert!(packet.payload().is_empty());
1231        }
1232
1233        #[test]
1234        fn test_view_large() {
1235            let mut buf = [0x0_u8; 128];
1236            buf[..8].copy_from_slice(&[0x01, 0x03, 0xdf, 0xdc, 0x20, 0x00, 0x00, 0x00]);
1237            let packet = DestinationUnreachablePacket::new_view(&buf).unwrap();
1238            assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
1239            assert_eq!(IcmpCode(3), packet.get_icmp_code());
1240            assert_eq!(57308, packet.get_checksum());
1241            assert_eq!(32, packet.get_length());
1242            assert_eq!(&[0x0_u8; 120], packet.payload());
1243            assert_eq!(None, packet.extension());
1244        }
1245
1246        #[test]
1247        fn test_new_insufficient_buffer() {
1248            const SIZE: usize = DestinationUnreachablePacket::minimum_packet_size();
1249            let mut buf = [0_u8; SIZE - 1];
1250            let err = DestinationUnreachablePacket::new(&mut buf).unwrap_err();
1251            assert_eq!(
1252                Error::InsufficientPacketBuffer(
1253                    String::from("DestinationUnreachablePacket"),
1254                    SIZE,
1255                    SIZE - 1
1256                ),
1257                err
1258            );
1259        }
1260
1261        #[test]
1262        fn test_new_view_insufficient_buffer() {
1263            const SIZE: usize = DestinationUnreachablePacket::minimum_packet_size();
1264            let buf = [0_u8; SIZE - 1];
1265            let err = DestinationUnreachablePacket::new_view(&buf).unwrap_err();
1266            assert_eq!(
1267                Error::InsufficientPacketBuffer(
1268                    String::from("DestinationUnreachablePacket"),
1269                    SIZE,
1270                    SIZE - 1
1271                ),
1272                err
1273            );
1274        }
1275    }
1276}