network_types/
ip.rs

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