Skip to main content

network_types/
ip.rs

1use core::{error::Error, fmt, mem};
2
3use num_traits::FromPrimitive as _;
4
5use crate::{getter_be, setter_be};
6
7/// Represents errors that can occur while processing ICMP headers.
8#[derive(Debug)]
9pub enum IpError {
10    /// Invalid ID of an encapsulated protocol.
11    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/// IP headers, which are present after the Ethernet header.
32#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
33pub enum IpHdr {
34    V4(Ipv4Hdr),
35    V6(Ipv6Hdr),
36}
37
38/// IPv4 header, which is present after the Ethernet header.
39#[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    /// Returns the IP version field (should be 4).
60    #[inline]
61    pub fn version(&self) -> u8 {
62        (self.vihl >> 4) & 0xF
63    }
64
65    /// Returns the IP header length in bytes.
66    #[inline]
67    pub fn ihl(&self) -> u8 {
68        (self.vihl & 0xF) << 2
69    }
70
71    /// Returns the length of the IP options in bytes.
72    #[inline]
73    pub fn options_len(&self) -> u8 {
74        self.ihl() - Self::LEN as u8
75    }
76
77    /// Sets both the version and IHL fields.
78    #[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    /// Returns the DSCP (Differentiated Services Code Point) field.
85    #[inline]
86    pub fn dscp(&self) -> u8 {
87        (self.tos >> 2) & 0x3F
88    }
89
90    /// Returns the ECN (Explicit Congestion Notification) field.
91    #[inline]
92    pub fn ecn(&self) -> u8 {
93        self.tos & 0x3
94    }
95
96    /// Sets the TOS field with separate DSCP and ECN values.
97    #[inline]
98    pub fn set_tos(&mut self, dscp: u8, ecn: u8) {
99        self.tos = ((dscp & 0x3F) << 2) | (ecn & 0x3);
100    }
101
102    /// Returns the total length of the IP packet.
103    #[inline]
104    pub fn tot_len(&self) -> u16 {
105        // SAFETY: Pointer arithmetic in bounds of the struct.
106        unsafe { getter_be!(self, tot_len, u16) }
107    }
108
109    /// Sets the total length of the IP packet.
110    #[inline]
111    pub fn set_tot_len(&mut self, len: u16) {
112        // SAFETY: Pointer arithmetic in bounds of the struct.
113        unsafe { setter_be!(self, tot_len, len) }
114    }
115
116    /// Returns the identification field.
117    #[inline]
118    pub fn id(&self) -> u16 {
119        // SAFETY: Pointer arithmetic in bounds of the struct.
120        unsafe { getter_be!(self, id, u16) }
121    }
122
123    /// Sets the identification field.
124    #[inline]
125    pub fn set_id(&mut self, id: u16) {
126        // SAFETY: Pointer arithmetic in bounds of the struct.
127        unsafe { setter_be!(self, id, id) }
128    }
129
130    #[inline]
131    fn frags(&self) -> u16 {
132        // SAFETY: Pointer arithmetic in bounds of the struct.
133        unsafe { getter_be!(self, frags, u16) }
134    }
135
136    /// Returns the fragmentation flags (3 bits).
137    #[inline]
138    pub fn frag_flags(&self) -> u8 {
139        (self.frags() >> 13) as u8
140    }
141
142    /// Returns the fragmentation offset (13 bits).
143    #[inline]
144    pub fn frag_offset(&self) -> u16 {
145        self.frags() & 0x1FFF
146    }
147
148    /// Sets both the fragmentation flags and offset.
149    #[inline]
150    pub fn set_frags(&mut self, flags: u8, offset: u16) {
151        let value = ((flags as u16 & 0x7) << 13) | (offset & 0x1FFF);
152        // SAFETY: Pointer arithmetic in bounds of the struct.
153        unsafe { setter_be!(self, frags, value) }
154    }
155
156    /// Returns the encapsulated protocol.
157    #[inline]
158    pub fn proto(&self) -> Result<IpProto, IpError> {
159        IpProto::from_u8(self.proto).ok_or(IpError::InvalidProto(self.proto))
160    }
161
162    /// Sets the encapsulated protocol.
163    #[inline]
164    pub fn set_proto(&mut self, proto: IpProto) {
165        self.proto = proto.into();
166    }
167
168    /// Returns the checksum field.
169    #[inline]
170    pub fn checksum(&self) -> u16 {
171        // SAFETY: Pointer arithmetic in bounds of the struct.
172        unsafe { getter_be!(self, check, u16) }
173    }
174
175    /// Sets the checksum field.
176    #[inline]
177    pub fn set_checksum(&mut self, checksum: u16) {
178        // SAFETY: Pointer arithmetic in bounds of the struct.
179        unsafe { setter_be!(self, check, checksum) }
180    }
181
182    /// Returns the source address field.
183    #[inline]
184    pub fn src_addr(&self) -> core::net::Ipv4Addr {
185        core::net::Ipv4Addr::from(self.src_addr)
186    }
187
188    /// Returns the destination address field.
189    #[inline]
190    pub fn dst_addr(&self) -> core::net::Ipv4Addr {
191        core::net::Ipv4Addr::from(self.dst_addr)
192    }
193
194    /// Sets the source address field.
195    #[inline]
196    pub fn set_src_addr(&mut self, src: core::net::Ipv4Addr) {
197        self.src_addr = src.octets();
198    }
199
200    /// Sets the destination address field.
201    #[inline]
202    pub fn set_dst_addr(&mut self, dst: core::net::Ipv4Addr) {
203        self.dst_addr = dst.octets();
204    }
205}
206
207/// IPv6 header, which is present after the Ethernet header.
208#[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    /// First 4 bytes containing Version (4 bits), Traffic Class (8 bits), and Flow Label (20 bits)
214    pub vcf: [u8; 4],
215    /// Payload length (excluding the IPv6 header)
216    pub payload_len: [u8; 2],
217    /// Next header protocol
218    pub next_hdr: u8,
219    /// Hop limit (similar to TTL in IPv4)
220    pub hop_limit: u8,
221    /// Source IPv6 address (16 bytes)
222    pub src_addr: [u8; 16],
223    /// Destination IPv6 address (16 bytes)
224    pub dst_addr: [u8; 16],
225}
226
227impl Ipv6Hdr {
228    pub const LEN: usize = mem::size_of::<Ipv6Hdr>();
229
230    /// Returns the IP version field (should be 6).
231    #[inline]
232    pub fn version(&self) -> u8 {
233        (self.vcf[0] >> 4) & 0xF
234    }
235
236    /// Sets the version field.
237    #[inline]
238    pub fn set_version(&mut self, version: u8) {
239        self.vcf[0] = (self.vcf[0] & 0x0F) | ((version & 0xF) << 4);
240    }
241
242    /// Returns the DSCP (Differentiated Services Code Point) field.
243    #[inline]
244    pub fn dscp(&self) -> u8 {
245        ((self.vcf[0] & 0x0F) << 2) | ((self.vcf[1] >> 6) & 0x03)
246    }
247
248    /// Returns the ECN (Explicit Congestion Notification) field.
249    #[inline]
250    pub fn ecn(&self) -> u8 {
251        (self.vcf[1] >> 4) & 0x03
252    }
253
254    /// Returns the flow label field (20 bits).
255    #[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    /// Sets the DSCP and ECN fields.
261    #[inline]
262    pub fn set_dscp_ecn(&mut self, dscp: u8, ecn: u8) {
263        // Set the lower 4 bits of the first byte (upper 4 bits of DSCP)
264        self.vcf[0] = (self.vcf[0] & 0xF0) | ((dscp >> 2) & 0x0F);
265
266        // Set the upper 2 bits of the second byte (lower 2 bits of DSCP) and the next 2 bits (ECN)
267        self.vcf[1] = (self.vcf[1] & 0x0F) | (((dscp & 0x03) << 6) | ((ecn & 0x03) << 4));
268    }
269
270    /// Sets the flow label field (20 bits).
271    #[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    /// Sets the version, DSCP, ECN, and flow label in one operation.
279    #[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    /// Returns the payload length.
289    #[inline]
290    pub fn payload_len(&self) -> u16 {
291        // SAFETY: Pointer arithmetic in bounds of the struct.
292        unsafe { getter_be!(self, payload_len, u16) }
293    }
294
295    /// Sets the payload length.
296    #[inline]
297    pub fn set_payload_len(&mut self, len: u16) {
298        // SAFETY: Pointer arithmetic in bounds of the struct.
299        unsafe { setter_be!(self, payload_len, len) }
300    }
301
302    /// Returns the encapsulated protocol.
303    #[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    /// Sets the encapsulated protocol.
309    #[inline]
310    pub fn set_next_hdr(&mut self, proto: IpProto) {
311        self.next_hdr = proto.into();
312    }
313
314    /// Returns the source address field.
315    #[inline]
316    pub fn src_addr(&self) -> core::net::Ipv6Addr {
317        core::net::Ipv6Addr::from(self.src_addr)
318    }
319
320    /// Returns the destination address field.
321    #[inline]
322    pub fn dst_addr(&self) -> core::net::Ipv6Addr {
323        core::net::Ipv6Addr::from(self.dst_addr)
324    }
325
326    /// Sets the source address field.
327    #[inline]
328    pub fn set_src_addr(&mut self, src: core::net::Ipv6Addr) {
329        self.src_addr = src.octets();
330    }
331
332    /// Sets the destination address field.
333    #[inline]
334    pub fn set_dst_addr(&mut self, dst: core::net::Ipv6Addr) {
335        self.dst_addr = dst.octets();
336    }
337}
338
339/// Protocol which is encapsulated in the IPv4 packet.
340/// <https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml>
341#[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    /// IPv6 Hop-by-Hop Option
348    HopOpt = 0,
349    /// Internet Control Message
350    Icmp = 1,
351    /// Internet Group Management
352    Igmp = 2,
353    /// Gateway-to-Gateway
354    Ggp = 3,
355    /// IPv4 encapsulation
356    Ipv4 = 4,
357    /// Stream
358    Stream = 5,
359    /// Transmission Control
360    Tcp = 6,
361    /// CBT
362    Cbt = 7,
363    /// Exterior Gateway Protocol
364    Egp = 8,
365    /// Any private interior gateway (used by Cisco for their IGRP)
366    Igp = 9,
367    /// BBN RCC Monitoring
368    BbnRccMon = 10,
369    /// Network Voice Protocol
370    NvpII = 11,
371    /// PUP
372    Pup = 12,
373    /// ARGUS
374    Argus = 13,
375    /// EMCON
376    Emcon = 14,
377    /// Cross Net Debugger
378    Xnet = 15,
379    /// Chaos
380    Chaos = 16,
381    /// User Datagram
382    Udp = 17,
383    /// Multiplexing
384    Mux = 18,
385    /// DCN Measurement Subsystems
386    DcnMeas = 19,
387    /// Host Monitoring
388    Hmp = 20,
389    /// Packet Radio Measurement
390    Prm = 21,
391    /// XEROX NS IDP
392    Idp = 22,
393    /// Trunk-1
394    Trunk1 = 23,
395    /// Trunk-2
396    Trunk2 = 24,
397    /// Leaf-1
398    Leaf1 = 25,
399    /// Leaf-2
400    Leaf2 = 26,
401    /// Reliable Data Protocol
402    Rdp = 27,
403    /// Internet Reliable Transaction
404    Irtp = 28,
405    /// ISO Transport Protocol Class 4
406    Tp4 = 29,
407    /// Bulk Data Transfer Protocol
408    Netblt = 30,
409    /// MFE Network Services Protocol
410    MfeNsp = 31,
411    /// MERIT Internodal Protocol
412    MeritInp = 32,
413    /// Datagram Congestion Control Protocol
414    Dccp = 33,
415    /// Third Party Connect Protocol
416    ThirdPartyConnect = 34,
417    /// Inter-Domain Policy Routing Protocol
418    Idpr = 35,
419    /// XTP
420    Xtp = 36,
421    /// Datagram Delivery Protocol
422    Ddp = 37,
423    /// IDPR Control Message Transport Proto
424    IdprCmtp = 38,
425    /// TP++ Transport Protocol
426    TpPlusPlus = 39,
427    /// IL Transport Protocol
428    Il = 40,
429    /// IPv6 encapsulation
430    Ipv6 = 41,
431    /// Source Demand Routing Protocol
432    Sdrp = 42,
433    /// Routing Header for IPv6
434    Ipv6Route = 43,
435    /// Fragment Header for IPv6
436    Ipv6Frag = 44,
437    /// Inter-Domain Routing Protocol
438    Idrp = 45,
439    /// Reservation Protocol
440    Rsvp = 46,
441    /// General Routing Encapsulation
442    Gre = 47,
443    /// Dynamic Source Routing Protocol
444    Dsr = 48,
445    /// BNA
446    Bna = 49,
447    /// Encap Security Payload
448    Esp = 50,
449    /// Authentication Header
450    Ah = 51,
451    /// Integrated Net Layer Security TUBA
452    Inlsp = 52,
453    /// IP with Encryption
454    Swipe = 53,
455    /// NBMA Address Resolution Protocol
456    Narp = 54,
457    /// IP Mobility
458    Mobile = 55,
459    /// Transport Layer Security Protocol using Kryptonet key management
460    Tlsp = 56,
461    /// SKIP
462    Skip = 57,
463    /// Internet Control Message Protocol for IPv6
464    Ipv6Icmp = 58,
465    /// No Next Header for IPv6
466    Ipv6NoNxt = 59,
467    /// Destination Options for IPv6
468    Ipv6Opts = 60,
469    /// Any host internal protocol
470    AnyHostInternal = 61,
471    /// CFTP
472    Cftp = 62,
473    /// Any local network
474    AnyLocalNetwork = 63,
475    /// SATNET and Backroom EXPAK
476    SatExpak = 64,
477    /// Kryptolan
478    Kryptolan = 65,
479    /// MIT Remote Virtual Disk Protocol
480    Rvd = 66,
481    /// Internet Pluribus Packet Core
482    Ippc = 67,
483    /// Any distributed file system
484    AnyDistributedFileSystem = 68,
485    /// SATNET Monitoring
486    SatMon = 69,
487    /// VISA Protocol
488    Visa = 70,
489    /// Internet Packet Core Utility
490    Ipcv = 71,
491    /// Computer Protocol Network Executive
492    Cpnx = 72,
493    /// Computer Protocol Heart Beat
494    Cphb = 73,
495    /// Wang Span Network
496    Wsn = 74,
497    /// Packet Video Protocol
498    Pvp = 75,
499    /// Backroom SATNET Monitoring
500    BrSatMon = 76,
501    /// SUN ND PROTOCOL-Temporary
502    SunNd = 77,
503    /// WIDEBAND Monitoring
504    WbMon = 78,
505    /// WIDEBAND EXPAK
506    WbExpak = 79,
507    /// ISO Internet Protocol
508    IsoIp = 80,
509    /// VMTP
510    Vmtp = 81,
511    /// SECURE-VMTP
512    SecureVmtp = 82,
513    /// VINES
514    Vines = 83,
515    /// Transaction Transport Protocol
516    Ttp = 84,
517    /// NSFNET-IGP
518    NsfnetIgp = 85,
519    /// Dissimilar Gateway Protocol
520    Dgp = 86,
521    /// TCF
522    Tcf = 87,
523    /// EIGRP
524    Eigrp = 88,
525    /// OSPFIGP
526    Ospfigp = 89,
527    /// Sprite RPC Protocol
528    SpriteRpc = 90,
529    /// Locus Address Resolution Protocol
530    Larp = 91,
531    /// Multicast Transport Protocol
532    Mtp = 92,
533    /// AX.25 Frames
534    Ax25 = 93,
535    /// IP-within-IP Encapsulation Protocol
536    Ipip = 94,
537    /// Mobile Internetworking Control Pro.
538    Micp = 95,
539    /// Semaphore Communications Sec. Pro.
540    SccSp = 96,
541    /// Ethernet-within-IP Encapsulation
542    Etherip = 97,
543    /// Encapsulation Header
544    Encap = 98,
545    /// Any private encryption scheme
546    AnyPrivateEncryptionScheme = 99,
547    /// GMTP
548    Gmtp = 100,
549    /// Ipsilon Flow Management Protocol
550    Ifmp = 101,
551    /// PNNI over IP
552    Pnni = 102,
553    /// Protocol Independent Multicast
554    Pim = 103,
555    /// ARIS
556    Aris = 104,
557    /// SCPS
558    Scps = 105,
559    /// QNX
560    Qnx = 106,
561    /// Active Networks
562    ActiveNetworks = 107,
563    /// IP Payload Compression Protocol
564    IpComp = 108,
565    /// Sitara Networks Protocol
566    Snp = 109,
567    /// Compaq Peer Protocol
568    CompaqPeer = 110,
569    /// IPX in IP
570    IpxInIp = 111,
571    /// Virtual Router Redundancy Protocol
572    Vrrp = 112,
573    /// PGM Reliable Transport Protocol
574    Pgm = 113,
575    /// Any 0-hop protocol
576    AnyZeroHopProtocol = 114,
577    /// Layer Two Tunneling Protocol
578    L2tp = 115,
579    /// D-II Data Exchange (DDX)
580    Ddx = 116,
581    /// Interactive Agent Transfer Protocol
582    Iatp = 117,
583    /// Schedule Transfer Protocol
584    Stp = 118,
585    /// SpectraLink Radio Protocol
586    Srp = 119,
587    /// UTI
588    Uti = 120,
589    /// Simple Message Protocol
590    Smp = 121,
591    /// Simple Multicast Protocol
592    Sm = 122,
593    /// Performance Transparency Protocol
594    Ptp = 123,
595    /// ISIS over IPv4
596    IsisOverIpv4 = 124,
597    /// FIRE
598    Fire = 125,
599    /// Combat Radio Transport Protocol
600    Crtp = 126,
601    /// Combat Radio User Datagram
602    Crudp = 127,
603    /// SSCOPMCE
604    Sscopmce = 128,
605    /// IPLT
606    Iplt = 129,
607    /// Secure Packet Shield
608    Sps = 130,
609    /// Private IP Encapsulation within IP
610    Pipe = 131,
611    /// Stream Control Transmission Protocol
612    Sctp = 132,
613    /// Fibre Channel
614    Fc = 133,
615    /// RSVP-E2E-IGNORE
616    RsvpE2eIgnore = 134,
617    /// Mobility Header
618    MobilityHeader = 135,
619    /// Lightweight User Datagram Protocol
620    UdpLite = 136,
621    /// MPLS-in-IP
622    Mpls = 137,
623    /// MANET Protocols
624    Manet = 138,
625    /// Host Identity Protocol
626    Hip = 139,
627    /// Shim6 Protocol
628    Shim6 = 140,
629    /// Wrapped Encapsulating Security Payload
630    Wesp = 141,
631    /// Robust Header Compression
632    Rohc = 142,
633    /// Ethernet in IPv4
634    EthernetInIpv4 = 143,
635    /// AGGFRAG encapsulation payload for ESP
636    Aggfrag = 144,
637    /// Use for experimentation and testing
638    Test1 = 253,
639    /// Use for experimentation and testing
640    Test2 = 254,
641    /// Reserved
642    Reserved = 255,
643}
644
645// `num_traits::ToPrimitive::to_u8` returns an `Option`, but since `IpProto` is
646// `#[repr(u8)]`, it will never return `None`. Provide an infallible
647// alternative for convenience.
648impl 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    // Helper to create a default Ipv4Hdr for tests
660    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    // Helper to create a default Ipv6Hdr for tests
676    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); // Version 4, IHL 20 bytes (5 words)
691        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); // Version 4, IHL 24 bytes (6 words)
696        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); // Version 4, IHL 60 bytes (15 words)
701        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); // DSCP 10, ECN 1
710        assert_eq!(hdr.dscp(), 0b001010);
711        assert_eq!(hdr.ecn(), 0b01);
712
713        hdr.set_tos(0b110011, 0b10); // DSCP 51, ECN 2
714        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        // Flags: 0b010 (DF set), Offset: 100
736        hdr.set_frags(0b010, 100);
737        assert_eq!(hdr.frag_flags(), 0b010);
738        assert_eq!(hdr.frag_offset(), 100);
739
740        // Flags: 0b001 (MF set), Offset: 0x1ABC
741        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        // DSCP: 0b001010 (10), ECN: 0b01 (1)
775        hdr.set_dscp_ecn(0b001010, 0b01);
776        assert_eq!(hdr.dscp(), 0b001010);
777        assert_eq!(hdr.ecn(), 0b01);
778
779        // DSCP: 0b110011 (51), ECN: 0b10 (2)
780        // Ensure other parts of vcf[0] and vcf[1] are not clobbered unnecessarily
781        // by setting version and flow label first
782        hdr.set_version(6);
783        hdr.set_flow_label(0xFFFFF); // Max flow label
784        hdr.set_dscp_ecn(0b110011, 0b10);
785        assert_eq!(hdr.version(), 6); // Check version is maintained
786        assert_eq!(hdr.dscp(), 0b110011);
787        assert_eq!(hdr.ecn(), 0b10);
788        assert_eq!(hdr.flow_label(), 0xFFFFF); // Check flow label is maintained
789    }
790
791    #[test]
792    fn test_ipv6_flow_label() {
793        let mut hdr = default_ipv6_hdr();
794        hdr.set_flow_label(0x12345); // 20-bit value
795        assert_eq!(hdr.flow_label(), 0x12345);
796
797        // Ensure other parts of vcf[1] are not clobbered
798        // by setting dscp and ecn first
799        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; // 15
813        let ecn = 0b11; // 3
814        let flow_label = 0xFEDCB; // 20-bit
815
816        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); // Check a field to ensure it's the same
855        } 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); // Check a field
863        } else {
864            panic!("Expected IpHdr::V6");
865        }
866    }
867}