smoltcp/wire/
icmpv4.rs

1use byteorder::{ByteOrder, NetworkEndian};
2use core::{cmp, fmt};
3
4use super::{Error, Result};
5use crate::phy::ChecksumCapabilities;
6use crate::wire::ip::checksum;
7use crate::wire::{Ipv4Packet, Ipv4Repr};
8
9enum_with_unknown! {
10    /// Internet protocol control message type.
11    pub enum Message(u8) {
12        /// Echo reply
13        EchoReply      =  0,
14        /// Destination unreachable
15        DstUnreachable =  3,
16        /// Message redirect
17        Redirect       =  5,
18        /// Echo request
19        EchoRequest    =  8,
20        /// Router advertisement
21        RouterAdvert   =  9,
22        /// Router solicitation
23        RouterSolicit  = 10,
24        /// Time exceeded
25        TimeExceeded   = 11,
26        /// Parameter problem
27        ParamProblem   = 12,
28        /// Timestamp
29        Timestamp      = 13,
30        /// Timestamp reply
31        TimestampReply = 14
32    }
33}
34
35impl fmt::Display for Message {
36    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37        match *self {
38            Message::EchoReply => write!(f, "echo reply"),
39            Message::DstUnreachable => write!(f, "destination unreachable"),
40            Message::Redirect => write!(f, "message redirect"),
41            Message::EchoRequest => write!(f, "echo request"),
42            Message::RouterAdvert => write!(f, "router advertisement"),
43            Message::RouterSolicit => write!(f, "router solicitation"),
44            Message::TimeExceeded => write!(f, "time exceeded"),
45            Message::ParamProblem => write!(f, "parameter problem"),
46            Message::Timestamp => write!(f, "timestamp"),
47            Message::TimestampReply => write!(f, "timestamp reply"),
48            Message::Unknown(id) => write!(f, "{id}"),
49        }
50    }
51}
52
53enum_with_unknown! {
54    /// Internet protocol control message subtype for type "Destination Unreachable".
55    pub enum DstUnreachable(u8) {
56        /// Destination network unreachable
57        NetUnreachable   =  0,
58        /// Destination host unreachable
59        HostUnreachable  =  1,
60        /// Destination protocol unreachable
61        ProtoUnreachable =  2,
62        /// Destination port unreachable
63        PortUnreachable  =  3,
64        /// Fragmentation required, and DF flag set
65        FragRequired     =  4,
66        /// Source route failed
67        SrcRouteFailed   =  5,
68        /// Destination network unknown
69        DstNetUnknown    =  6,
70        /// Destination host unknown
71        DstHostUnknown   =  7,
72        /// Source host isolated
73        SrcHostIsolated  =  8,
74        /// Network administratively prohibited
75        NetProhibited    =  9,
76        /// Host administratively prohibited
77        HostProhibited   = 10,
78        /// Network unreachable for ToS
79        NetUnreachToS    = 11,
80        /// Host unreachable for ToS
81        HostUnreachToS   = 12,
82        /// Communication administratively prohibited
83        CommProhibited   = 13,
84        /// Host precedence violation
85        HostPrecedViol   = 14,
86        /// Precedence cutoff in effect
87        PrecedCutoff     = 15
88    }
89}
90
91impl fmt::Display for DstUnreachable {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        match *self {
94            DstUnreachable::NetUnreachable => write!(f, "destination network unreachable"),
95            DstUnreachable::HostUnreachable => write!(f, "destination host unreachable"),
96            DstUnreachable::ProtoUnreachable => write!(f, "destination protocol unreachable"),
97            DstUnreachable::PortUnreachable => write!(f, "destination port unreachable"),
98            DstUnreachable::FragRequired => write!(f, "fragmentation required, and DF flag set"),
99            DstUnreachable::SrcRouteFailed => write!(f, "source route failed"),
100            DstUnreachable::DstNetUnknown => write!(f, "destination network unknown"),
101            DstUnreachable::DstHostUnknown => write!(f, "destination host unknown"),
102            DstUnreachable::SrcHostIsolated => write!(f, "source host isolated"),
103            DstUnreachable::NetProhibited => write!(f, "network administratively prohibited"),
104            DstUnreachable::HostProhibited => write!(f, "host administratively prohibited"),
105            DstUnreachable::NetUnreachToS => write!(f, "network unreachable for ToS"),
106            DstUnreachable::HostUnreachToS => write!(f, "host unreachable for ToS"),
107            DstUnreachable::CommProhibited => {
108                write!(f, "communication administratively prohibited")
109            }
110            DstUnreachable::HostPrecedViol => write!(f, "host precedence violation"),
111            DstUnreachable::PrecedCutoff => write!(f, "precedence cutoff in effect"),
112            DstUnreachable::Unknown(id) => write!(f, "{id}"),
113        }
114    }
115}
116
117enum_with_unknown! {
118    /// Internet protocol control message subtype for type "Redirect Message".
119    pub enum Redirect(u8) {
120        /// Redirect Datagram for the Network
121        Net     = 0,
122        /// Redirect Datagram for the Host
123        Host    = 1,
124        /// Redirect Datagram for the ToS & network
125        NetToS  = 2,
126        /// Redirect Datagram for the ToS & host
127        HostToS = 3
128    }
129}
130
131enum_with_unknown! {
132    /// Internet protocol control message subtype for type "Time Exceeded".
133    pub enum TimeExceeded(u8) {
134        /// TTL expired in transit
135        TtlExpired  = 0,
136        /// Fragment reassembly time exceeded
137        FragExpired = 1
138    }
139}
140
141impl fmt::Display for TimeExceeded {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        match *self {
144            TimeExceeded::TtlExpired => write!(f, "time-to-live exceeded in transit"),
145            TimeExceeded::FragExpired => write!(f, "fragment reassembly time exceeded"),
146            TimeExceeded::Unknown(id) => write!(f, "{id}"),
147        }
148    }
149}
150
151enum_with_unknown! {
152    /// Internet protocol control message subtype for type "Parameter Problem".
153    pub enum ParamProblem(u8) {
154        /// Pointer indicates the error
155        AtPointer     = 0,
156        /// Missing a required option
157        MissingOption = 1,
158        /// Bad length
159        BadLength     = 2
160    }
161}
162
163/// A read/write wrapper around an Internet Control Message Protocol version 4 packet buffer.
164#[derive(Debug, PartialEq, Eq, Clone)]
165#[cfg_attr(feature = "defmt", derive(defmt::Format))]
166pub struct Packet<T: AsRef<[u8]>> {
167    buffer: T,
168}
169
170mod field {
171    use crate::wire::field::*;
172
173    pub const TYPE: usize = 0;
174    pub const CODE: usize = 1;
175    pub const CHECKSUM: Field = 2..4;
176
177    pub const UNUSED: Field = 4..8;
178
179    pub const ECHO_IDENT: Field = 4..6;
180    pub const ECHO_SEQNO: Field = 6..8;
181
182    pub const HEADER_END: usize = 8;
183}
184
185impl<T: AsRef<[u8]>> Packet<T> {
186    /// Imbue a raw octet buffer with ICMPv4 packet structure.
187    pub const fn new_unchecked(buffer: T) -> Packet<T> {
188        Packet { buffer }
189    }
190
191    /// Shorthand for a combination of [new_unchecked] and [check_len].
192    ///
193    /// [new_unchecked]: #method.new_unchecked
194    /// [check_len]: #method.check_len
195    pub fn new_checked(buffer: T) -> Result<Packet<T>> {
196        let packet = Self::new_unchecked(buffer);
197        packet.check_len()?;
198        Ok(packet)
199    }
200
201    /// Ensure that no accessor method will panic if called.
202    /// Returns `Err(Error)` if the buffer is too short.
203    ///
204    /// The result of this check is invalidated by calling [set_header_len].
205    ///
206    /// [set_header_len]: #method.set_header_len
207    pub fn check_len(&self) -> Result<()> {
208        let len = self.buffer.as_ref().len();
209        if len < field::HEADER_END {
210            Err(Error)
211        } else {
212            Ok(())
213        }
214    }
215
216    /// Consume the packet, returning the underlying buffer.
217    pub fn into_inner(self) -> T {
218        self.buffer
219    }
220
221    /// Return the message type field.
222    #[inline]
223    pub fn msg_type(&self) -> Message {
224        let data = self.buffer.as_ref();
225        Message::from(data[field::TYPE])
226    }
227
228    /// Return the message code field.
229    #[inline]
230    pub fn msg_code(&self) -> u8 {
231        let data = self.buffer.as_ref();
232        data[field::CODE]
233    }
234
235    /// Return the checksum field.
236    #[inline]
237    pub fn checksum(&self) -> u16 {
238        let data = self.buffer.as_ref();
239        NetworkEndian::read_u16(&data[field::CHECKSUM])
240    }
241
242    /// Return the identifier field (for echo request and reply packets).
243    ///
244    /// # Panics
245    /// This function may panic if this packet is not an echo request or reply packet.
246    #[inline]
247    pub fn echo_ident(&self) -> u16 {
248        let data = self.buffer.as_ref();
249        NetworkEndian::read_u16(&data[field::ECHO_IDENT])
250    }
251
252    /// Return the sequence number field (for echo request and reply packets).
253    ///
254    /// # Panics
255    /// This function may panic if this packet is not an echo request or reply packet.
256    #[inline]
257    pub fn echo_seq_no(&self) -> u16 {
258        let data = self.buffer.as_ref();
259        NetworkEndian::read_u16(&data[field::ECHO_SEQNO])
260    }
261
262    /// Return the header length.
263    /// The result depends on the value of the message type field.
264    pub fn header_len(&self) -> usize {
265        match self.msg_type() {
266            Message::EchoRequest => field::ECHO_SEQNO.end,
267            Message::EchoReply => field::ECHO_SEQNO.end,
268            Message::DstUnreachable => field::UNUSED.end,
269            _ => field::UNUSED.end, // make a conservative assumption
270        }
271    }
272
273    /// Validate the header checksum.
274    ///
275    /// # Fuzzing
276    /// This function always returns `true` when fuzzing.
277    pub fn verify_checksum(&self) -> bool {
278        if cfg!(fuzzing) {
279            return true;
280        }
281
282        let data = self.buffer.as_ref();
283        checksum::data(data) == !0
284    }
285}
286
287impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
288    /// Return a pointer to the type-specific data.
289    #[inline]
290    pub fn data(&self) -> &'a [u8] {
291        let data = self.buffer.as_ref();
292        &data[self.header_len()..]
293    }
294}
295
296impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
297    /// Set the message type field.
298    #[inline]
299    pub fn set_msg_type(&mut self, value: Message) {
300        let data = self.buffer.as_mut();
301        data[field::TYPE] = value.into()
302    }
303
304    /// Set the message code field.
305    #[inline]
306    pub fn set_msg_code(&mut self, value: u8) {
307        let data = self.buffer.as_mut();
308        data[field::CODE] = value
309    }
310
311    /// Set the checksum field.
312    #[inline]
313    pub fn set_checksum(&mut self, value: u16) {
314        let data = self.buffer.as_mut();
315        NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
316    }
317
318    /// Set the identifier field (for echo request and reply packets).
319    ///
320    /// # Panics
321    /// This function may panic if this packet is not an echo request or reply packet.
322    #[inline]
323    pub fn set_echo_ident(&mut self, value: u16) {
324        let data = self.buffer.as_mut();
325        NetworkEndian::write_u16(&mut data[field::ECHO_IDENT], value)
326    }
327
328    /// Set the sequence number field (for echo request and reply packets).
329    ///
330    /// # Panics
331    /// This function may panic if this packet is not an echo request or reply packet.
332    #[inline]
333    pub fn set_echo_seq_no(&mut self, value: u16) {
334        let data = self.buffer.as_mut();
335        NetworkEndian::write_u16(&mut data[field::ECHO_SEQNO], value)
336    }
337
338    /// Compute and fill in the header checksum.
339    pub fn fill_checksum(&mut self) {
340        self.set_checksum(0);
341        let checksum = {
342            let data = self.buffer.as_ref();
343            !checksum::data(data)
344        };
345        self.set_checksum(checksum)
346    }
347}
348
349impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
350    /// Return a mutable pointer to the type-specific data.
351    #[inline]
352    pub fn data_mut(&mut self) -> &mut [u8] {
353        let range = self.header_len()..;
354        let data = self.buffer.as_mut();
355        &mut data[range]
356    }
357}
358
359impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
360    fn as_ref(&self) -> &[u8] {
361        self.buffer.as_ref()
362    }
363}
364
365/// A high-level representation of an Internet Control Message Protocol version 4 packet header.
366#[derive(Debug, PartialEq, Eq, Clone, Copy)]
367#[cfg_attr(feature = "defmt", derive(defmt::Format))]
368#[non_exhaustive]
369pub enum Repr<'a> {
370    EchoRequest {
371        ident: u16,
372        seq_no: u16,
373        data: &'a [u8],
374    },
375    EchoReply {
376        ident: u16,
377        seq_no: u16,
378        data: &'a [u8],
379    },
380    DstUnreachable {
381        reason: DstUnreachable,
382        header: Ipv4Repr,
383        data: &'a [u8],
384    },
385    TimeExceeded {
386        reason: TimeExceeded,
387        header: Ipv4Repr,
388        data: &'a [u8],
389    },
390}
391
392impl<'a> Repr<'a> {
393    /// Parse an Internet Control Message Protocol version 4 packet and return
394    /// a high-level representation.
395    pub fn parse<T>(
396        packet: &Packet<&'a T>,
397        checksum_caps: &ChecksumCapabilities,
398    ) -> Result<Repr<'a>>
399    where
400        T: AsRef<[u8]> + ?Sized,
401    {
402        packet.check_len()?;
403
404        // Valid checksum is expected.
405        if checksum_caps.icmpv4.rx() && !packet.verify_checksum() {
406            return Err(Error);
407        }
408
409        match (packet.msg_type(), packet.msg_code()) {
410            (Message::EchoRequest, 0) => Ok(Repr::EchoRequest {
411                ident: packet.echo_ident(),
412                seq_no: packet.echo_seq_no(),
413                data: packet.data(),
414            }),
415
416            (Message::EchoReply, 0) => Ok(Repr::EchoReply {
417                ident: packet.echo_ident(),
418                seq_no: packet.echo_seq_no(),
419                data: packet.data(),
420            }),
421
422            (Message::DstUnreachable, code) => {
423                let ip_packet = Ipv4Packet::new_checked(packet.data())?;
424
425                let payload = &packet.data()[ip_packet.header_len() as usize..];
426                // RFC 792 requires exactly eight bytes to be returned.
427                // We allow more, since there isn't a reason not to, but require at least eight.
428                if payload.len() < 8 {
429                    return Err(Error);
430                }
431
432                Ok(Repr::DstUnreachable {
433                    reason: DstUnreachable::from(code),
434                    header: Ipv4Repr {
435                        src_addr: ip_packet.src_addr(),
436                        dst_addr: ip_packet.dst_addr(),
437                        next_header: ip_packet.next_header(),
438                        payload_len: payload.len(),
439                        hop_limit: ip_packet.hop_limit(),
440                    },
441                    data: payload,
442                })
443            }
444
445            (Message::TimeExceeded, code) => {
446                let ip_packet = Ipv4Packet::new_checked(packet.data())?;
447
448                let payload = &packet.data()[ip_packet.header_len() as usize..];
449                // RFC 792 requires exactly eight bytes to be returned.
450                // We allow more, since there isn't a reason not to, but require at least eight.
451                if payload.len() < 8 {
452                    return Err(Error);
453                }
454
455                Ok(Repr::TimeExceeded {
456                    reason: TimeExceeded::from(code),
457                    header: Ipv4Repr {
458                        src_addr: ip_packet.src_addr(),
459                        dst_addr: ip_packet.dst_addr(),
460                        next_header: ip_packet.next_header(),
461                        payload_len: payload.len(),
462                        hop_limit: ip_packet.hop_limit(),
463                    },
464                    data: payload,
465                })
466            }
467
468            _ => Err(Error),
469        }
470    }
471
472    /// Return the length of a packet that will be emitted from this high-level representation.
473    pub const fn buffer_len(&self) -> usize {
474        match self {
475            &Repr::EchoRequest { data, .. } | &Repr::EchoReply { data, .. } => {
476                field::ECHO_SEQNO.end + data.len()
477            }
478            &Repr::DstUnreachable { header, data, .. }
479            | &Repr::TimeExceeded { header, data, .. } => {
480                field::UNUSED.end + header.buffer_len() + data.len()
481            }
482        }
483    }
484
485    /// Emit a high-level representation into an Internet Control Message Protocol version 4
486    /// packet.
487    pub fn emit<T>(&self, packet: &mut Packet<&mut T>, checksum_caps: &ChecksumCapabilities)
488    where
489        T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
490    {
491        packet.set_msg_code(0);
492        match *self {
493            Repr::EchoRequest {
494                ident,
495                seq_no,
496                data,
497            } => {
498                packet.set_msg_type(Message::EchoRequest);
499                packet.set_msg_code(0);
500                packet.set_echo_ident(ident);
501                packet.set_echo_seq_no(seq_no);
502                let data_len = cmp::min(packet.data_mut().len(), data.len());
503                packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
504            }
505
506            Repr::EchoReply {
507                ident,
508                seq_no,
509                data,
510            } => {
511                packet.set_msg_type(Message::EchoReply);
512                packet.set_msg_code(0);
513                packet.set_echo_ident(ident);
514                packet.set_echo_seq_no(seq_no);
515                let data_len = cmp::min(packet.data_mut().len(), data.len());
516                packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
517            }
518
519            Repr::DstUnreachable {
520                reason,
521                header,
522                data,
523            } => {
524                packet.set_msg_type(Message::DstUnreachable);
525                packet.set_msg_code(reason.into());
526
527                let mut ip_packet = Ipv4Packet::new_unchecked(packet.data_mut());
528                header.emit(&mut ip_packet, checksum_caps);
529                let payload = &mut ip_packet.into_inner()[header.buffer_len()..];
530                payload.copy_from_slice(data)
531            }
532
533            Repr::TimeExceeded {
534                reason,
535                header,
536                data,
537            } => {
538                packet.set_msg_type(Message::TimeExceeded);
539                packet.set_msg_code(reason.into());
540
541                let mut ip_packet = Ipv4Packet::new_unchecked(packet.data_mut());
542                header.emit(&mut ip_packet, checksum_caps);
543                let payload = &mut ip_packet.into_inner()[header.buffer_len()..];
544                payload.copy_from_slice(data)
545            }
546        }
547
548        if checksum_caps.icmpv4.tx() {
549            packet.fill_checksum()
550        } else {
551            // make sure we get a consistently zeroed checksum,
552            // since implementations might rely on it
553            packet.set_checksum(0);
554        }
555    }
556}
557
558impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
559    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
560        match Repr::parse(self, &ChecksumCapabilities::default()) {
561            Ok(repr) => write!(f, "{repr}"),
562            Err(err) => {
563                write!(f, "ICMPv4 ({err})")?;
564                write!(f, " type={:?}", self.msg_type())?;
565                match self.msg_type() {
566                    Message::DstUnreachable => {
567                        write!(f, " code={:?}", DstUnreachable::from(self.msg_code()))
568                    }
569                    Message::TimeExceeded => {
570                        write!(f, " code={:?}", TimeExceeded::from(self.msg_code()))
571                    }
572                    _ => write!(f, " code={}", self.msg_code()),
573                }
574            }
575        }
576    }
577}
578
579impl<'a> fmt::Display for Repr<'a> {
580    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
581        match *self {
582            Repr::EchoRequest {
583                ident,
584                seq_no,
585                data,
586            } => write!(
587                f,
588                "ICMPv4 echo request id={} seq={} len={}",
589                ident,
590                seq_no,
591                data.len()
592            ),
593            Repr::EchoReply {
594                ident,
595                seq_no,
596                data,
597            } => write!(
598                f,
599                "ICMPv4 echo reply id={} seq={} len={}",
600                ident,
601                seq_no,
602                data.len()
603            ),
604            Repr::DstUnreachable { reason, .. } => {
605                write!(f, "ICMPv4 destination unreachable ({reason})")
606            }
607            Repr::TimeExceeded { reason, .. } => {
608                write!(f, "ICMPv4 time exceeded ({reason})")
609            }
610        }
611    }
612}
613
614use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
615
616impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
617    fn pretty_print(
618        buffer: &dyn AsRef<[u8]>,
619        f: &mut fmt::Formatter,
620        indent: &mut PrettyIndent,
621    ) -> fmt::Result {
622        let packet = match Packet::new_checked(buffer) {
623            Err(err) => return write!(f, "{indent}({err})"),
624            Ok(packet) => packet,
625        };
626        write!(f, "{indent}{packet}")?;
627
628        match packet.msg_type() {
629            Message::DstUnreachable | Message::TimeExceeded => {
630                indent.increase(f)?;
631                super::Ipv4Packet::<&[u8]>::pretty_print(&packet.data(), f, indent)
632            }
633            _ => Ok(()),
634        }
635    }
636}
637
638#[cfg(test)]
639mod test {
640    use super::*;
641
642    static ECHO_PACKET_BYTES: [u8; 12] = [
643        0x08, 0x00, 0x8e, 0xfe, 0x12, 0x34, 0xab, 0xcd, 0xaa, 0x00, 0x00, 0xff,
644    ];
645
646    static ECHO_DATA_BYTES: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
647
648    #[test]
649    fn test_echo_deconstruct() {
650        let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
651        assert_eq!(packet.msg_type(), Message::EchoRequest);
652        assert_eq!(packet.msg_code(), 0);
653        assert_eq!(packet.checksum(), 0x8efe);
654        assert_eq!(packet.echo_ident(), 0x1234);
655        assert_eq!(packet.echo_seq_no(), 0xabcd);
656        assert_eq!(packet.data(), &ECHO_DATA_BYTES[..]);
657        assert!(packet.verify_checksum());
658    }
659
660    #[test]
661    fn test_echo_construct() {
662        let mut bytes = vec![0xa5; 12];
663        let mut packet = Packet::new_unchecked(&mut bytes);
664        packet.set_msg_type(Message::EchoRequest);
665        packet.set_msg_code(0);
666        packet.set_echo_ident(0x1234);
667        packet.set_echo_seq_no(0xabcd);
668        packet.data_mut().copy_from_slice(&ECHO_DATA_BYTES[..]);
669        packet.fill_checksum();
670        assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
671    }
672
673    fn echo_packet_repr() -> Repr<'static> {
674        Repr::EchoRequest {
675            ident: 0x1234,
676            seq_no: 0xabcd,
677            data: &ECHO_DATA_BYTES,
678        }
679    }
680
681    #[test]
682    fn test_echo_parse() {
683        let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
684        let repr = Repr::parse(&packet, &ChecksumCapabilities::default()).unwrap();
685        assert_eq!(repr, echo_packet_repr());
686    }
687
688    #[test]
689    fn test_echo_emit() {
690        let repr = echo_packet_repr();
691        let mut bytes = vec![0xa5; repr.buffer_len()];
692        let mut packet = Packet::new_unchecked(&mut bytes);
693        repr.emit(&mut packet, &ChecksumCapabilities::default());
694        assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
695    }
696
697    #[test]
698    fn test_check_len() {
699        let bytes = [0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
700        assert_eq!(Packet::new_checked(&[]), Err(Error));
701        assert_eq!(Packet::new_checked(&bytes[..4]), Err(Error));
702        assert!(Packet::new_checked(&bytes[..]).is_ok());
703    }
704}