1use core::mem;
2use core::net;
3
4use num_traits::FromPrimitive as _;
5
6use crate::getter_be;
7use crate::setter_be;
8
9#[derive(Debug, Copy, Clone)]
16pub enum Icmp {
17 V4(Icmpv4Hdr),
18 V6(Icmpv6Hdr),
19}
20
21#[derive(Debug)]
27pub enum IcmpError {
28 InvalidIcmpType(u8),
29}
30
31#[repr(C)]
50#[derive(Debug, Copy, Clone)]
51#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
52#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
53pub struct Icmpv4Hdr {
54 pub type_: u8,
55 pub code: u8,
56 pub check: [u8; 2],
57 pub data: [u8; 4],
58}
59
60#[derive(Clone, Copy, num_derive::FromPrimitive, num_derive::ToPrimitive)]
61#[repr(u8)]
62pub enum Icmpv4Type {
63 EchoReply = 0,
64 DestinationUnreachable = 3,
65 Redirect = 5,
66 Echo = 8,
67 ParameterProblem = 12,
68 Timestamp = 13,
69 TimestampReply = 14,
70 InformationRequest = 15,
71 InformationReply = 16,
72 AddressMaskRequest = 17,
73 AddressMaskReply = 18,
74 Traceroute = 30,
75 DomainNameRequest = 37,
76 DomainNameReply = 38,
77 Photuris = 40,
78}
79
80#[derive(Debug, Copy, Clone)]
82pub enum Icmpv4HdrData<'a> {
83 EchoReply(&'a IcmpIdSequence),
84 DestinationUnreachable(&'a IcmpDstUnreachable),
85 Redirect(&'a Icmpv4Redirect),
86 Echo(&'a IcmpIdSequence),
87 ParameterProblem(&'a Icmpv4ParamProblem),
88 Timestamp(&'a IcmpIdSequence),
89 TimestampReply(&'a IcmpIdSequence),
90 InformationRequest(&'a IcmpIdSequence),
91 InformationReply(&'a IcmpIdSequence),
92 AddressMaskRequest(&'a IcmpIdSequence),
93 AddressMaskReply(&'a IcmpIdSequence),
94 Traceroute(&'a IcmpTraceroute),
95 DomainNameRequest(&'a IcmpIdSequence),
96 DomainNameReply(&'a IcmpIdSequence),
97 Photuris(&'a IcmpHdrPhoturis),
98}
99
100#[derive(Debug)]
102pub enum Icmpv4HdrDataMut<'a> {
103 EchoReply(&'a mut IcmpIdSequence),
104 DestinationUnreachable(&'a mut IcmpDstUnreachable),
105 Redirect(&'a mut Icmpv4Redirect),
106 Echo(&'a mut IcmpIdSequence),
107 ParameterProblem(&'a mut Icmpv4ParamProblem),
108 Timestamp(&'a mut IcmpIdSequence),
109 TimestampReply(&'a mut IcmpIdSequence),
110 InformationRequest(&'a mut IcmpIdSequence),
111 InformationReply(&'a mut IcmpIdSequence),
112 AddressMaskRequest(&'a mut IcmpIdSequence),
113 AddressMaskReply(&'a mut IcmpIdSequence),
114 Traceroute(&'a mut IcmpTraceroute),
115 DomainNameRequest(&'a mut IcmpIdSequence),
116 DomainNameReply(&'a mut IcmpIdSequence),
117 Photuris(&'a mut IcmpHdrPhoturis),
118}
119
120impl Icmpv4Hdr {
121 pub const LEN: usize = mem::size_of::<Icmpv4Hdr>();
122
123 #[inline]
124 pub fn icmp_type(&self) -> Result<Icmpv4Type, IcmpError> {
125 Icmpv4Type::from_u8(self.type_).ok_or(IcmpError::InvalidIcmpType(self.type_))
126 }
127
128 pub fn checksum(&self) -> u16 {
131 unsafe { getter_be!(self, check, u16) }
133 }
134
135 pub fn set_checksum(&mut self, checksum: u16) {
139 unsafe { setter_be!(self, check, checksum) }
141 }
142
143 #[inline]
145 pub fn data(&self) -> Result<Icmpv4HdrData<'_>, IcmpError> {
146 match self.icmp_type()? {
147 Icmpv4Type::EchoReply => Ok(Icmpv4HdrData::EchoReply(unsafe {
148 self.id_sequence_unchecked()
149 })),
150 Icmpv4Type::DestinationUnreachable => {
151 Ok(Icmpv4HdrData::DestinationUnreachable(unsafe {
152 self.destination_unreachable_unchecked()
153 }))
154 }
155 Icmpv4Type::Redirect => Ok(Icmpv4HdrData::Redirect(unsafe {
156 self.redirect_unchecked()
157 })),
158 Icmpv4Type::Echo => Ok(Icmpv4HdrData::Echo(unsafe { self.id_sequence_unchecked() })),
159 Icmpv4Type::ParameterProblem => Ok(Icmpv4HdrData::ParameterProblem(unsafe {
160 self.parameter_problem_unchecked()
161 })),
162 Icmpv4Type::Timestamp => Ok(Icmpv4HdrData::Timestamp(unsafe {
163 self.id_sequence_unchecked()
164 })),
165 Icmpv4Type::TimestampReply => Ok(Icmpv4HdrData::TimestampReply(unsafe {
166 self.id_sequence_unchecked()
167 })),
168 Icmpv4Type::InformationRequest => Ok(Icmpv4HdrData::InformationRequest(unsafe {
169 self.id_sequence_unchecked()
170 })),
171 Icmpv4Type::InformationReply => Ok(Icmpv4HdrData::InformationReply(unsafe {
172 self.id_sequence_unchecked()
173 })),
174 Icmpv4Type::AddressMaskRequest => Ok(Icmpv4HdrData::AddressMaskRequest(unsafe {
175 self.id_sequence_unchecked()
176 })),
177 Icmpv4Type::AddressMaskReply => Ok(Icmpv4HdrData::AddressMaskReply(unsafe {
178 self.id_sequence_unchecked()
179 })),
180 Icmpv4Type::Traceroute => Ok(Icmpv4HdrData::Traceroute(unsafe {
181 self.traceroute_unchecked()
182 })),
183 Icmpv4Type::DomainNameRequest => Ok(Icmpv4HdrData::DomainNameRequest(unsafe {
184 self.id_sequence_unchecked()
185 })),
186 Icmpv4Type::DomainNameReply => Ok(Icmpv4HdrData::DomainNameReply(unsafe {
187 self.id_sequence_unchecked()
188 })),
189 Icmpv4Type::Photuris => Ok(Icmpv4HdrData::Photuris(unsafe {
190 self.photuris_unchecked()
191 })),
192 }
193 }
194
195 #[inline]
197 pub fn data_mut(&mut self) -> Result<Icmpv4HdrDataMut<'_>, IcmpError> {
198 match self.icmp_type()? {
199 Icmpv4Type::EchoReply => Ok(Icmpv4HdrDataMut::EchoReply(unsafe {
200 self.id_sequence_mut_unchecked()
201 })),
202 Icmpv4Type::DestinationUnreachable => {
203 Ok(Icmpv4HdrDataMut::DestinationUnreachable(unsafe {
204 self.destination_unreachable_mut_unchecked()
205 }))
206 }
207 Icmpv4Type::Redirect => Ok(Icmpv4HdrDataMut::Redirect(unsafe {
208 self.redirect_mut_unchecked()
209 })),
210 Icmpv4Type::Echo => Ok(Icmpv4HdrDataMut::Echo(unsafe {
211 self.id_sequence_mut_unchecked()
212 })),
213 Icmpv4Type::ParameterProblem => Ok(Icmpv4HdrDataMut::ParameterProblem(unsafe {
214 self.parameter_problem_mut_unchecked()
215 })),
216 Icmpv4Type::Timestamp => Ok(Icmpv4HdrDataMut::Timestamp(unsafe {
217 self.id_sequence_mut_unchecked()
218 })),
219 Icmpv4Type::TimestampReply => Ok(Icmpv4HdrDataMut::TimestampReply(unsafe {
220 self.id_sequence_mut_unchecked()
221 })),
222 Icmpv4Type::InformationRequest => Ok(Icmpv4HdrDataMut::InformationRequest(unsafe {
223 self.id_sequence_mut_unchecked()
224 })),
225 Icmpv4Type::InformationReply => Ok(Icmpv4HdrDataMut::InformationReply(unsafe {
226 self.id_sequence_mut_unchecked()
227 })),
228 Icmpv4Type::AddressMaskRequest => Ok(Icmpv4HdrDataMut::AddressMaskRequest(unsafe {
229 self.id_sequence_mut_unchecked()
230 })),
231 Icmpv4Type::AddressMaskReply => Ok(Icmpv4HdrDataMut::AddressMaskReply(unsafe {
232 self.id_sequence_mut_unchecked()
233 })),
234 Icmpv4Type::Traceroute => Ok(Icmpv4HdrDataMut::Traceroute(unsafe {
235 self.traceroute_mut_unchecked()
236 })),
237 Icmpv4Type::DomainNameRequest => Ok(Icmpv4HdrDataMut::DomainNameRequest(unsafe {
238 self.id_sequence_mut_unchecked()
239 })),
240 Icmpv4Type::DomainNameReply => Ok(Icmpv4HdrDataMut::DomainNameReply(unsafe {
241 self.id_sequence_mut_unchecked()
242 })),
243 Icmpv4Type::Photuris => Ok(Icmpv4HdrDataMut::Photuris(unsafe {
244 self.photuris_mut_unchecked()
245 })),
246 }
247 }
248}
249
250impl Icmpv4Hdr {
252 #[inline]
260 pub unsafe fn id_sequence_unchecked(&self) -> &IcmpIdSequence {
261 mem::transmute(&self.data)
262 }
263
264 #[inline]
272 pub unsafe fn id_sequence_mut_unchecked(&mut self) -> &mut IcmpIdSequence {
273 mem::transmute(&mut self.data)
274 }
275
276 #[inline]
281 pub unsafe fn redirect_unchecked(&self) -> &Icmpv4Redirect {
282 mem::transmute(&self.data)
283 }
284
285 #[inline]
290 pub unsafe fn redirect_mut_unchecked(&mut self) -> &mut Icmpv4Redirect {
291 mem::transmute(&mut self.data)
292 }
293
294 #[inline]
301 pub unsafe fn destination_unreachable_unchecked(&self) -> &IcmpDstUnreachable {
302 mem::transmute(&self.data)
303 }
304
305 #[inline]
312 pub unsafe fn destination_unreachable_mut_unchecked(&mut self) -> &mut IcmpDstUnreachable {
313 mem::transmute(&mut self.data)
314 }
315
316 #[inline]
322 pub unsafe fn parameter_problem_unchecked(&self) -> &Icmpv4ParamProblem {
323 mem::transmute(&self.data)
324 }
325
326 #[inline]
332 pub unsafe fn parameter_problem_mut_unchecked(&mut self) -> &mut Icmpv4ParamProblem {
333 mem::transmute(&mut self.data)
334 }
335
336 #[inline]
343 pub unsafe fn traceroute_unchecked(&self) -> &IcmpTraceroute {
344 mem::transmute(&self.data)
345 }
346
347 #[inline]
354 pub unsafe fn traceroute_mut_unchecked(&mut self) -> &mut IcmpTraceroute {
355 mem::transmute(&mut self.data)
356 }
357
358 #[inline]
364 pub unsafe fn photuris_unchecked(&self) -> &IcmpHdrPhoturis {
365 mem::transmute(&self.data)
366 }
367
368 #[inline]
374 pub unsafe fn photuris_mut_unchecked(&mut self) -> &mut IcmpHdrPhoturis {
375 mem::transmute(&mut self.data)
376 }
377}
378
379#[repr(C)]
392#[derive(Debug, Copy, Clone)]
393#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
394#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
395pub struct IcmpIdSequence {
396 pub id: [u8; 2],
397 pub sequence: [u8; 2],
398}
399
400impl IcmpIdSequence {
401 #[inline]
403 pub fn id(&self) -> u16 {
404 unsafe { getter_be!(self, id, u16) }
405 }
406
407 #[inline]
409 pub fn set_id(&mut self, id: u16) {
410 unsafe { setter_be!(self, id, id) }
411 }
412
413 #[inline]
415 pub fn sequence(&self) -> u16 {
416 unsafe { getter_be!(self, sequence, u16) }
417 }
418
419 #[inline]
427 pub fn set_sequence(&mut self, sequence: u16) {
428 unsafe { setter_be!(self, sequence, sequence) }
429 }
430}
431
432#[repr(C)]
435#[derive(Debug, Copy, Clone)]
436#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
437#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
438pub struct Icmpv4Redirect {
439 gateway: [u8; 4],
440}
441
442impl Icmpv4Redirect {
443 #[inline]
444 pub fn gateway_address(&self) -> net::Ipv4Addr {
445 net::Ipv4Addr::from(self.gateway)
446 }
447
448 #[inline]
449 pub fn set_gateway_address(&mut self, addr: net::Ipv4Addr) {
450 self.gateway = addr.octets();
451 }
452}
453
454#[repr(C)]
458#[derive(Debug, Copy, Clone)]
459#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
460#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
461pub struct IcmpDstUnreachable {
462 pub _unused: [u8; 2],
463 pub mtu: [u8; 2],
464}
465
466impl IcmpDstUnreachable {
467 #[inline]
474 pub fn mtu(&self) -> u16 {
475 unsafe { getter_be!(self, mtu, u16) }
476 }
477
478 #[inline]
479 pub fn set_mtu(&mut self, mtu: u16) {
480 unsafe { setter_be!(self, mtu, mtu) }
481 }
482}
483
484#[repr(C)]
488#[derive(Debug, Copy, Clone)]
489#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
490#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
491pub struct Icmpv4ParamProblem {
492 pub pointer: u8,
493 pub _unused: [u8; 3], }
495
496impl Icmpv4ParamProblem {
497 #[inline]
498 pub fn pointer(&self) -> u8 {
499 self.pointer
500 }
501
502 #[inline]
503 pub fn set_pointer(&mut self, pointer: u8) {
504 self.pointer = pointer;
505 }
506}
507
508#[repr(C)]
513#[derive(Debug, Copy, Clone)]
514#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
515#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
516pub struct IcmpHdrPhoturis {
517 pub reserved_spi: [u8; 2],
518 pub pointer: [u8; 2],
519}
520
521impl IcmpHdrPhoturis {
522 #[inline]
523 pub fn reserved_spi(&self) -> u16 {
524 unsafe { getter_be!(self, reserved_spi, u16) }
525 }
526
527 #[inline]
528 pub fn set_reserved_spi(&mut self, spi: u16) {
529 unsafe { setter_be!(self, reserved_spi, spi) }
530 }
531
532 #[inline]
533 pub fn pointer(&self) -> u16 {
534 unsafe { getter_be!(self, pointer, u16) }
535 }
536
537 #[inline]
538 pub fn set_pointer(&mut self, pointer: u16) {
539 unsafe { setter_be!(self, pointer, pointer) }
540 }
541}
542
543#[repr(C)]
547#[derive(Debug, Copy, Clone)]
548#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
549#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
550pub struct IcmpTraceroute {
551 pub id: [u8; 2],
552 pub _unused: [u8; 2],
553}
554
555impl IcmpTraceroute {
556 #[inline]
563 pub fn id(&self) -> u16 {
564 unsafe { getter_be!(self, id, u16) }
565 }
566
567 #[inline]
573 pub fn set_id(&mut self, id: u16) {
574 unsafe { setter_be!(self, id, id) }
575 }
576}
577
578#[repr(C)]
618#[derive(Debug, Copy, Clone)]
619#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
620#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
621pub struct IcmpTimestampMsgPart {
622 pub originate_timestamp: [u8; 4],
623 pub receive_timestamp: [u8; 4],
624 pub transmit_timestamp: [u8; 4],
625}
626
627impl IcmpTimestampMsgPart {
628 pub const LEN: usize = mem::size_of::<IcmpTimestampMsgPart>();
629
630 pub fn originate_timestamp(&self) -> u32 {
632 unsafe { getter_be!(self, originate_timestamp, u32) }
634 }
635
636 pub fn set_originate_timestamp(&mut self, timestamp: u32) {
639 unsafe { setter_be!(self, originate_timestamp, timestamp) }
641 }
642
643 pub fn receive_timestamp(&self) -> u32 {
645 unsafe { getter_be!(self, receive_timestamp, u32) }
647 }
648
649 pub fn set_receive_timestamp(&mut self, timestamp: u32) {
652 unsafe { setter_be!(self, receive_timestamp, timestamp) }
654 }
655
656 pub fn transmit_timestamp(&self) -> u32 {
658 unsafe { getter_be!(self, transmit_timestamp, u32) }
660 }
661
662 pub fn set_transmit_timestamp(&mut self, timestamp: u32) {
665 unsafe { setter_be!(self, transmit_timestamp, timestamp) }
667 }
668}
669
670#[repr(C)]
710#[derive(Debug, Copy, Clone)]
711#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
712#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
713pub struct IcmpTracerouteMsgPart {
714 pub hops_out: [u8; 2],
715 pub hops_in: [u8; 2],
716 pub bandwidth_out: [u8; 4],
717 pub mtu_out: [u8; 4],
718}
719
720impl IcmpTracerouteMsgPart {
721 pub const LEN: usize = mem::size_of::<IcmpTracerouteMsgPart>();
722
723 pub fn hops_out(&self) -> u16 {
726 unsafe { getter_be!(self, hops_out, u16) }
728 }
729
730 pub fn set_hops_out(&mut self, hops: u16) {
733 unsafe { setter_be!(self, hops_out, hops) }
735 }
736
737 pub fn hops_in(&self) -> u16 {
740 unsafe { getter_be!(self, hops_in, u16) }
742 }
743
744 pub fn set_hops_in(&mut self, hops: u16) {
747 unsafe { setter_be!(self, hops_in, hops) }
749 }
750
751 pub fn bandwidth_out(&self) -> u32 {
754 unsafe { getter_be!(self, bandwidth_out, u32) }
756 }
757
758 pub fn set_bandwidth_out(&mut self, bandwidth: u32) {
761 unsafe { setter_be!(self, bandwidth_out, bandwidth) }
763 }
764
765 pub fn mtu_out(&self) -> u32 {
768 unsafe { getter_be!(self, mtu_out, u32) }
770 }
771
772 pub fn set_mtu_out(&mut self, mtu: u32) {
775 unsafe { setter_be!(self, mtu_out, mtu) }
777 }
778}
779
780#[repr(C)]
800#[derive(Debug, Copy, Clone)]
801#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
802#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
803pub struct Icmpv6Hdr {
804 pub type_: u8,
805 pub code: u8,
806 pub check: [u8; 2],
807 pub data: [u8; 4],
808}
809
810#[derive(Clone, Copy, num_derive::FromPrimitive, num_derive::ToPrimitive)]
811#[repr(u8)]
812pub enum Icmpv6Type {
813 PacketTooBig = 2,
814 ParameterProblem = 4,
815 EchoRequest = 128,
816 EchoReply = 129,
817 RedirectMessage = 137,
818}
819
820#[derive(Debug)]
822pub enum Icmpv6HdrData<'a> {
823 PacketTooBig(&'a IcmpPacketTooBig),
824 ParameterProblem(&'a Icmpv6ParamProblem),
825 EchoRequest(&'a IcmpIdSequence),
826 EchoReply(&'a IcmpIdSequence),
827 RedirectMessage(&'a Icmpv6Redirect),
828}
829
830#[derive(Debug)]
832pub enum Icmpv6HdrDataMut<'a> {
833 PacketTooBig(&'a mut IcmpPacketTooBig),
834 ParameterProblem(&'a mut Icmpv6ParamProblem),
835 EchoRequest(&'a mut IcmpIdSequence),
836 EchoReply(&'a mut IcmpIdSequence),
837 RedirectMessage(&'a mut Icmpv6Redirect),
838}
839
840impl Icmpv6Hdr {
841 pub const LEN: usize = mem::size_of::<Icmpv6Hdr>();
842
843 #[inline]
844 pub fn icmp_type(&self) -> Result<Icmpv6Type, IcmpError> {
845 Icmpv6Type::from_u8(self.type_).ok_or(IcmpError::InvalidIcmpType(self.type_))
846 }
847
848 pub fn checksum(&self) -> u16 {
851 unsafe { getter_be!(self, check, u16) }
853 }
854
855 pub fn set_checksum(&mut self, checksum: u16) {
859 unsafe { setter_be!(self, check, checksum) }
861 }
862
863 #[inline]
865 pub fn data(&self) -> Result<Icmpv6HdrData<'_>, IcmpError> {
866 match self.icmp_type()? {
867 Icmpv6Type::PacketTooBig => Ok(Icmpv6HdrData::PacketTooBig(unsafe {
868 self.packet_too_big_unchecked()
869 })),
870 Icmpv6Type::ParameterProblem => Ok(Icmpv6HdrData::ParameterProblem(unsafe {
871 self.parameter_problem_unchecked()
872 })),
873 Icmpv6Type::EchoRequest => Ok(Icmpv6HdrData::EchoRequest(unsafe {
874 self.id_sequence_unchecked()
875 })),
876 Icmpv6Type::EchoReply => Ok(Icmpv6HdrData::EchoReply(unsafe {
877 self.id_sequence_unchecked()
878 })),
879 Icmpv6Type::RedirectMessage => Ok(Icmpv6HdrData::RedirectMessage(unsafe {
880 self.redirect_unchecked()
881 })),
882 }
883 }
884
885 #[inline]
887 pub fn data_mut(&mut self) -> Result<Icmpv6HdrDataMut<'_>, IcmpError> {
888 match self.icmp_type()? {
889 Icmpv6Type::PacketTooBig => Ok(Icmpv6HdrDataMut::PacketTooBig(unsafe {
890 self.packet_too_big_mut_unchecked()
891 })),
892 Icmpv6Type::ParameterProblem => Ok(Icmpv6HdrDataMut::ParameterProblem(unsafe {
893 self.parameter_problem_mut_unchecked()
894 })),
895 Icmpv6Type::EchoRequest => Ok(Icmpv6HdrDataMut::EchoRequest(unsafe {
896 self.id_sequence_mut_unchecked()
897 })),
898 Icmpv6Type::EchoReply => Ok(Icmpv6HdrDataMut::EchoReply(unsafe {
899 self.id_sequence_mut_unchecked()
900 })),
901 Icmpv6Type::RedirectMessage => Ok(Icmpv6HdrDataMut::RedirectMessage(unsafe {
902 self.redirect_mut_unchecked()
903 })),
904 }
905 }
906}
907
908impl Icmpv6Hdr {
910 #[inline]
917 pub unsafe fn id_sequence_unchecked(&self) -> &IcmpIdSequence {
918 mem::transmute(&self.data)
919 }
920
921 #[inline]
928 pub unsafe fn id_sequence_mut_unchecked(&mut self) -> &mut IcmpIdSequence {
929 mem::transmute(&mut self.data)
930 }
931
932 #[inline]
938 pub unsafe fn packet_too_big_unchecked(&self) -> &IcmpPacketTooBig {
939 mem::transmute(&self.data)
940 }
941
942 #[inline]
948 pub unsafe fn packet_too_big_mut_unchecked(&mut self) -> &mut IcmpPacketTooBig {
949 mem::transmute(&mut self.data)
950 }
951
952 #[inline]
958 pub unsafe fn parameter_problem_unchecked(&self) -> &Icmpv6ParamProblem {
959 mem::transmute(&self.data)
960 }
961
962 #[inline]
968 pub unsafe fn parameter_problem_mut_unchecked(&mut self) -> &mut Icmpv6ParamProblem {
969 mem::transmute(&mut self.data)
970 }
971
972 #[inline]
979 pub unsafe fn redirect_unchecked(&self) -> &Icmpv6Redirect {
980 mem::transmute(&self.data)
981 }
982
983 #[inline]
990 pub unsafe fn redirect_mut_unchecked(&mut self) -> &mut Icmpv6Redirect {
991 mem::transmute(&mut self.data)
992 }
993}
994
995#[repr(C)]
997#[derive(Debug, Copy, Clone)]
998#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
999#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
1000pub struct IcmpPacketTooBig {
1001 mtu: [u8; 4],
1002}
1003
1004impl IcmpPacketTooBig {
1005 #[inline]
1006 pub fn mtu(&self) -> u32 {
1007 unsafe { getter_be!(self, mtu, u32) }
1009 }
1010
1011 #[inline]
1012 pub fn set_mtu(&mut self, mtu: u32) {
1013 unsafe { setter_be!(self, mtu, mtu) }
1015 }
1016}
1017
1018#[repr(C)]
1022#[derive(Debug, Copy, Clone)]
1023#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
1024#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
1025pub struct Icmpv6ParamProblem {
1026 pub pointer: [u8; 4],
1027}
1028
1029impl Icmpv6ParamProblem {
1030 #[inline]
1031 pub fn pointer(&self) -> u32 {
1032 unsafe { getter_be!(self, pointer, u32) }
1034 }
1035
1036 #[inline]
1037 pub fn set_pointer(&mut self, pointer: u32) {
1038 unsafe { setter_be!(self, pointer, pointer) }
1040 }
1041}
1042
1043#[repr(C)]
1047#[derive(Debug, Copy, Clone)]
1048#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
1049#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
1050pub struct Icmpv6Redirect {
1051 pub reserved: [u8; 4],
1052}
1053
1054#[cfg(test)]
1055mod tests {
1056 use super::*;
1057 use core::net::Ipv4Addr;
1058
1059 macro_rules! expect_data {
1060 ($hdr:expr, $enum:ident, $variant:ident) => {{
1061 match $hdr.data().expect("invalid ICMP message") {
1062 $enum::$variant(value) => value,
1063 _ => panic!("expected {} message", stringify!($variant)),
1064 }
1065 }};
1066 }
1067
1068 macro_rules! expect_data_mut {
1069 ($hdr:expr, $enum:ident, $variant:ident) => {{
1070 match $hdr.data_mut().expect("invalid ICMP message") {
1071 $enum::$variant(value) => value,
1072 _ => panic!("expected {} message", stringify!($variant)),
1073 }
1074 }};
1075 }
1076
1077 #[test]
1078 fn test_icmp_hdr_size() {
1079 assert_eq!(Icmpv4Hdr::LEN, 8);
1081 assert_eq!(Icmpv4Hdr::LEN, mem::size_of::<Icmpv4Hdr>());
1082 }
1083
1084 fn create_test_icmp_hdr() -> Icmpv4Hdr {
1086 Icmpv4Hdr {
1087 type_: 0,
1088 code: 0,
1089 check: [0, 0],
1090 data: [0, 0, 0, 0],
1091 }
1092 }
1093
1094 #[test]
1095 fn test_checksum() {
1096 let mut hdr = create_test_icmp_hdr();
1097 let test_checksum: u16 = 0x1234;
1098
1099 let bytes = test_checksum.to_be_bytes();
1101 hdr.check = bytes;
1102
1103 assert_eq!(hdr.checksum(), test_checksum);
1105
1106 hdr.set_checksum(0xABCD);
1108 assert_eq!(hdr.check, [0xAB, 0xCD]);
1109 assert_eq!(hdr.checksum(), 0xABCD);
1110 }
1111
1112 #[test]
1113 fn test_echo_fields() {
1114 let mut hdr = create_test_icmp_hdr();
1115 hdr.type_ = 0;
1117
1118 let test_id: u16 = 0x4321;
1120 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, EchoReply).set_id(test_id);
1121 assert_eq!(expect_data!(&hdr, Icmpv4HdrData, EchoReply).id(), test_id);
1122
1123 assert_eq!(hdr.data[..2], test_id.to_be_bytes());
1125
1126 let test_seq: u16 = 0x8765;
1128 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, EchoReply).set_sequence(test_seq);
1129 assert_eq!(
1130 expect_data!(&hdr, Icmpv4HdrData, EchoReply).sequence(),
1131 test_seq
1132 );
1133
1134 assert_eq!(hdr.data[2..], test_seq.to_be_bytes());
1136 }
1137
1138 #[test]
1139 fn test_gateway_address() {
1140 let mut hdr = create_test_icmp_hdr();
1141 hdr.type_ = 5;
1143 let test_addr = Ipv4Addr::new(192, 168, 1, 1);
1144
1145 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, Redirect).set_gateway_address(test_addr);
1146 assert_eq!(
1147 expect_data!(&hdr, Icmpv4HdrData, Redirect).gateway_address(),
1148 test_addr
1149 );
1150
1151 assert_eq!(hdr.data, [192, 168, 1, 1]);
1153 }
1154
1155 #[test]
1156 fn test_message_enum_echo() {
1157 let mut hdr = create_test_icmp_hdr();
1158 hdr.type_ = 8;
1159
1160 match hdr.data_mut().expect("echo view") {
1161 Icmpv4HdrDataMut::Echo(echo) => {
1162 echo.set_id(0xABCD);
1163 echo.set_sequence(0x1234);
1164 }
1165 _ => panic!("unexpected variant"),
1166 }
1167
1168 match hdr.data().expect("echo view") {
1169 Icmpv4HdrData::Echo(echo) => {
1170 assert_eq!(echo.id(), 0xABCD);
1171 assert_eq!(echo.sequence(), 0x1234);
1172 }
1173 _ => panic!("unexpected variant"),
1174 }
1175 }
1176
1177 #[test]
1178 fn test_message_enum_invalid_type() {
1179 let hdr = Icmpv4Hdr {
1180 type_: 9,
1181 code: 0,
1182 check: [0, 0],
1183 data: [0, 0, 0, 0],
1184 };
1185
1186 assert!(hdr.data().is_err());
1187 }
1188
1189 #[test]
1190 fn test_next_hop_mtu() {
1191 let mut hdr = create_test_icmp_hdr();
1192 hdr.type_ = 3;
1194 let test_mtu: u16 = 1500;
1195
1196 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, DestinationUnreachable).set_mtu(test_mtu);
1197 assert_eq!(
1198 expect_data!(&hdr, Icmpv4HdrData, DestinationUnreachable).mtu(),
1199 test_mtu
1200 );
1201
1202 assert_eq!(hdr.data[2..], test_mtu.to_be_bytes());
1204 }
1205
1206 #[test]
1207 fn test_parameter_pointer() {
1208 let mut hdr = create_test_icmp_hdr();
1209 hdr.type_ = 12;
1211 let test_pointer: u8 = 42;
1212
1213 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, ParameterProblem).set_pointer(test_pointer);
1214 assert_eq!(
1215 expect_data!(&hdr, Icmpv4HdrData, ParameterProblem).pointer(),
1216 test_pointer
1217 );
1218
1219 assert_eq!(hdr.data[0], test_pointer);
1221 }
1222
1223 #[test]
1224 fn test_traceroute_id() {
1225 let mut hdr = create_test_icmp_hdr();
1226 hdr.type_ = 30;
1228 let test_id: u16 = 0x9876;
1229
1230 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, Traceroute).set_id(test_id);
1231 assert_eq!(expect_data!(&hdr, Icmpv4HdrData, Traceroute).id(), test_id);
1232
1233 assert_eq!(hdr.data[..2], test_id.to_be_bytes());
1235 }
1236
1237 #[test]
1238 fn test_photuris_spi() {
1239 let mut hdr = create_test_icmp_hdr();
1240 hdr.type_ = 40;
1242 let test_spi: u16 = 0xFEDC;
1243
1244 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, Photuris).set_reserved_spi(test_spi);
1245 assert_eq!(
1246 expect_data!(&hdr, Icmpv4HdrData, Photuris).reserved_spi(),
1247 test_spi
1248 );
1249
1250 assert_eq!(hdr.data[..2], test_spi.to_be_bytes());
1252 }
1253
1254 #[test]
1255 fn test_photuris_pointer() {
1256 let mut hdr = create_test_icmp_hdr();
1257 hdr.type_ = 40;
1259 let test_pointer: u16 = 0x1A2B;
1260
1261 expect_data_mut!(&mut hdr, Icmpv4HdrDataMut, Photuris).set_pointer(test_pointer);
1262 assert_eq!(
1263 expect_data!(&hdr, Icmpv4HdrData, Photuris).pointer(),
1264 test_pointer
1265 );
1266
1267 assert_eq!(hdr.data[2..], test_pointer.to_be_bytes());
1269 }
1270
1271 #[test]
1272 fn test_type_and_code_fields() {
1273 let mut hdr = create_test_icmp_hdr();
1274
1275 hdr.type_ = 8;
1278 hdr.code = 0;
1279 assert_eq!(hdr.type_, 8);
1280 assert_eq!(hdr.code, 0);
1281
1282 hdr.type_ = 3;
1284 hdr.code = 1;
1285 assert_eq!(hdr.type_, 3);
1286 assert_eq!(hdr.code, 1);
1287 }
1288
1289 #[test]
1290 fn test_icmp_hdr_bitwise_operations() {
1291 let mut hdr = create_test_icmp_hdr();
1293
1294 hdr.set_checksum(0x1234);
1296
1297 let modified_checksum = hdr.checksum() ^ 0xFFFF; hdr.set_checksum(modified_checksum);
1300
1301 assert_eq!(hdr.checksum(), 0xEDCB); }
1303
1304 #[test]
1305 fn test_icmp_common_type_constants() {
1306 let mut hdr = create_test_icmp_hdr();
1308
1309 hdr.type_ = 8;
1311 assert_eq!(hdr.type_, 8);
1312
1313 hdr.type_ = 0;
1315 assert_eq!(hdr.type_, 0);
1316
1317 hdr.type_ = 3;
1319 assert_eq!(hdr.type_, 3);
1320
1321 hdr.type_ = 5;
1323 assert_eq!(hdr.type_, 5);
1324 }
1325
1326 #[test]
1327 fn test_icmp_timestamp_msg_part_size() {
1328 assert_eq!(IcmpTimestampMsgPart::LEN, 12);
1330 assert_eq!(
1331 IcmpTimestampMsgPart::LEN,
1332 mem::size_of::<IcmpTimestampMsgPart>()
1333 );
1334 }
1335
1336 #[test]
1337 fn test_timestamp_originate() {
1338 let mut timestamp_part = IcmpTimestampMsgPart {
1339 originate_timestamp: [0, 0, 0, 0],
1340 receive_timestamp: [0, 0, 0, 0],
1341 transmit_timestamp: [0, 0, 0, 0],
1342 };
1343
1344 let test_timestamp: u32 = 0x12345678;
1346 timestamp_part.set_originate_timestamp(test_timestamp);
1347 assert_eq!(timestamp_part.originate_timestamp(), test_timestamp);
1348
1349 assert_eq!(timestamp_part.originate_timestamp, [0x12, 0x34, 0x56, 0x78]);
1351
1352 timestamp_part.set_originate_timestamp(0);
1354 assert_eq!(timestamp_part.originate_timestamp(), 0);
1355 assert_eq!(timestamp_part.originate_timestamp, [0, 0, 0, 0]);
1356
1357 timestamp_part.set_originate_timestamp(u32::MAX);
1359 assert_eq!(timestamp_part.originate_timestamp(), u32::MAX);
1360 assert_eq!(timestamp_part.originate_timestamp, [0xFF, 0xFF, 0xFF, 0xFF]);
1361 }
1362
1363 #[test]
1364 fn test_timestamp_receive() {
1365 let mut timestamp_part = IcmpTimestampMsgPart {
1366 originate_timestamp: [0, 0, 0, 0],
1367 receive_timestamp: [0, 0, 0, 0],
1368 transmit_timestamp: [0, 0, 0, 0],
1369 };
1370
1371 let test_timestamp: u32 = 0x87654321;
1373 timestamp_part.set_receive_timestamp(test_timestamp);
1374 assert_eq!(timestamp_part.receive_timestamp(), test_timestamp);
1375
1376 assert_eq!(timestamp_part.receive_timestamp, [0x87, 0x65, 0x43, 0x21]);
1378
1379 timestamp_part.set_receive_timestamp(0);
1381 assert_eq!(timestamp_part.receive_timestamp(), 0);
1382 assert_eq!(timestamp_part.receive_timestamp, [0, 0, 0, 0]);
1383
1384 timestamp_part.set_receive_timestamp(u32::MAX);
1386 assert_eq!(timestamp_part.receive_timestamp(), u32::MAX);
1387 assert_eq!(timestamp_part.receive_timestamp, [0xFF, 0xFF, 0xFF, 0xFF]);
1388 }
1389
1390 #[test]
1391 fn test_timestamp_transmit() {
1392 let mut timestamp_part = IcmpTimestampMsgPart {
1393 originate_timestamp: [0, 0, 0, 0],
1394 receive_timestamp: [0, 0, 0, 0],
1395 transmit_timestamp: [0, 0, 0, 0],
1396 };
1397
1398 let test_timestamp: u32 = 0xABCDEF01;
1400 timestamp_part.set_transmit_timestamp(test_timestamp);
1401 assert_eq!(timestamp_part.transmit_timestamp(), test_timestamp);
1402
1403 assert_eq!(timestamp_part.transmit_timestamp, [0xAB, 0xCD, 0xEF, 0x01]);
1405
1406 timestamp_part.set_transmit_timestamp(0);
1408 assert_eq!(timestamp_part.transmit_timestamp(), 0);
1409 assert_eq!(timestamp_part.transmit_timestamp, [0, 0, 0, 0]);
1410
1411 timestamp_part.set_transmit_timestamp(u32::MAX);
1413 assert_eq!(timestamp_part.transmit_timestamp(), u32::MAX);
1414 assert_eq!(timestamp_part.transmit_timestamp, [0xFF, 0xFF, 0xFF, 0xFF]);
1415 }
1416
1417 #[test]
1418 fn test_timestamp_msg_part_construction() {
1419 let mut timestamp_part = IcmpTimestampMsgPart {
1421 originate_timestamp: [0, 0, 0, 0],
1422 receive_timestamp: [0, 0, 0, 0],
1423 transmit_timestamp: [0, 0, 0, 0],
1424 };
1425
1426 timestamp_part.set_originate_timestamp(0x11223344);
1428 timestamp_part.set_receive_timestamp(0x55667788);
1429 timestamp_part.set_transmit_timestamp(0x99AABBCC);
1430
1431 assert_eq!(timestamp_part.originate_timestamp(), 0x11223344);
1433 assert_eq!(timestamp_part.receive_timestamp(), 0x55667788);
1434 assert_eq!(timestamp_part.transmit_timestamp(), 0x99AABBCC);
1435
1436 assert_eq!(timestamp_part.originate_timestamp, [0x11, 0x22, 0x33, 0x44]);
1438 assert_eq!(timestamp_part.receive_timestamp, [0x55, 0x66, 0x77, 0x88]);
1439 assert_eq!(timestamp_part.transmit_timestamp, [0x99, 0xAA, 0xBB, 0xCC]);
1440 }
1441
1442 #[test]
1443 fn test_icmp_traceroute_msg_part_size() {
1444 assert_eq!(IcmpTracerouteMsgPart::LEN, 12);
1446 assert_eq!(
1447 IcmpTracerouteMsgPart::LEN,
1448 mem::size_of::<IcmpTracerouteMsgPart>()
1449 );
1450 }
1451
1452 #[test]
1453 fn test_traceroute_hops_out() {
1454 let mut traceroute_part = IcmpTracerouteMsgPart {
1455 hops_out: [0, 0],
1456 hops_in: [0, 0],
1457 bandwidth_out: [0, 0, 0, 0],
1458 mtu_out: [0, 0, 0, 0],
1459 };
1460
1461 let test_hops: u16 = 0x1234;
1463 traceroute_part.set_hops_out(test_hops);
1464 assert_eq!(traceroute_part.hops_out(), test_hops);
1465
1466 assert_eq!(traceroute_part.hops_out, [0x12, 0x34]);
1468
1469 traceroute_part.set_hops_out(0);
1471 assert_eq!(traceroute_part.hops_out(), 0);
1472 assert_eq!(traceroute_part.hops_out, [0, 0]);
1473
1474 traceroute_part.set_hops_out(u16::MAX);
1476 assert_eq!(traceroute_part.hops_out(), u16::MAX);
1477 assert_eq!(traceroute_part.hops_out, [0xFF, 0xFF]);
1478 }
1479
1480 #[test]
1481 fn test_traceroute_hops_in() {
1482 let mut traceroute_part = IcmpTracerouteMsgPart {
1483 hops_out: [0, 0],
1484 hops_in: [0, 0],
1485 bandwidth_out: [0, 0, 0, 0],
1486 mtu_out: [0, 0, 0, 0],
1487 };
1488
1489 let test_hops: u16 = 0x5678;
1491 traceroute_part.set_hops_in(test_hops);
1492 assert_eq!(traceroute_part.hops_in(), test_hops);
1493
1494 assert_eq!(traceroute_part.hops_in, [0x56, 0x78]);
1496
1497 traceroute_part.set_hops_in(0);
1499 assert_eq!(traceroute_part.hops_in(), 0);
1500 assert_eq!(traceroute_part.hops_in, [0, 0]);
1501
1502 traceroute_part.set_hops_in(u16::MAX);
1504 assert_eq!(traceroute_part.hops_in(), u16::MAX);
1505 assert_eq!(traceroute_part.hops_in, [0xFF, 0xFF]);
1506 }
1507
1508 #[test]
1509 fn test_traceroute_bandwidth_out() {
1510 let mut traceroute_part = IcmpTracerouteMsgPart {
1511 hops_out: [0, 0],
1512 hops_in: [0, 0],
1513 bandwidth_out: [0, 0, 0, 0],
1514 mtu_out: [0, 0, 0, 0],
1515 };
1516
1517 let test_bandwidth: u32 = 0x12345678;
1519 traceroute_part.set_bandwidth_out(test_bandwidth);
1520 assert_eq!(traceroute_part.bandwidth_out(), test_bandwidth);
1521
1522 assert_eq!(traceroute_part.bandwidth_out, [0x12, 0x34, 0x56, 0x78]);
1524
1525 traceroute_part.set_bandwidth_out(0);
1527 assert_eq!(traceroute_part.bandwidth_out(), 0);
1528 assert_eq!(traceroute_part.bandwidth_out, [0, 0, 0, 0]);
1529
1530 traceroute_part.set_bandwidth_out(u32::MAX);
1532 assert_eq!(traceroute_part.bandwidth_out(), u32::MAX);
1533 assert_eq!(traceroute_part.bandwidth_out, [0xFF, 0xFF, 0xFF, 0xFF]);
1534 }
1535
1536 #[test]
1537 fn test_traceroute_mtu_out() {
1538 let mut traceroute_part = IcmpTracerouteMsgPart {
1539 hops_out: [0, 0],
1540 hops_in: [0, 0],
1541 bandwidth_out: [0, 0, 0, 0],
1542 mtu_out: [0, 0, 0, 0],
1543 };
1544
1545 let test_mtu: u32 = 0x87654321;
1547 traceroute_part.set_mtu_out(test_mtu);
1548 assert_eq!(traceroute_part.mtu_out(), test_mtu);
1549
1550 assert_eq!(traceroute_part.mtu_out, [0x87, 0x65, 0x43, 0x21]);
1552
1553 traceroute_part.set_mtu_out(0);
1555 assert_eq!(traceroute_part.mtu_out(), 0);
1556 assert_eq!(traceroute_part.mtu_out, [0, 0, 0, 0]);
1557
1558 traceroute_part.set_mtu_out(u32::MAX);
1560 assert_eq!(traceroute_part.mtu_out(), u32::MAX);
1561 assert_eq!(traceroute_part.mtu_out, [0xFF, 0xFF, 0xFF, 0xFF]);
1562 }
1563
1564 #[test]
1565 fn test_traceroute_msg_part_construction() {
1566 let mut traceroute_part = IcmpTracerouteMsgPart {
1568 hops_out: [0, 0],
1569 hops_in: [0, 0],
1570 bandwidth_out: [0, 0, 0, 0],
1571 mtu_out: [0, 0, 0, 0],
1572 };
1573
1574 traceroute_part.set_hops_out(30);
1576 traceroute_part.set_hops_in(25);
1577 traceroute_part.set_bandwidth_out(100000000); traceroute_part.set_mtu_out(1500);
1579
1580 assert_eq!(traceroute_part.hops_out(), 30);
1582 assert_eq!(traceroute_part.hops_in(), 25);
1583 assert_eq!(traceroute_part.bandwidth_out(), 100000000);
1584 assert_eq!(traceroute_part.mtu_out(), 1500);
1585
1586 assert_eq!(traceroute_part.hops_out, [0, 30]);
1588 assert_eq!(traceroute_part.hops_in, [0, 25]);
1589 assert_eq!(traceroute_part.bandwidth_out, [0x05, 0xF5, 0xE1, 0x00]); assert_eq!(traceroute_part.mtu_out, [0, 0, 0x05, 0xDC]); }
1592
1593 #[test]
1594 fn test_icmpv6_hdr_size() {
1595 assert_eq!(Icmpv6Hdr::LEN, 8);
1597 assert_eq!(Icmpv6Hdr::LEN, mem::size_of::<Icmpv6Hdr>());
1598 }
1599
1600 fn create_test_icmpv6_hdr() -> Icmpv6Hdr {
1602 Icmpv6Hdr {
1603 type_: 0,
1604 code: 0,
1605 check: [0, 0],
1606 data: [0, 0, 0, 0],
1607 }
1608 }
1609
1610 #[test]
1611 fn test_icmpv6_checksum() {
1612 let mut hdr = create_test_icmpv6_hdr();
1613 let test_checksum: u16 = 0x1234;
1614
1615 let bytes = test_checksum.to_be_bytes();
1617 hdr.check = bytes;
1618
1619 assert_eq!(hdr.checksum(), test_checksum);
1621
1622 hdr.set_checksum(0xABCD);
1624 assert_eq!(hdr.check, [0xAB, 0xCD]);
1625 assert_eq!(hdr.checksum(), 0xABCD);
1626 }
1627
1628 #[test]
1629 fn test_icmpv6_echo_fields() {
1630 let mut hdr = create_test_icmpv6_hdr();
1631 hdr.type_ = 128;
1633
1634 let test_id: u16 = 0x4321;
1636 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, EchoRequest).set_id(test_id);
1637 assert_eq!(expect_data!(&hdr, Icmpv6HdrData, EchoRequest).id(), test_id);
1638
1639 let test_id_bytes = test_id.to_be_bytes();
1641 assert_eq!(&hdr.data[..2], &test_id_bytes);
1642
1643 let test_seq: u16 = 0x8765;
1645 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, EchoRequest).set_sequence(test_seq);
1646 assert_eq!(
1647 expect_data!(&hdr, Icmpv6HdrData, EchoRequest).sequence(),
1648 test_seq
1649 );
1650
1651 let test_seq_bytes = test_seq.to_be_bytes();
1653 assert_eq!(&hdr.data[2..], &test_seq_bytes);
1654 }
1655
1656 #[test]
1657 fn test_icmpv6_mtu() {
1658 let mut hdr = create_test_icmpv6_hdr();
1659 hdr.type_ = 2;
1661 let test_mtu: u32 = 0x12345678;
1662
1663 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, PacketTooBig).set_mtu(test_mtu);
1664 assert_eq!(
1665 expect_data!(&hdr, Icmpv6HdrData, PacketTooBig).mtu(),
1666 test_mtu
1667 );
1668
1669 assert_eq!(hdr.data, test_mtu.to_be_bytes());
1671
1672 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, PacketTooBig).set_mtu(0);
1674 assert_eq!(expect_data!(&hdr, Icmpv6HdrData, PacketTooBig).mtu(), 0);
1675 assert_eq!(hdr.data, [0, 0, 0, 0]);
1676
1677 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, PacketTooBig).set_mtu(u32::MAX);
1679 assert_eq!(
1680 expect_data!(&hdr, Icmpv6HdrData, PacketTooBig).mtu(),
1681 u32::MAX
1682 );
1683 assert_eq!(hdr.data, [0xFF, 0xFF, 0xFF, 0xFF]);
1684 }
1685
1686 #[test]
1687 fn test_icmpv6_pointer() {
1688 let mut hdr = create_test_icmpv6_hdr();
1689 hdr.type_ = 4;
1691 let test_pointer: u32 = 0x87654321;
1692
1693 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, ParameterProblem).set_pointer(test_pointer);
1694 assert_eq!(
1695 expect_data!(&hdr, Icmpv6HdrData, ParameterProblem).pointer(),
1696 test_pointer
1697 );
1698
1699 assert_eq!(hdr.data, test_pointer.to_be_bytes());
1701
1702 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, ParameterProblem).set_pointer(0);
1704 assert_eq!(
1705 expect_data!(&hdr, Icmpv6HdrData, ParameterProblem).pointer(),
1706 0
1707 );
1708 assert_eq!(hdr.data, [0, 0, 0, 0]);
1709
1710 expect_data_mut!(&mut hdr, Icmpv6HdrDataMut, ParameterProblem).set_pointer(u32::MAX);
1712 assert_eq!(
1713 expect_data!(&hdr, Icmpv6HdrData, ParameterProblem).pointer(),
1714 u32::MAX
1715 );
1716 assert_eq!(hdr.data, [0xFF, 0xFF, 0xFF, 0xFF]);
1717 }
1718
1719 #[test]
1720 fn test_icmpv6_type_and_code_fields() {
1721 let mut hdr = create_test_icmpv6_hdr();
1722
1723 hdr.type_ = 128;
1726 hdr.code = 0;
1727 assert_eq!(hdr.type_, 128);
1728 assert_eq!(hdr.code, 0);
1729
1730 hdr.type_ = 129;
1732 hdr.code = 0;
1733 assert_eq!(hdr.type_, 129);
1734 assert_eq!(hdr.code, 0);
1735
1736 hdr.type_ = 1;
1738 hdr.code = 0;
1739 assert_eq!(hdr.type_, 1);
1740 assert_eq!(hdr.code, 0);
1741
1742 hdr.type_ = 2;
1744 hdr.code = 0;
1745 assert_eq!(hdr.type_, 2);
1746 assert_eq!(hdr.code, 0);
1747
1748 hdr.type_ = 3;
1750 hdr.code = 0;
1751 assert_eq!(hdr.type_, 3);
1752 assert_eq!(hdr.code, 0);
1753
1754 hdr.type_ = 4;
1756 hdr.code = 0;
1757 assert_eq!(hdr.type_, 4);
1758 assert_eq!(hdr.code, 0);
1759 }
1760}
1761
1762#[cfg(all(test, feature = "wincode"))]
1763mod wincode_prop_tests {
1764 use super::*;
1765 use proptest::array::{uniform2, uniform4};
1766 use proptest::prelude::*;
1767 use proptest::test_runner::Config as ProptestConfig;
1768 use wincode::{SchemaRead, SchemaWrite, config::DefaultConfig};
1769
1770 const MAX_PACKET_SIZE: usize = Icmpv6Hdr::LEN;
1771
1772 trait FixedPacket {
1773 const SERIALIZED_LEN: usize;
1774 }
1775
1776 impl FixedPacket for Icmpv4Hdr {
1777 const SERIALIZED_LEN: usize = Icmpv4Hdr::LEN;
1778 }
1779
1780 impl FixedPacket for Icmpv6Hdr {
1781 const SERIALIZED_LEN: usize = Icmpv6Hdr::LEN;
1782 }
1783
1784 fn round_trip<T>(value: &T) -> T
1785 where
1786 T: SchemaWrite<DefaultConfig, Src = T>,
1787 for<'de> T: SchemaRead<'de, DefaultConfig, Dst = T>,
1788 T: FixedPacket,
1789 {
1790 let mut bytes = [0u8; MAX_PACKET_SIZE];
1791 let len = T::SERIALIZED_LEN;
1792 assert!(len <= bytes.len());
1793 wincode::serialize_into(bytes.as_mut_slice(), value).unwrap();
1794 wincode::deserialize(&bytes).unwrap()
1795 }
1796
1797 fn icmp_hdr_strategy() -> impl Strategy<Value = Icmpv4Hdr> {
1798 (
1799 any::<u8>(),
1800 any::<u8>(),
1801 uniform2(any::<u8>()),
1802 uniform4(any::<u8>()),
1803 )
1804 .prop_map(|(type_, code, check, data)| Icmpv4Hdr {
1805 type_,
1806 code,
1807 check,
1808 data,
1809 })
1810 }
1811
1812 fn echo_bytes(id: [u8; 2], seq: [u8; 2]) -> [u8; 4] {
1813 let mut bytes = [0u8; 4];
1814 bytes[..2].copy_from_slice(&id);
1815 bytes[2..].copy_from_slice(&seq);
1816 bytes
1817 }
1818
1819 fn icmpv6_hdr_strategy() -> impl Strategy<Value = Icmpv6Hdr> {
1820 let echo = (
1821 Just(128u8),
1822 any::<u8>(),
1823 uniform2(any::<u8>()),
1824 uniform2(any::<u8>()),
1825 uniform2(any::<u8>()),
1826 )
1827 .prop_map(|(type_, code, check, id, seq)| Icmpv6Hdr {
1828 type_,
1829 code,
1830 check,
1831 data: echo_bytes(id, seq),
1832 });
1833
1834 let echo_reply = (
1835 Just(129u8),
1836 any::<u8>(),
1837 uniform2(any::<u8>()),
1838 uniform2(any::<u8>()),
1839 uniform2(any::<u8>()),
1840 )
1841 .prop_map(|(type_, code, check, id, seq)| Icmpv6Hdr {
1842 type_,
1843 code,
1844 check,
1845 data: echo_bytes(id, seq),
1846 });
1847
1848 let packet_too_big = (
1849 Just(2u8),
1850 any::<u8>(),
1851 uniform2(any::<u8>()),
1852 uniform4(any::<u8>()),
1853 )
1854 .prop_map(|(type_, code, check, bytes)| Icmpv6Hdr {
1855 type_,
1856 code,
1857 check,
1858 data: bytes,
1859 });
1860
1861 let param_problem = (
1862 Just(4u8),
1863 any::<u8>(),
1864 uniform2(any::<u8>()),
1865 uniform4(any::<u8>()),
1866 )
1867 .prop_map(|(type_, code, check, bytes)| Icmpv6Hdr {
1868 type_,
1869 code,
1870 check,
1871 data: bytes,
1872 });
1873
1874 let redirect = (
1875 Just(137u8),
1876 any::<u8>(),
1877 uniform2(any::<u8>()),
1878 uniform4(any::<u8>()),
1879 )
1880 .prop_map(|(type_, code, check, reserved)| Icmpv6Hdr {
1881 type_,
1882 code,
1883 check,
1884 data: reserved,
1885 });
1886
1887 let fallback = (
1888 any::<u8>().prop_filter("use reserved field", |ty| {
1889 !matches!(ty, 128 | 129 | 2 | 4 | 137)
1890 }),
1891 any::<u8>(),
1892 uniform2(any::<u8>()),
1893 uniform4(any::<u8>()),
1894 )
1895 .prop_map(|(type_, code, check, bytes)| Icmpv6Hdr {
1896 type_,
1897 code,
1898 check,
1899 data: bytes,
1900 });
1901
1902 prop_oneof![
1903 echo,
1904 echo_reply,
1905 packet_too_big,
1906 param_problem,
1907 redirect,
1908 fallback
1909 ]
1910 }
1911
1912 proptest! {
1913 #![proptest_config(ProptestConfig {
1914 failure_persistence: None,
1915 ..ProptestConfig::default()
1916 })]
1917
1918 #[test]
1919 fn icmp_hdr_round_trips(hdr in icmp_hdr_strategy()) {
1920 let decoded = round_trip(&hdr);
1921 prop_assert_eq!(decoded.type_, hdr.type_);
1922 prop_assert_eq!(decoded.code, hdr.code);
1923 prop_assert_eq!(decoded.check, hdr.check);
1924 prop_assert_eq!(decoded.data, hdr.data);
1925 }
1926
1927 #[test]
1928 fn icmpv6_hdr_round_trips(hdr in icmpv6_hdr_strategy()) {
1929 let decoded = round_trip(&hdr);
1930 prop_assert_eq!(decoded.type_, hdr.type_);
1931 prop_assert_eq!(decoded.code, hdr.code);
1932 prop_assert_eq!(decoded.check, hdr.check);
1933 prop_assert_eq!(decoded.data, hdr.data);
1934 }
1935 }
1936}