Skip to main content

iris_core/protocols/packet/
ipv6.rs

1//! IPv6 packet.
2
3use crate::memory::mbuf::Mbuf;
4use crate::protocols::packet::{Packet, PacketHeader, PacketParseError};
5use crate::utils::types::*;
6
7use std::net::Ipv6Addr;
8
9const IPV6_PROTOCOL: usize = 0x86DD;
10const IPV6_HEADER_LEN: usize = 40;
11
12/// An IPv6 packet.
13///
14/// Optional IPv6 extension headers are not parsed by default.
15#[derive(Debug)]
16pub struct Ipv6<'a> {
17    /// Fixed header.
18    header: Ipv6Header,
19    /// Offset to `header` from the start of `mbuf`.
20    offset: usize,
21    /// Packet buffer.
22    mbuf: &'a Mbuf,
23}
24
25impl Ipv6<'_> {
26    /// Returns the IP protocol version.
27    #[inline]
28    pub fn version(&self) -> u8 {
29        let v: u32 = (self.header.version_to_flow_label & u32be::from(0xf000_0000)).into();
30        (v >> 28) as u8
31    }
32
33    /// Returns the differentiated services code point (DSCP).
34    #[inline]
35    pub fn dscp(&self) -> u8 {
36        let v: u32 = (self.header.version_to_flow_label & u32be::from(0x0fc0_0000)).into();
37        (v >> 22) as u8
38    }
39
40    /// Returns the explicit congestion notification (ECN).
41    #[inline]
42    pub fn ecn(&self) -> u8 {
43        let v: u32 = (self.header.version_to_flow_label & u32be::from(0x0030_0000)).into();
44        (v >> 20) as u8
45    }
46
47    /// Returns the traffic class (former name of differentiated services field).
48    #[inline]
49    pub fn traffic_class(&self) -> u8 {
50        let v: u32 = (self.header.version_to_flow_label & u32be::from(0x0ff0_0000)).into();
51        (v >> 20) as u8
52    }
53
54    /// Returns the flow label.
55    #[inline]
56    pub fn flow_label(&self) -> u32 {
57        (self.header.version_to_flow_label & u32be::from(0x000f_ffff)).into()
58    }
59
60    /// Returns the 32-bit field containing the version, traffic class, and flow label.
61    #[inline]
62    pub fn version_to_flow_label(&self) -> u32 {
63        self.header.version_to_flow_label.into()
64    }
65
66    /// Returns the length of the payload in bytes.
67    #[inline]
68    pub fn payload_length(&self) -> u16 {
69        self.header.payload_length.into()
70    }
71
72    /// Returns the encapsulated protocol identifier.
73    #[inline]
74    pub fn next_header(&self) -> u8 {
75        self.header.next_header
76    }
77
78    /// Returns hop limit/time to live of the packet.
79    #[inline]
80    pub fn hop_limit(&self) -> u8 {
81        self.header.hop_limit
82    }
83
84    /// Returns the sender's IPv6 address.
85    #[inline]
86    pub fn src_addr(&self) -> Ipv6Addr {
87        self.header.src_addr
88    }
89
90    /// Returns the receiver's IPv6 address.
91    #[inline]
92    pub fn dst_addr(&self) -> Ipv6Addr {
93        self.header.dst_addr
94    }
95}
96
97impl<'a> Packet<'a> for Ipv6<'a> {
98    fn mbuf(&self) -> &Mbuf {
99        self.mbuf
100    }
101
102    fn header_len(&self) -> usize {
103        self.header.length()
104    }
105
106    fn next_header_offset(&self) -> usize {
107        self.offset + self.header_len()
108    }
109
110    fn next_header(&self) -> Option<usize> {
111        Some(self.next_header().into())
112    }
113
114    fn parse_from(outer: &'a impl Packet<'a>) -> Result<Self, PacketParseError>
115    where
116        Self: Sized,
117    {
118        let offset = outer.next_header_offset();
119        if let Ok(header) = outer.mbuf().get_data(offset) {
120            match outer.next_header() {
121                Some(IPV6_PROTOCOL) => Ok(Ipv6 {
122                    header: unsafe { *header },
123                    offset,
124                    mbuf: outer.mbuf(),
125                }),
126                _ => Err(PacketParseError::InvalidProtocol),
127            }
128        } else {
129            Err(PacketParseError::InvalidRead)
130        }
131    }
132}
133
134// Fixed portion of Ipv6 header NICE-TO-HAVE: handle extension headers
135#[derive(Debug, Clone, Copy)]
136#[repr(C)]
137struct Ipv6Header {
138    version_to_flow_label: u32be,
139    payload_length: u16be,
140    next_header: u8,
141    hop_limit: u8,
142    src_addr: Ipv6Addr,
143    dst_addr: Ipv6Addr,
144}
145
146impl PacketHeader for Ipv6Header {
147    /// Payload offset
148    fn length(&self) -> usize {
149        IPV6_HEADER_LEN
150    }
151}