1use core::{error::Error, fmt, mem};
2
3use num_traits::FromPrimitive as _;
4
5use crate::{getter_be, setter_be};
6
7#[derive(Debug)]
9pub enum IpError {
10 InvalidProto(u8),
12}
13
14impl IpError {
15 pub fn msg_and_code(&self) -> (&'static str, u8) {
16 match self {
17 Self::InvalidProto(id) => ("invalid ID of an encapsulated protocol", *id),
18 }
19 }
20}
21
22impl fmt::Display for IpError {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 let (msg, code) = self.msg_and_code();
25 write!(f, "{msg}: {code}")
26 }
27}
28
29impl Error for IpError {}
30
31#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
33pub enum IpHdr {
34 V4(Ipv4Hdr),
35 V6(Ipv6Hdr),
36}
37
38#[repr(C)]
40#[derive(Debug, Copy, Clone)]
41#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
42#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
43pub struct Ipv4Hdr {
44 pub vihl: u8,
45 pub tos: u8,
46 pub tot_len: [u8; 2],
47 pub id: [u8; 2],
48 pub frags: [u8; 2],
49 pub ttl: u8,
50 pub proto: u8,
51 pub check: [u8; 2],
52 pub src_addr: [u8; 4],
53 pub dst_addr: [u8; 4],
54}
55
56impl Ipv4Hdr {
57 pub const LEN: usize = mem::size_of::<Ipv4Hdr>();
58
59 #[inline]
61 pub fn version(&self) -> u8 {
62 (self.vihl >> 4) & 0xF
63 }
64
65 #[inline]
67 pub fn ihl(&self) -> u8 {
68 (self.vihl & 0xF) << 2
69 }
70
71 #[inline]
73 pub fn options_len(&self) -> u8 {
74 self.ihl() - Self::LEN as u8
75 }
76
77 #[inline]
79 pub fn set_vihl(&mut self, version: u8, ihl_in_bytes: u8) {
80 let ihl_in_words = ihl_in_bytes / 4;
81 self.vihl = ((version & 0xF) << 4) | (ihl_in_words & 0xF);
82 }
83
84 #[inline]
86 pub fn dscp(&self) -> u8 {
87 (self.tos >> 2) & 0x3F
88 }
89
90 #[inline]
92 pub fn ecn(&self) -> u8 {
93 self.tos & 0x3
94 }
95
96 #[inline]
98 pub fn set_tos(&mut self, dscp: u8, ecn: u8) {
99 self.tos = ((dscp & 0x3F) << 2) | (ecn & 0x3);
100 }
101
102 #[inline]
104 pub fn tot_len(&self) -> u16 {
105 unsafe { getter_be!(self, tot_len, u16) }
107 }
108
109 #[inline]
111 pub fn set_tot_len(&mut self, len: u16) {
112 unsafe { setter_be!(self, tot_len, len) }
114 }
115
116 #[inline]
118 pub fn id(&self) -> u16 {
119 unsafe { getter_be!(self, id, u16) }
121 }
122
123 #[inline]
125 pub fn set_id(&mut self, id: u16) {
126 unsafe { setter_be!(self, id, id) }
128 }
129
130 #[inline]
131 fn frags(&self) -> u16 {
132 unsafe { getter_be!(self, frags, u16) }
134 }
135
136 #[inline]
138 pub fn frag_flags(&self) -> u8 {
139 (self.frags() >> 13) as u8
140 }
141
142 #[inline]
144 pub fn frag_offset(&self) -> u16 {
145 self.frags() & 0x1FFF
146 }
147
148 #[inline]
150 pub fn set_frags(&mut self, flags: u8, offset: u16) {
151 let value = ((flags as u16 & 0x7) << 13) | (offset & 0x1FFF);
152 unsafe { setter_be!(self, frags, value) }
154 }
155
156 #[inline]
158 pub fn proto(&self) -> Result<IpProto, IpError> {
159 IpProto::from_u8(self.proto).ok_or(IpError::InvalidProto(self.proto))
160 }
161
162 #[inline]
164 pub fn set_proto(&mut self, proto: IpProto) {
165 self.proto = proto.into();
166 }
167
168 #[inline]
170 pub fn checksum(&self) -> u16 {
171 unsafe { getter_be!(self, check, u16) }
173 }
174
175 #[inline]
177 pub fn set_checksum(&mut self, checksum: u16) {
178 unsafe { setter_be!(self, check, checksum) }
180 }
181
182 #[inline]
184 pub fn src_addr(&self) -> core::net::Ipv4Addr {
185 core::net::Ipv4Addr::from(self.src_addr)
186 }
187
188 #[inline]
190 pub fn dst_addr(&self) -> core::net::Ipv4Addr {
191 core::net::Ipv4Addr::from(self.dst_addr)
192 }
193
194 #[inline]
196 pub fn set_src_addr(&mut self, src: core::net::Ipv4Addr) {
197 self.src_addr = src.octets();
198 }
199
200 #[inline]
202 pub fn set_dst_addr(&mut self, dst: core::net::Ipv4Addr) {
203 self.dst_addr = dst.octets();
204 }
205}
206
207#[repr(C)]
209#[derive(Debug, Copy, Clone)]
210#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
211#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
212pub struct Ipv6Hdr {
213 pub vcf: [u8; 4],
215 pub payload_len: [u8; 2],
217 pub next_hdr: u8,
219 pub hop_limit: u8,
221 pub src_addr: [u8; 16],
223 pub dst_addr: [u8; 16],
225}
226
227impl Ipv6Hdr {
228 pub const LEN: usize = mem::size_of::<Ipv6Hdr>();
229
230 #[inline]
232 pub fn version(&self) -> u8 {
233 (self.vcf[0] >> 4) & 0xF
234 }
235
236 #[inline]
238 pub fn set_version(&mut self, version: u8) {
239 self.vcf[0] = (self.vcf[0] & 0x0F) | ((version & 0xF) << 4);
240 }
241
242 #[inline]
244 pub fn dscp(&self) -> u8 {
245 ((self.vcf[0] & 0x0F) << 2) | ((self.vcf[1] >> 6) & 0x03)
246 }
247
248 #[inline]
250 pub fn ecn(&self) -> u8 {
251 (self.vcf[1] >> 4) & 0x03
252 }
253
254 #[inline]
256 pub fn flow_label(&self) -> u32 {
257 ((self.vcf[1] as u32 & 0x0F) << 16) | ((self.vcf[2] as u32) << 8) | (self.vcf[3] as u32)
258 }
259
260 #[inline]
262 pub fn set_dscp_ecn(&mut self, dscp: u8, ecn: u8) {
263 self.vcf[0] = (self.vcf[0] & 0xF0) | ((dscp >> 2) & 0x0F);
265
266 self.vcf[1] = (self.vcf[1] & 0x0F) | (((dscp & 0x03) << 6) | ((ecn & 0x03) << 4));
268 }
269
270 #[inline]
272 pub fn set_flow_label(&mut self, flow_label: u32) {
273 self.vcf[1] = (self.vcf[1] & 0xF0) | ((flow_label >> 16) as u8 & 0x0F);
274 self.vcf[2] = ((flow_label >> 8) & 0xFF) as u8;
275 self.vcf[3] = (flow_label & 0xFF) as u8;
276 }
277
278 #[inline]
280 pub fn set_vcf(&mut self, version: u8, dscp: u8, ecn: u8, flow_label: u32) {
281 self.vcf[0] = ((version & 0x0F) << 4) | ((dscp >> 2) & 0x0F);
282 self.vcf[1] =
283 ((dscp & 0x03) << 6) | ((ecn & 0x03) << 4) | ((flow_label >> 16) as u8 & 0x0F);
284 self.vcf[2] = ((flow_label >> 8) & 0xFF) as u8;
285 self.vcf[3] = (flow_label & 0xFF) as u8;
286 }
287
288 #[inline]
290 pub fn payload_len(&self) -> u16 {
291 unsafe { getter_be!(self, payload_len, u16) }
293 }
294
295 #[inline]
297 pub fn set_payload_len(&mut self, len: u16) {
298 unsafe { setter_be!(self, payload_len, len) }
300 }
301
302 #[inline]
304 pub fn next_hdr(&self) -> Result<IpProto, IpError> {
305 IpProto::from_u8(self.next_hdr).ok_or(IpError::InvalidProto(self.next_hdr))
306 }
307
308 #[inline]
310 pub fn set_next_hdr(&mut self, proto: IpProto) {
311 self.next_hdr = proto.into();
312 }
313
314 #[inline]
316 pub fn src_addr(&self) -> core::net::Ipv6Addr {
317 core::net::Ipv6Addr::from(self.src_addr)
318 }
319
320 #[inline]
322 pub fn dst_addr(&self) -> core::net::Ipv6Addr {
323 core::net::Ipv6Addr::from(self.dst_addr)
324 }
325
326 #[inline]
328 pub fn set_src_addr(&mut self, src: core::net::Ipv6Addr) {
329 self.src_addr = src.octets();
330 }
331
332 #[inline]
334 pub fn set_dst_addr(&mut self, dst: core::net::Ipv6Addr) {
335 self.dst_addr = dst.octets();
336 }
337}
338
339#[repr(u8)]
342#[derive(
343 PartialEq, Eq, Debug, Copy, Clone, Hash, num_derive::FromPrimitive, num_derive::ToPrimitive,
344)]
345#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
346pub enum IpProto {
347 HopOpt = 0,
349 Icmp = 1,
351 Igmp = 2,
353 Ggp = 3,
355 Ipv4 = 4,
357 Stream = 5,
359 Tcp = 6,
361 Cbt = 7,
363 Egp = 8,
365 Igp = 9,
367 BbnRccMon = 10,
369 NvpII = 11,
371 Pup = 12,
373 Argus = 13,
375 Emcon = 14,
377 Xnet = 15,
379 Chaos = 16,
381 Udp = 17,
383 Mux = 18,
385 DcnMeas = 19,
387 Hmp = 20,
389 Prm = 21,
391 Idp = 22,
393 Trunk1 = 23,
395 Trunk2 = 24,
397 Leaf1 = 25,
399 Leaf2 = 26,
401 Rdp = 27,
403 Irtp = 28,
405 Tp4 = 29,
407 Netblt = 30,
409 MfeNsp = 31,
411 MeritInp = 32,
413 Dccp = 33,
415 ThirdPartyConnect = 34,
417 Idpr = 35,
419 Xtp = 36,
421 Ddp = 37,
423 IdprCmtp = 38,
425 TpPlusPlus = 39,
427 Il = 40,
429 Ipv6 = 41,
431 Sdrp = 42,
433 Ipv6Route = 43,
435 Ipv6Frag = 44,
437 Idrp = 45,
439 Rsvp = 46,
441 Gre = 47,
443 Dsr = 48,
445 Bna = 49,
447 Esp = 50,
449 Ah = 51,
451 Inlsp = 52,
453 Swipe = 53,
455 Narp = 54,
457 Mobile = 55,
459 Tlsp = 56,
461 Skip = 57,
463 Ipv6Icmp = 58,
465 Ipv6NoNxt = 59,
467 Ipv6Opts = 60,
469 AnyHostInternal = 61,
471 Cftp = 62,
473 AnyLocalNetwork = 63,
475 SatExpak = 64,
477 Kryptolan = 65,
479 Rvd = 66,
481 Ippc = 67,
483 AnyDistributedFileSystem = 68,
485 SatMon = 69,
487 Visa = 70,
489 Ipcv = 71,
491 Cpnx = 72,
493 Cphb = 73,
495 Wsn = 74,
497 Pvp = 75,
499 BrSatMon = 76,
501 SunNd = 77,
503 WbMon = 78,
505 WbExpak = 79,
507 IsoIp = 80,
509 Vmtp = 81,
511 SecureVmtp = 82,
513 Vines = 83,
515 Ttp = 84,
517 NsfnetIgp = 85,
519 Dgp = 86,
521 Tcf = 87,
523 Eigrp = 88,
525 Ospfigp = 89,
527 SpriteRpc = 90,
529 Larp = 91,
531 Mtp = 92,
533 Ax25 = 93,
535 Ipip = 94,
537 Micp = 95,
539 SccSp = 96,
541 Etherip = 97,
543 Encap = 98,
545 AnyPrivateEncryptionScheme = 99,
547 Gmtp = 100,
549 Ifmp = 101,
551 Pnni = 102,
553 Pim = 103,
555 Aris = 104,
557 Scps = 105,
559 Qnx = 106,
561 ActiveNetworks = 107,
563 IpComp = 108,
565 Snp = 109,
567 CompaqPeer = 110,
569 IpxInIp = 111,
571 Vrrp = 112,
573 Pgm = 113,
575 AnyZeroHopProtocol = 114,
577 L2tp = 115,
579 Ddx = 116,
581 Iatp = 117,
583 Stp = 118,
585 Srp = 119,
587 Uti = 120,
589 Smp = 121,
591 Sm = 122,
593 Ptp = 123,
595 IsisOverIpv4 = 124,
597 Fire = 125,
599 Crtp = 126,
601 Crudp = 127,
603 Sscopmce = 128,
605 Iplt = 129,
607 Sps = 130,
609 Pipe = 131,
611 Sctp = 132,
613 Fc = 133,
615 RsvpE2eIgnore = 134,
617 MobilityHeader = 135,
619 UdpLite = 136,
621 Mpls = 137,
623 Manet = 138,
625 Hip = 139,
627 Shim6 = 140,
629 Wesp = 141,
631 Rohc = 142,
633 EthernetInIpv4 = 143,
635 Aggfrag = 144,
637 Test1 = 253,
639 Test2 = 254,
641 Reserved = 255,
643}
644
645impl From<IpProto> for u8 {
649 fn from(value: IpProto) -> Self {
650 value as u8
651 }
652}
653
654#[cfg(test)]
655mod tests {
656 use super::*;
657 use core::net::{Ipv4Addr, Ipv6Addr};
658
659 fn default_ipv4_hdr() -> Ipv4Hdr {
661 Ipv4Hdr {
662 vihl: 0,
663 tos: 0,
664 tot_len: [0; 2],
665 id: [0; 2],
666 frags: [0; 2],
667 ttl: 0,
668 proto: IpProto::Tcp.into(),
669 check: [0; 2],
670 src_addr: [0; 4],
671 dst_addr: [0; 4],
672 }
673 }
674
675 fn default_ipv6_hdr() -> Ipv6Hdr {
677 Ipv6Hdr {
678 vcf: [0; 4],
679 payload_len: [0; 2],
680 next_hdr: IpProto::Tcp.into(),
681 hop_limit: 0,
682 src_addr: [0; 16],
683 dst_addr: [0; 16],
684 }
685 }
686
687 #[test]
688 fn test_ipv4_vihl() {
689 let mut hdr = default_ipv4_hdr();
690 hdr.set_vihl(4, 20); assert_eq!(hdr.version(), 4);
692 assert_eq!(hdr.ihl(), 20);
693 assert_eq!(hdr.options_len(), 0);
694
695 hdr.set_vihl(4, 24); assert_eq!(hdr.version(), 4);
697 assert_eq!(hdr.ihl(), 24);
698 assert_eq!(hdr.options_len(), 4);
699
700 hdr.set_vihl(4, 60); assert_eq!(hdr.version(), 4);
702 assert_eq!(hdr.ihl(), 60);
703 assert_eq!(hdr.options_len(), 40);
704 }
705
706 #[test]
707 fn test_ipv4_tos() {
708 let mut hdr = default_ipv4_hdr();
709 hdr.set_tos(0b001010, 0b01); assert_eq!(hdr.dscp(), 0b001010);
711 assert_eq!(hdr.ecn(), 0b01);
712
713 hdr.set_tos(0b110011, 0b10); assert_eq!(hdr.dscp(), 0b110011);
715 assert_eq!(hdr.ecn(), 0b10);
716 }
717
718 #[test]
719 fn test_ipv4_tot_len() {
720 let mut hdr = default_ipv4_hdr();
721 hdr.set_tot_len(1500);
722 assert_eq!(hdr.tot_len(), 1500);
723 }
724
725 #[test]
726 fn test_ipv4_id() {
727 let mut hdr = default_ipv4_hdr();
728 hdr.set_id(0xABCD);
729 assert_eq!(hdr.id(), 0xABCD);
730 }
731
732 #[test]
733 fn test_ipv4_frags() {
734 let mut hdr = default_ipv4_hdr();
735 hdr.set_frags(0b010, 100);
737 assert_eq!(hdr.frag_flags(), 0b010);
738 assert_eq!(hdr.frag_offset(), 100);
739
740 hdr.set_frags(0b001, 0x1ABC);
742 assert_eq!(hdr.frag_flags(), 0b001);
743 assert_eq!(hdr.frag_offset(), 0x1ABC);
744 }
745
746 #[test]
747 fn test_ipv4_checksum() {
748 let mut hdr = default_ipv4_hdr();
749 hdr.set_checksum(0x1234);
750 assert_eq!(hdr.checksum(), 0x1234);
751 }
752
753 #[test]
754 fn test_ipv4_addrs() {
755 let mut hdr = default_ipv4_hdr();
756 let src = Ipv4Addr::new(192, 168, 1, 1);
757 let dst = Ipv4Addr::new(10, 0, 0, 1);
758 hdr.set_src_addr(src);
759 hdr.set_dst_addr(dst);
760 assert_eq!(hdr.src_addr(), src);
761 assert_eq!(hdr.dst_addr(), dst);
762 }
763
764 #[test]
765 fn test_ipv6_version() {
766 let mut hdr = default_ipv6_hdr();
767 hdr.set_version(6);
768 assert_eq!(hdr.version(), 6);
769 }
770
771 #[test]
772 fn test_ipv6_dscp_ecn() {
773 let mut hdr = default_ipv6_hdr();
774 hdr.set_dscp_ecn(0b001010, 0b01);
776 assert_eq!(hdr.dscp(), 0b001010);
777 assert_eq!(hdr.ecn(), 0b01);
778
779 hdr.set_version(6);
783 hdr.set_flow_label(0xFFFFF); hdr.set_dscp_ecn(0b110011, 0b10);
785 assert_eq!(hdr.version(), 6); assert_eq!(hdr.dscp(), 0b110011);
787 assert_eq!(hdr.ecn(), 0b10);
788 assert_eq!(hdr.flow_label(), 0xFFFFF); }
790
791 #[test]
792 fn test_ipv6_flow_label() {
793 let mut hdr = default_ipv6_hdr();
794 hdr.set_flow_label(0x12345); assert_eq!(hdr.flow_label(), 0x12345);
796
797 hdr.set_version(6);
800 hdr.set_dscp_ecn(0b001010, 0b01);
801 hdr.set_flow_label(0xABCDE);
802 assert_eq!(hdr.version(), 6);
803 assert_eq!(hdr.dscp(), 0b001010);
804 assert_eq!(hdr.ecn(), 0b01);
805 assert_eq!(hdr.flow_label(), 0xABCDE);
806 }
807
808 #[test]
809 fn test_ipv6_set_vcf() {
810 let mut hdr = default_ipv6_hdr();
811 let version = 6;
812 let dscp = 0b001111; let ecn = 0b11; let flow_label = 0xFEDCB; hdr.set_vcf(version, dscp, ecn, flow_label);
817 assert_eq!(hdr.version(), version);
818 assert_eq!(hdr.dscp(), dscp);
819 assert_eq!(hdr.ecn(), ecn);
820 assert_eq!(hdr.flow_label(), flow_label);
821 }
822
823 #[test]
824 fn test_ipv6_payload_len() {
825 let mut hdr = default_ipv6_hdr();
826 hdr.set_payload_len(3000);
827 assert_eq!(hdr.payload_len(), 3000);
828 }
829
830 #[test]
831 fn test_ipv6_addrs() {
832 let mut hdr = default_ipv6_hdr();
833 let src = Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0001);
834 let dst = Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x0002);
835 hdr.set_src_addr(src);
836 hdr.set_dst_addr(dst);
837 assert_eq!(hdr.src_addr(), src);
838 assert_eq!(hdr.dst_addr(), dst);
839 }
840
841 #[test]
842 fn test_ip_proto_variants() {
843 assert_eq!(IpProto::Tcp as u8, 6);
844 assert_eq!(IpProto::Udp as u8, 17);
845 assert_eq!(IpProto::Icmp as u8, 1);
846 assert_eq!(IpProto::Ipv6Icmp as u8, 58);
847 }
848
849 #[test]
850 fn test_iphdr_enum() {
851 let ipv4_hdr = default_ipv4_hdr();
852 let ip_hdr_v4 = IpHdr::V4(ipv4_hdr);
853 if let IpHdr::V4(hdr) = ip_hdr_v4 {
854 assert_eq!(hdr.vihl, ipv4_hdr.vihl); } else {
856 panic!("Expected IpHdr::V4");
857 }
858
859 let ipv6_hdr = default_ipv6_hdr();
860 let ip_hdr_v6 = IpHdr::V6(ipv6_hdr);
861 if let IpHdr::V6(hdr) = ip_hdr_v6 {
862 assert_eq!(hdr.vcf, ipv6_hdr.vcf); } else {
864 panic!("Expected IpHdr::V6");
865 }
866 }
867}