1use crate::buffer::Buffer;
2use crate::error::{Error, Result};
3use std::fmt::{Debug, Formatter};
4
5#[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 => 8,
20 Self::EchoReply => 0,
21 Self::DestinationUnreachable => 3,
22 Self::TimeExceeded => 11,
23 Self::Other(id) => *id,
24 }
25 }
26}
27
28impl From<u8> for IcmpType {
29 fn from(val: u8) -> Self {
30 match val {
31 8 => Self::EchoRequest,
32 0 => Self::EchoReply,
33 3 => Self::DestinationUnreachable,
34 11 => Self::TimeExceeded,
35 id => Self::Other(id),
36 }
37 }
38}
39
40#[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#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
52pub enum IcmpTimeExceededCode {
53 TtlExpired,
55 FragmentReassembly,
57 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
75pub 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!([0x08], packet.packet()[0..1]);
171 packet.set_icmp_type(IcmpType::EchoReply);
172 assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
173 assert_eq!([0x00], packet.packet()[0..1]);
174 packet.set_icmp_type(IcmpType::DestinationUnreachable);
175 assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
176 assert_eq!([0x03], packet.packet()[0..1]);
177 packet.set_icmp_type(IcmpType::TimeExceeded);
178 assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
179 assert_eq!([0x0B], 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::icmpv4::{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 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!([0x08], packet.packet()[0..1]);
380 packet.set_icmp_type(IcmpType::EchoReply);
381 assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
382 assert_eq!([0x00], packet.packet()[0..1]);
383 packet.set_icmp_type(IcmpType::DestinationUnreachable);
384 assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
385 assert_eq!([0x03], packet.packet()[0..1]);
386 packet.set_icmp_type(IcmpType::TimeExceeded);
387 assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
388 assert_eq!([0x0B], 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 = [0x08, 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::icmpv4::{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 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!([0x08], packet.packet()[0..1]);
632 packet.set_icmp_type(IcmpType::EchoReply);
633 assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
634 assert_eq!([0x00], packet.packet()[0..1]);
635 packet.set_icmp_type(IcmpType::DestinationUnreachable);
636 assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
637 assert_eq!([0x03], packet.packet()[0..1]);
638 packet.set_icmp_type(IcmpType::TimeExceeded);
639 assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
640 assert_eq!([0x0B], 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 = [0x00, 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::icmpv4::{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 = 5;
754
755 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()) * 4;
867 let icmp_payload = &self.buf.as_slice()[Self::minimum_packet_size()..];
868 split(length, icmp_payload)
869 }
870 }
871
872 impl Debug for TimeExceededPacket<'_> {
873 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
874 f.debug_struct("TimeExceededPacket")
875 .field("icmp_type", &self.get_icmp_type())
876 .field("icmp_code", &self.get_icmp_code())
877 .field("checksum", &self.get_checksum())
878 .field("length", &self.get_length())
879 .field("payload", &fmt_payload(self.payload()))
880 .finish()
881 }
882 }
883
884 #[cfg(test)]
885 mod tests {
886 use super::*;
887
888 #[test]
889 fn test_icmp_type() {
890 let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
891 let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
892 packet.set_icmp_type(IcmpType::EchoRequest);
893 assert_eq!(IcmpType::EchoRequest, packet.get_icmp_type());
894 assert_eq!([0x08], packet.packet()[0..1]);
895 packet.set_icmp_type(IcmpType::EchoReply);
896 assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
897 assert_eq!([0x00], packet.packet()[0..1]);
898 packet.set_icmp_type(IcmpType::DestinationUnreachable);
899 assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
900 assert_eq!([0x03], packet.packet()[0..1]);
901 packet.set_icmp_type(IcmpType::TimeExceeded);
902 assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
903 assert_eq!([0x0B], packet.packet()[0..1]);
904 packet.set_icmp_type(IcmpType::Other(255));
905 assert_eq!(IcmpType::Other(255), packet.get_icmp_type());
906 assert_eq!([0xFF], packet.packet()[0..1]);
907 }
908
909 #[test]
910 fn test_icmp_code() {
911 let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
912 let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
913 packet.set_icmp_code(IcmpCode(0));
914 assert_eq!(IcmpCode(0), packet.get_icmp_code());
915 assert_eq!([0x00], packet.packet()[1..2]);
916 packet.set_icmp_code(IcmpCode(5));
917 assert_eq!(IcmpCode(5), packet.get_icmp_code());
918 assert_eq!([0x05], packet.packet()[1..2]);
919 packet.set_icmp_code(IcmpCode(255));
920 assert_eq!(IcmpCode(255), packet.get_icmp_code());
921 assert_eq!([0xFF], packet.packet()[1..2]);
922 }
923
924 #[test]
925 fn test_checksum() {
926 let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
927 let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
928 packet.set_checksum(0);
929 assert_eq!(0, packet.get_checksum());
930 assert_eq!([0x00, 0x00], packet.packet()[2..=3]);
931 packet.set_checksum(1999);
932 assert_eq!(1999, packet.get_checksum());
933 assert_eq!([0x07, 0xCF], packet.packet()[2..=3]);
934 packet.set_checksum(u16::MAX);
935 assert_eq!(u16::MAX, packet.get_checksum());
936 assert_eq!([0xFF, 0xFF], packet.packet()[2..=3]);
937 }
938
939 #[test]
940 fn test_length() {
941 let mut buf = [0_u8; TimeExceededPacket::minimum_packet_size()];
942 let mut packet = TimeExceededPacket::new(&mut buf).unwrap();
943 packet.set_length(0);
944 assert_eq!(0, packet.get_length());
945 assert_eq!([0x00], packet.packet()[5..6]);
946 packet.set_length(8);
947 assert_eq!(8, packet.get_length());
948 assert_eq!([0x08], packet.packet()[5..6]);
949 packet.set_length(u8::MAX);
950 assert_eq!(u8::MAX, packet.get_length());
951 assert_eq!([0xFF], packet.packet()[5..6]);
952 }
953
954 #[test]
955 fn test_view() {
956 let buf = [0x0b, 0x00, 0xf4, 0xee, 0x00, 0x11, 0x00, 0x00];
957 let packet = TimeExceededPacket::new_view(&buf).unwrap();
958 assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
959 assert_eq!(IcmpCode(0), packet.get_icmp_code());
960 assert_eq!(62702, packet.get_checksum());
961 assert_eq!(17, packet.get_length());
962 assert!(packet.payload().is_empty());
963 }
964
965 #[test]
966 fn test_view_large() {
967 let mut buf = [0x0_u8; 256];
968 buf[..8].copy_from_slice(&[0x0b, 0x00, 0xf4, 0xee, 0x00, 0x40, 0x00, 0x00]);
969 let packet = TimeExceededPacket::new_view(&buf).unwrap();
970 assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
971 assert_eq!(IcmpCode(0), packet.get_icmp_code());
972 assert_eq!(62702, packet.get_checksum());
973 assert_eq!(64, packet.get_length());
974 assert_eq!(&[0x0_u8; 248], packet.payload());
975 assert_eq!(None, packet.extension());
976 }
977
978 #[test]
979 fn test_new_insufficient_buffer() {
980 const SIZE: usize = TimeExceededPacket::minimum_packet_size();
981 let mut buf = [0_u8; SIZE - 1];
982 let err = TimeExceededPacket::new(&mut buf).unwrap_err();
983 assert_eq!(
984 Error::InsufficientPacketBuffer(String::from("TimeExceededPacket"), SIZE, SIZE - 1),
985 err
986 );
987 }
988
989 #[test]
990 fn test_new_view_insufficient_buffer() {
991 const SIZE: usize = TimeExceededPacket::minimum_packet_size();
992 let buf = [0_u8; SIZE - 1];
993 let err = TimeExceededPacket::new_view(&buf).unwrap_err();
994 assert_eq!(
995 Error::InsufficientPacketBuffer(String::from("TimeExceededPacket"), SIZE, SIZE - 1),
996 err
997 );
998 }
999 }
1000}
1001
1002pub mod destination_unreachable {
1003 use crate::buffer::Buffer;
1004 use crate::error::{Error, Result};
1005 use crate::fmt_payload;
1006 use crate::icmp_extension::extension_splitter::split;
1007 use crate::icmpv4::{IcmpCode, IcmpType};
1008 use std::fmt::{Debug, Formatter};
1009
1010 const TYPE_OFFSET: usize = 0;
1011 const CODE_OFFSET: usize = 1;
1012 const CHECKSUM_OFFSET: usize = 2;
1013 const LENGTH_OFFSET: usize = 5;
1014 const NEXT_HOP_MTU_OFFSET: usize = 6;
1015
1016 pub struct DestinationUnreachablePacket<'a> {
1022 buf: Buffer<'a>,
1023 }
1024
1025 impl<'a> DestinationUnreachablePacket<'a> {
1026 pub fn new(packet: &'a mut [u8]) -> Result<Self> {
1027 if packet.len() >= Self::minimum_packet_size() {
1028 Ok(Self {
1029 buf: Buffer::Mutable(packet),
1030 })
1031 } else {
1032 Err(Error::InsufficientPacketBuffer(
1033 String::from("DestinationUnreachablePacket"),
1034 Self::minimum_packet_size(),
1035 packet.len(),
1036 ))
1037 }
1038 }
1039
1040 pub fn new_view(packet: &'a [u8]) -> Result<Self> {
1041 if packet.len() >= Self::minimum_packet_size() {
1042 Ok(Self {
1043 buf: Buffer::Immutable(packet),
1044 })
1045 } else {
1046 Err(Error::InsufficientPacketBuffer(
1047 String::from("DestinationUnreachablePacket"),
1048 Self::minimum_packet_size(),
1049 packet.len(),
1050 ))
1051 }
1052 }
1053
1054 #[must_use]
1055 pub const fn minimum_packet_size() -> usize {
1056 8
1057 }
1058
1059 #[must_use]
1060 pub fn get_icmp_type(&self) -> IcmpType {
1061 IcmpType::from(self.buf.read(TYPE_OFFSET))
1062 }
1063
1064 #[must_use]
1065 pub fn get_icmp_code(&self) -> IcmpCode {
1066 IcmpCode::from(self.buf.read(CODE_OFFSET))
1067 }
1068
1069 #[must_use]
1070 pub fn get_checksum(&self) -> u16 {
1071 u16::from_be_bytes(self.buf.get_bytes(CHECKSUM_OFFSET))
1072 }
1073
1074 #[must_use]
1075 pub fn get_length(&self) -> u8 {
1076 self.buf.read(LENGTH_OFFSET)
1077 }
1078
1079 #[must_use]
1080 pub fn get_next_hop_mtu(&self) -> u16 {
1081 u16::from_be_bytes(self.buf.get_bytes(NEXT_HOP_MTU_OFFSET))
1082 }
1083
1084 pub fn set_icmp_type(&mut self, val: IcmpType) {
1085 *self.buf.write(TYPE_OFFSET) = val.id();
1086 }
1087
1088 pub fn set_icmp_code(&mut self, val: IcmpCode) {
1089 *self.buf.write(CODE_OFFSET) = val.0;
1090 }
1091
1092 pub fn set_checksum(&mut self, val: u16) {
1093 self.buf.set_bytes(CHECKSUM_OFFSET, val.to_be_bytes());
1094 }
1095
1096 pub fn set_length(&mut self, val: u8) {
1097 *self.buf.write(LENGTH_OFFSET) = val;
1098 }
1099
1100 pub fn set_next_hop_mtu(&mut self, val: u16) {
1101 self.buf.set_bytes(NEXT_HOP_MTU_OFFSET, val.to_be_bytes());
1102 }
1103
1104 pub fn set_payload(&mut self, vals: &[u8]) {
1105 let current_offset = Self::minimum_packet_size();
1106 self.buf.as_slice_mut()[current_offset..current_offset + vals.len()]
1107 .copy_from_slice(vals);
1108 }
1109
1110 #[must_use]
1111 pub fn packet(&self) -> &[u8] {
1112 self.buf.as_slice()
1113 }
1114
1115 #[must_use]
1116 pub fn payload(&self) -> &[u8] {
1117 let (payload, _) = self.split_payload_extension();
1118 payload
1119 }
1120
1121 #[must_use]
1122 pub fn payload_raw(&self) -> &[u8] {
1123 &self.buf.as_slice()[Self::minimum_packet_size()..]
1124 }
1125
1126 #[must_use]
1127 pub fn extension(&self) -> Option<&[u8]> {
1128 let (_, extension) = self.split_payload_extension();
1129 extension
1130 }
1131
1132 fn split_payload_extension(&self) -> (&[u8], Option<&[u8]>) {
1133 let length = usize::from(self.get_length()) * 4;
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!([0x08], packet.packet()[0..1]);
1163 packet.set_icmp_type(IcmpType::EchoReply);
1164 assert_eq!(IcmpType::EchoReply, packet.get_icmp_type());
1165 assert_eq!([0x00], packet.packet()[0..1]);
1166 packet.set_icmp_type(IcmpType::DestinationUnreachable);
1167 assert_eq!(IcmpType::DestinationUnreachable, packet.get_icmp_type());
1168 assert_eq!([0x03], packet.packet()[0..1]);
1169 packet.set_icmp_type(IcmpType::TimeExceeded);
1170 assert_eq!(IcmpType::TimeExceeded, packet.get_icmp_type());
1171 assert_eq!([0x0B], 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()[5..6]);
1214 packet.set_length(8);
1215 assert_eq!(8, packet.get_length());
1216 assert_eq!([0x08], packet.packet()[5..6]);
1217 packet.set_length(u8::MAX);
1218 assert_eq!(u8::MAX, packet.get_length());
1219 assert_eq!([0xFF], packet.packet()[5..6]);
1220 }
1221
1222 #[test]
1223 fn test_view() {
1224 let buf = [0x03, 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; 256];
1236 buf[..8].copy_from_slice(&[0x03, 0x03, 0xdf, 0xdc, 0x00, 0x40, 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!(64, packet.get_length());
1242 assert_eq!(&[0x0_u8; 248], 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}