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