1use crate::*;
2use arrayvec::ArrayVec;
3
4#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct Icmpv4Header {
11 pub icmp_type: Icmpv4Type,
13 pub checksum: u16,
15}
16
17impl Icmpv4Header {
18 pub const MIN_LEN: usize = 8;
21
22 #[deprecated(since = "0.14.0", note = "Please use Icmpv4Header::MIN_LEN instead")]
24 pub const MIN_SERIALIZED_SIZE: usize = 8;
25
26 pub const MAX_LEN: usize = 20;
33
34 #[deprecated(since = "0.14.0", note = "Please use Icmpv4Header::MAX_LEN instead")]
36 pub const MAX_SERIALIZED_SIZE: usize = 20;
37
38 pub fn new(icmp_type: Icmpv4Type) -> Icmpv4Header {
41 Icmpv4Header {
43 icmp_type,
44 checksum: 0,
45 }
46 }
47
48 pub fn with_checksum(icmp_type: Icmpv4Type, payload: &[u8]) -> Icmpv4Header {
50 let checksum = icmp_type.calc_checksum(payload);
51 Icmpv4Header {
52 icmp_type,
53 checksum,
54 }
55 }
56
57 #[inline]
59 pub fn from_slice(slice: &[u8]) -> Result<(Icmpv4Header, &[u8]), err::LenError> {
60 let header = Icmpv4Slice::from_slice(slice)?.header();
61 let rest = &slice[header.header_len()..];
62 Ok((header, rest))
63 }
64
65 #[cfg(feature = "std")]
67 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
68 pub fn read<T: std::io::Read + Sized>(reader: &mut T) -> Result<Icmpv4Header, std::io::Error> {
69 let mut bytes = [0u8; Icmpv4Header::MAX_LEN];
70
71 reader.read_exact(&mut bytes[..8])?;
73
74 match bytes[0] {
75 icmpv4::TYPE_TIMESTAMP_REPLY | icmpv4::TYPE_TIMESTAMP => {
76 if 0 == bytes[1] {
77 reader.read_exact(&mut bytes[8..icmpv4::TimestampMessage::LEN])?;
80 Ok(Icmpv4Slice {
81 slice: &bytes[..icmpv4::TimestampMessage::LEN],
82 }
83 .header())
84 } else {
85 Ok(Icmpv4Slice { slice: &bytes[..8] }.header())
87 }
88 }
89 _ => Ok(Icmpv4Slice { slice: &bytes[..8] }.header()),
90 }
91 }
92
93 #[cfg(feature = "std")]
95 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
96 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
97 writer.write_all(&self.to_bytes())
98 }
99
100 #[inline]
102 pub fn header_len(&self) -> usize {
103 self.icmp_type.header_len()
104 }
105
106 #[inline]
109 pub fn fixed_payload_size(&self) -> Option<usize> {
110 self.icmp_type.fixed_payload_size()
111 }
112
113 pub fn update_checksum(&mut self, payload: &[u8]) {
118 self.checksum = self.icmp_type.calc_checksum(payload);
119 }
120
121 #[rustfmt::skip]
123 pub fn to_bytes(&self) -> ArrayVec<u8, { Icmpv4Header::MAX_LEN }> {
124 let checksum_be = self.checksum.to_be_bytes();
125 let re_zero =
126 |type_u8: u8, code_u8: u8| -> ArrayVec<u8, { Icmpv4Header::MAX_LEN }> {
127
128 #[rustfmt::skip]
129 let mut re = ArrayVec::from([
130 type_u8, code_u8, checksum_be[0], checksum_be[1],
131 0, 0, 0, 0,
132 0, 0, 0, 0,
133 0, 0, 0, 0,
134 0, 0, 0, 0,
135 ]);
136 unsafe {
138 re.set_len(8);
139 }
140 re
141 };
142
143 let re_2u16 = |type_u8: u8,
144 code_u8: u8,
145 a_u16: u16,
146 b_u16: u16|
147 -> ArrayVec<u8, { Icmpv4Header::MAX_LEN }> {
148 let a = a_u16.to_be_bytes();
149 let b = b_u16.to_be_bytes();
150
151 #[rustfmt::skip]
152 let mut re = ArrayVec::from([
153 type_u8, code_u8, checksum_be[0], checksum_be[1],
154 a[0], a[1], b[0], b[1],
155 0, 0, 0, 0,
156 0, 0, 0, 0,
157 0, 0, 0, 0,
158 ]);
159 unsafe {
161 re.set_len(8);
162 }
163 re
164 };
165
166 let re_4u8 = |type_u8: u8,
167 code_u8: u8,
168 bytes5to8: [u8; 4]|
169 -> ArrayVec<u8, { Icmpv4Header::MAX_LEN }> {
170
171 #[rustfmt::skip]
172 let mut re = ArrayVec::from([
173 type_u8, code_u8, checksum_be[0], checksum_be[1],
174 bytes5to8[0], bytes5to8[1], bytes5to8[2], bytes5to8[3],
175 0, 0, 0, 0,
176 0, 0, 0, 0,
177 0, 0, 0, 0,
178 ]);
179 unsafe {
181 re.set_len(8);
182 }
183 re
184 };
185
186 let re_timestamp_msg = |type_u8: u8,
187 msg: &icmpv4::TimestampMessage|
188 -> ArrayVec<u8, { Icmpv4Header::MAX_LEN }> {
189 let id = msg.id.to_be_bytes();
190 let seq = msg.seq.to_be_bytes();
191 let o = msg.originate_timestamp.to_be_bytes();
192 let r = msg.receive_timestamp.to_be_bytes();
193 let t = msg.transmit_timestamp.to_be_bytes();
194
195 ArrayVec::from([
196 type_u8, 0, checksum_be[0], checksum_be[1],
197 id[0], id[1], seq[0], seq[1],
198 o[0], o[1], o[2], o[3],
199 r[0], r[1], r[2], r[3],
200 t[0], t[1], t[2], t[3],
201 ])
202 };
203
204 use Icmpv4Type::*;
205 use icmpv4::*;
206 match self.icmp_type {
207 Unknown {
208 type_u8,
209 code_u8,
210 bytes5to8,
211 } => re_4u8(type_u8, code_u8, bytes5to8),
212 EchoReply(echo) => re_2u16(TYPE_ECHO_REPLY, 0, echo.id, echo.seq),
213 DestinationUnreachable(ref dest) => {
214 use DestUnreachableHeader::*;
215 match dest {
216 Network => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_NET),
217 Host => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_HOST),
218 Protocol => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_PROTOCOL),
219 Port => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_PORT),
220 FragmentationNeeded { next_hop_mtu } => {
221 let m_be = next_hop_mtu.to_be_bytes();
222 re_4u8(
223 TYPE_DEST_UNREACH,
224 CODE_DST_UNREACH_NEED_FRAG,
225 [0, 0, m_be[0], m_be[1]],
226 )
227 }
228 SourceRouteFailed => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_SOURCE_ROUTE_FAILED),
229 NetworkUnknown => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_NET_UNKNOWN),
230 HostUnknown => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_HOST_UNKNOWN),
231 Isolated => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_ISOLATED),
232 NetworkProhibited => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_NET_PROHIB),
233 HostProhibited => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_HOST_PROHIB),
234 TosNetwork => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_TOS_NET),
235 TosHost => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_TOS_HOST),
236 FilterProhibited => re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_FILTER_PROHIB),
237 HostPrecedenceViolation => re_zero(
238 TYPE_DEST_UNREACH,
239 CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION,
240 ),
241 PrecedenceCutoff => {
242 re_zero(TYPE_DEST_UNREACH, CODE_DST_UNREACH_PRECEDENCE_CUTOFF)
243 }
244 }
245 }
246 Redirect(ref msg) => {
247 re_4u8(TYPE_REDIRECT, msg.code as u8, msg.gateway_internet_address)
248 }
249 EchoRequest(echo) => re_2u16(TYPE_ECHO_REQUEST, 0, echo.id, echo.seq),
250 TimeExceeded(code) => re_zero(TYPE_TIME_EXCEEDED, code as u8),
251 ParameterProblem(ref header) => {
252 use ParameterProblemHeader::*;
253 match header {
254 PointerIndicatesError(pointer) => re_4u8(
255 TYPE_PARAMETER_PROBLEM,
256 CODE_PARAMETER_PROBLEM_POINTER_INDICATES_ERROR,
257 [*pointer, 0, 0, 0],
258 ),
259 MissingRequiredOption => re_zero(
260 TYPE_PARAMETER_PROBLEM,
261 CODE_PARAMETER_PROBLEM_MISSING_REQUIRED_OPTION,
262 ),
263 BadLength => re_zero(TYPE_PARAMETER_PROBLEM, CODE_PARAMETER_PROBLEM_BAD_LENGTH),
264 }
265 }
266 TimestampRequest(ref msg) => re_timestamp_msg(TYPE_TIMESTAMP, msg),
267 TimestampReply(ref msg) => re_timestamp_msg(TYPE_TIMESTAMP_REPLY, msg),
268 }
269 }
270}
271
272#[cfg(test)]
273mod test {
274 use crate::{
275 err::{Layer, LenError},
276 icmpv4::*,
277 test_gens::*,
278 *,
279 };
280 use alloc::{format, vec::Vec};
281 use proptest::prelude::*;
282
283 #[test]
284 #[allow(deprecated)]
285 fn constants() {
286 assert_eq!(8, Icmpv4Header::MIN_LEN);
287 assert_eq!(20, Icmpv4Header::MAX_LEN);
288 assert_eq!(8, Icmpv4Header::MIN_SERIALIZED_SIZE);
289 assert_eq!(20, Icmpv4Header::MAX_SERIALIZED_SIZE);
290 }
291
292 proptest! {
293 #[test]
294 fn new(icmpv4_type in icmpv4_type_any()) {
295 assert_eq!(
296 Icmpv4Header {
297 icmp_type: icmpv4_type.clone(),
298 checksum: 0,
299 },
300 Icmpv4Header::new(icmpv4_type)
301 );
302 }
303 }
304
305 proptest! {
306 #[test]
307 fn with_checksum(
308 icmpv4_type in icmpv4_type_any(),
309 payload in proptest::collection::vec(any::<u8>(), 0..1024),
310 ) {
311 assert_eq!(
312 Icmpv4Header {
313 icmp_type: icmpv4_type.clone(),
314 checksum: icmpv4_type.calc_checksum(&payload),
315 },
316 Icmpv4Header::with_checksum(icmpv4_type, &payload)
317 );
318 }
319 }
320
321 proptest! {
322 #[test]
323 fn from_slice(
324 icmpv4_type in icmpv4_type_any(),
325 checksum in any::<u16>(),
326 payload in proptest::collection::vec(any::<u8>(), 0..1024),
327 ) {
328 use Icmpv4Type::*;
329
330 let header = Icmpv4Header {
332 icmp_type: icmpv4_type.clone(),
333 checksum: checksum,
334 };
335 let buffer = {
336 let mut buffer = Vec::with_capacity(header.header_len() + payload.len());
337 buffer.extend_from_slice(&header.to_bytes());
338
339 match icmpv4_type {
340 TimestampRequest(_) | TimestampReply(_) => {},
342 _ => {
343 buffer.extend_from_slice(&[0u8;36]);
344 }
345 }
346 buffer
347 };
348 {
349 let (actual, rest) = Icmpv4Header::from_slice(&buffer).unwrap();
350 assert_eq!(actual, header);
351 assert_eq!(rest, &buffer[header.header_len()..]);
352 }
353
354 for bad_len in 0..header.header_len() {
356 assert_eq!(
357 Icmpv4Header::from_slice(&buffer[..bad_len]),
358 Err(LenError{
359 required_len: if bad_len < Icmpv4Header::MIN_LEN {
360 Icmpv4Header::MIN_LEN
361 } else {
362 header.header_len()
363 },
364 len: bad_len,
365 len_source: LenSource::Slice,
366 layer: if bad_len < Icmpv4Header::MIN_LEN {
367 Layer::Icmpv4
368 } else {
369 use crate::Icmpv4Type::*;
370 match icmpv4_type {
371 TimestampRequest(_) => Layer::Icmpv4Timestamp,
372 TimestampReply(_) => Layer::Icmpv4TimestampReply,
373 _ => Layer::Icmpv4,
374 }
375 },
376 layer_start_offset: 0,
377 })
378 );
379 }
380 }
381 }
382
383 proptest! {
384 #[test]
385 fn read(
386 non_timestamp_type in any::<u8>().prop_filter(
387 "type must be a non timestamp type",
388 |v| (*v != icmpv4::TYPE_TIMESTAMP_REPLY && *v != icmpv4::TYPE_TIMESTAMP)
389 ),
390 non_zero_code in 1u8..=u8::MAX,
391 bytes in any::<[u8;icmpv4::TimestampMessage::LEN]>()
392 ) {
393 for (type_u8, code_u8) in [
394 (non_timestamp_type, bytes[1]),
396 (TYPE_TIMESTAMP_REPLY, 0u8),
398 (TYPE_TIMESTAMP, 0u8),
399 (TYPE_TIMESTAMP_REPLY, non_zero_code),
401 (TYPE_TIMESTAMP, non_zero_code),
402 ] {
403 let b = {
404 let mut b = bytes.clone();
405 b[0] = type_u8;
406 b[1] = code_u8;
407 b
408 };
409 let expected = Icmpv4Header::from_slice(&b).unwrap().0;
410
411 {
413 let mut cursor = std::io::Cursor::new(&b);
414 let actual = Icmpv4Header::read(&mut cursor).unwrap();
415 assert_eq!(expected, actual);
416 assert_eq!(expected.header_len() as u64, cursor.position());
417 }
418
419 for bad_len in 0..expected.header_len() {
421 let mut cursor = std::io::Cursor::new(&(b.as_ref()[..bad_len]));
422 assert!(Icmpv4Header::read(&mut cursor).is_err());
423 }
424 }
425 }
426 }
427
428 proptest! {
429 #[test]
430 fn write(
431 icmpv4_type in icmpv4_type_any(),
432 checksum in any::<u16>(),
433 ) {
434 let header = Icmpv4Header {
435 icmp_type: icmpv4_type.clone(),
436 checksum,
437 };
438
439 {
441 let bytes = header.to_bytes();
442 let mut buffer = Vec::with_capacity(header.header_len());
443 header.write(&mut buffer).unwrap();
444 assert_eq!(&bytes[..], &buffer[..]);
445 }
446
447 {
449 for bad_len in 0..icmpv4_type.header_len() {
450 let mut bytes = [0u8;Icmpv6Header::MAX_LEN];
451 let mut writer = std::io::Cursor::new(&mut bytes[..bad_len]);
452 header.write(&mut writer).unwrap_err();
453 }
454 }
455 }
456 }
457
458 proptest! {
459 #[test]
460 fn header_len(
461 checksum in any::<u16>(),
462 icmpv4_type in icmpv4_type_any()
463 ) {
464 let header = Icmpv4Header{
465 icmp_type: icmpv4_type.clone(),
466 checksum,
467 };
468 assert_eq!(header.header_len(), icmpv4_type.header_len());
469 }
470 }
471
472 proptest! {
473 #[test]
474 fn fixed_payload_size(
475 checksum in any::<u16>(),
476 icmpv4_type in icmpv4_type_any()
477 ) {
478 let header = Icmpv4Header{
479 icmp_type: icmpv4_type.clone(),
480 checksum,
481 };
482 assert_eq!(header.fixed_payload_size(), icmpv4_type.fixed_payload_size());
483 }
484 }
485
486 proptest! {
487 #[test]
488 fn update_checksum(
489 icmpv4_type in icmpv4_type_any(),
490 checksum in any::<u16>(),
491 payload in proptest::collection::vec(any::<u8>(), 0..1024),
492 ) {
493 let mut header = Icmpv4Header {
494 icmp_type: icmpv4_type.clone(),
495 checksum,
496 };
497 header.update_checksum(&payload);
498 assert_eq!(header.checksum, icmpv4_type.calc_checksum(&payload));
499 }
500 }
501
502 proptest! {
503 #[test]
504 #[rustfmt::skip]
505 fn to_bytes(
506 checksum in any::<u16>(),
507 next_hop_mtu in any::<u16>(),
508 redirect_code_u8 in 0u8..=3,
509 gateway_internet_address in any::<[u8;4]>(),
510 time_exceeded_code_u8 in 0u8..=1,
511 id in any::<u16>(),
512 seq in any::<u16>(),
513 originate_timestamp in any::<u32>(),
514 receive_timestamp in any::<u32>(),
515 transmit_timestamp in any::<u32>(),
516 pointer in any::<u8>(),
517 unknown_type_u8 in any::<u8>(),
518 unknown_code_u8 in any::<u8>(),
519 bytes5to8 in any::<[u8;4]>(),
520 ) {
521 use Icmpv4Type::*;
522 use arrayvec::ArrayVec;
523
524 let ts = TimestampMessage{
525 id,
526 seq,
527 originate_timestamp,
528 receive_timestamp,
529 transmit_timestamp,
530 };
531 let ts_bytes = {
532 let id_be = id.to_be_bytes();
533 let seq_be = seq.to_be_bytes();
534 let ot = originate_timestamp.to_be_bytes();
535 let rt = receive_timestamp.to_be_bytes();
536 let tt = transmit_timestamp.to_be_bytes();
537 [
538 0, 0, 0, 0,
539 id_be[0], id_be[1], seq_be[0], seq_be[1],
540 ot[0], ot[1], ot[2], ot[3],
541 rt[0], rt[1], rt[2], rt[3],
542 tt[0], tt[1], tt[2], tt[3],
543 ]
544 };
545 let echo = IcmpEchoHeader{
546 id,
547 seq,
548 };
549 let redirect = RedirectHeader{
550 code: RedirectCode::from_u8(redirect_code_u8).unwrap(),
551 gateway_internet_address,
552 };
553
554 let random_values = [
556 (
557 Unknown {
558 type_u8: unknown_type_u8,
559 code_u8: unknown_code_u8,
560 bytes5to8: bytes5to8,
561 },
562 8,
563 [
564 unknown_type_u8, unknown_code_u8, 0, 0,
565 bytes5to8[0], bytes5to8[1], bytes5to8[2], bytes5to8[3],
566 0, 0, 0, 0,
567 0, 0, 0, 0,
568 0, 0, 0, 0,
569 ],
570 ),
571 (
572 EchoReply(echo.clone()),
573 8,
574 {
575 let id_be = id.to_be_bytes();
576 let seq_be = seq.to_be_bytes();
577 [
578 TYPE_ECHO_REPLY, 0, 0, 0,
579 id_be[0], id_be[1], seq_be[0], seq_be[1],
580 0, 0, 0, 0,
581 0, 0, 0, 0,
582 0, 0, 0, 0,
583 ]
584 }
585 ),
586
587 (
588 Redirect(redirect),
589 8,
590 {
591 let gip = gateway_internet_address;
592 [
593 TYPE_REDIRECT, redirect_code_u8, 0, 0,
594 gip[0], gip[1], gip[2], gip[3],
595 0, 0, 0, 0,
596 0, 0, 0, 0,
597 0, 0, 0, 0,
598 ]
599 },
600 ),
601 (
602 EchoRequest(echo.clone()),
603 8,
604 {
605 let id_be = id.to_be_bytes();
606 let seq_be = seq.to_be_bytes();
607 [
608 TYPE_ECHO_REQUEST, 0, 0, 0,
609 id_be[0], id_be[1], seq_be[0], seq_be[1],
610 0, 0, 0, 0,
611 0, 0, 0, 0,
612 0, 0, 0, 0,
613 ]
614 }
615 ),
616 (
617 TimeExceeded(TimeExceededCode::from_u8(time_exceeded_code_u8).unwrap()),
618 8,
619 [
620 TYPE_TIME_EXCEEDED, time_exceeded_code_u8, 0, 0,
621 0, 0, 0, 0,
622 0, 0, 0, 0,
623 0, 0, 0, 0,
624 0, 0, 0, 0,
625 ],
626 ),
627 (
628 TimestampRequest(ts.clone()),
629 20,
630 {
631 let mut b = ts_bytes;
632 b[0] = TYPE_TIMESTAMP;
633 b
634 }
635 ),
636 (
637 TimestampReply(ts),
638 20,
639 {
640 let mut b = ts_bytes;
641 b[0] = TYPE_TIMESTAMP_REPLY;
642 b
643 }
644 ),
645 ];
646
647 for t in random_values {
648 let actual = Icmpv4Header{
649 icmp_type: t.0.clone(),
650 checksum,
651 }.to_bytes();
652
653 let mut expected = ArrayVec::from(t.2);
654 unsafe {
655 expected.set_len(t.1)
656 }
657 let checksum_be = checksum.to_be_bytes();
658 expected[2] = checksum_be[0];
659 expected[3] = checksum_be[1];
660 assert_eq!(expected, actual);
661 }
662
663 {
665 use DestUnreachableHeader::*;
666 let tests = [
667 (CODE_DST_UNREACH_NET, [0;2], Network),
668 (CODE_DST_UNREACH_HOST, [0;2], Host),
669 (CODE_DST_UNREACH_PROTOCOL, [0;2], Protocol),
670 (CODE_DST_UNREACH_PORT, [0;2], Port),
671 (CODE_DST_UNREACH_NEED_FRAG, next_hop_mtu.to_be_bytes(), FragmentationNeeded{ next_hop_mtu }),
672 (CODE_DST_UNREACH_SOURCE_ROUTE_FAILED, [0;2], SourceRouteFailed),
673 (CODE_DST_UNREACH_NET_UNKNOWN, [0;2], NetworkUnknown),
674 (CODE_DST_UNREACH_HOST_UNKNOWN, [0;2], HostUnknown),
675 (CODE_DST_UNREACH_ISOLATED, [0;2], Isolated),
676 (CODE_DST_UNREACH_NET_PROHIB, [0;2], NetworkProhibited),
677 (CODE_DST_UNREACH_HOST_PROHIB, [0;2], HostProhibited),
678 (CODE_DST_UNREACH_TOS_NET, [0;2], TosNetwork),
679 (CODE_DST_UNREACH_TOS_HOST, [0;2], TosHost),
680 (CODE_DST_UNREACH_FILTER_PROHIB, [0;2], FilterProhibited),
681 (CODE_DST_UNREACH_HOST_PRECEDENCE_VIOLATION, [0;2], HostPrecedenceViolation),
682 (CODE_DST_UNREACH_PRECEDENCE_CUTOFF, [0;2], PrecedenceCutoff),
683 ];
684 for t in tests {
685 let checksum_be = checksum.to_be_bytes();
686 let mut expected = ArrayVec::from([
687 TYPE_DEST_UNREACH, t.0, checksum_be[0], checksum_be[1],
688 0, 0, t.1[0], t.1[1],
689 0, 0, 0, 0,
690 0, 0, 0, 0,
691 0, 0, 0, 0,
692 ]);
693 unsafe {
694 expected.set_len(8);
695 }
696 let actual = Icmpv4Header{
697 icmp_type: DestinationUnreachable(t.2.clone()),
698 checksum,
699 }.to_bytes();
700 assert_eq!(expected, actual);
701 }
702 }
703
704 {
706 use ParameterProblemHeader::*;
707 let tests = [
708 (CODE_PARAMETER_PROBLEM_POINTER_INDICATES_ERROR, pointer, PointerIndicatesError(pointer)),
709 (CODE_PARAMETER_PROBLEM_MISSING_REQUIRED_OPTION, 0, MissingRequiredOption),
710 (CODE_PARAMETER_PROBLEM_BAD_LENGTH, 0, BadLength),
711 ];
712 for t in tests {
713 let checksum_be = checksum.to_be_bytes();
714 let mut expected = ArrayVec::from([
715 TYPE_PARAMETER_PROBLEM, t.0, checksum_be[0], checksum_be[1],
716 t.1, 0, 0, 0,
717 0, 0, 0, 0,
718 0, 0, 0, 0,
719 0, 0, 0, 0,
720 ]);
721 unsafe {
722 expected.set_len(8);
723 }
724 let actual = Icmpv4Header{
725 icmp_type: ParameterProblem(t.2.clone()),
726 checksum,
727 }.to_bytes();
728 assert_eq!(expected, actual);
729 }
730 }
731 }
732 }
733
734 #[test]
735 fn clone_eq() {
736 use Icmpv4Type::*;
737 let header = Icmpv4Header {
738 icmp_type: ParameterProblem(ParameterProblemHeader::BadLength),
739 checksum: 0,
740 };
741 assert_eq!(header.clone(), header);
742 }
743
744 #[test]
745 fn debug() {
746 use Icmpv4Type::*;
747 let header = Icmpv4Header {
748 icmp_type: ParameterProblem(ParameterProblemHeader::BadLength),
749 checksum: 0,
750 };
751 assert_eq!(
752 format!("{:?}", header),
753 format!(
754 "Icmpv4Header {{ icmp_type: {:?}, checksum: {:?} }}",
755 header.icmp_type, header.checksum
756 )
757 );
758 }
759}