catnip/
ip.rs

1//! Internet layer: Internet Protocol message header construction
2
3use crate::{IpV4Addr, Protocol, DSCP};
4
5use byte_struct::*;
6use modular_bitfield::prelude::*;
7use static_assertions::const_assert;
8use ufmt::derive::uDebug;
9
10const_assert!(IpV4Header::BYTE_LEN == 20);
11
12/// IPV4 header per IETF-RFC-791.
13/// See <https://en.wikipedia.org/wiki/IPv4>.
14#[derive(ByteStruct, Clone, Copy, uDebug, Debug, PartialEq, Eq)]
15#[byte_struct_be]
16pub struct IpV4Header {
17    /// Combined version and header length info in a single byte
18    pub version_and_header_length: VersionAndHeaderLength,
19    /// Type of Service / Differentiated-Service
20    pub dscp: DSCP,
21    /// Total length including header and data
22    pub total_length: u16,
23    /// Mostly-legacy id field
24    pub identification: u16,
25    /// Mostly-legacy packet fragmentation info
26    pub fragmentation: Fragmentation,
27    /// TTL counter
28    pub time_to_live: u8,
29    /// Transport-layer protocol
30    pub protocol: Protocol,
31    /// CRC checksum
32    pub checksum: u16,
33    /// Source IP address
34    pub src_ipaddr: IpV4Addr,
35    /// Destination IP address
36    pub dst_ipaddr: IpV4Addr,
37}
38
39impl IpV4Header {
40    /// Pack into big-endian (network) byte array
41    pub fn to_be_bytes(&self) -> [u8; Self::BYTE_LEN] {
42        let mut bytes = [0_u8; Self::BYTE_LEN];
43        self.write_bytes(&mut bytes);
44        bytes
45    }
46}
47
48/// IPV4 frame with header and data.
49/// Data should be sized in a multiple of 4 bytes.
50#[derive(Clone, Copy, uDebug, Debug, PartialEq, Eq)]
51pub struct IpV4Frame<T>
52where
53    T: ByteStruct,
54{
55    /// IP header
56    pub header: IpV4Header,
57    /// Data such as a UDP header; should be some multiple of 4 bytes (32-bit words)
58    pub data: T,
59}
60
61impl<T> ByteStructLen for IpV4Frame<T>
62where
63    T: ByteStruct,
64{
65    const BYTE_LEN: usize = IpV4Header::BYTE_LEN + T::BYTE_LEN;
66}
67
68impl<T> ByteStruct for IpV4Frame<T>
69where
70    T: ByteStruct,
71{
72    fn read_bytes(bytes: &[u8]) -> Self {
73        IpV4Frame::<T> {
74            header: IpV4Header::read_bytes(&bytes[0..IpV4Header::BYTE_LEN]),
75            data: T::read_bytes(&bytes[IpV4Header::BYTE_LEN..]),
76        }
77    }
78
79    fn write_bytes(&self, bytes: &mut [u8]) {
80        self.header.write_bytes(&mut bytes[0..IpV4Header::BYTE_LEN]);
81        self.data.write_bytes(&mut bytes[IpV4Header::BYTE_LEN..]);
82    }
83}
84
85impl<T> IpV4Frame<T>
86where
87    T: ByteStruct,
88{
89    /// Pack into big-endian (network) byte array
90    pub fn to_be_bytes(&self) -> [u8; Self::BYTE_LEN] {
91        let mut bytes = [0_u8; Self::BYTE_LEN];
92        self.write_bytes(&mut bytes);
93        bytes
94    }
95}
96
97/// Fragmentation flags and offset info
98#[bitfield(bits = 16)]
99#[derive(Clone, Copy, uDebug, Debug, Default, PartialEq, Eq)]
100pub struct Fragmentation {
101    unused: B1,
102    /// Flag for routers to drop packets instead of fragmenting
103    pub do_not_fragment: B1,
104    /// Flag that there are more fragments coming
105    pub more_fragments: B1,
106    /// Where we are in a set of fragments
107    pub offset: B13,
108}
109
110impl ByteStructLen for Fragmentation {
111    const BYTE_LEN: usize = 2;
112}
113
114impl ByteStruct for Fragmentation {
115    fn read_bytes(bytes: &[u8]) -> Self {
116        // All bit patterns are valid, so this will never error
117        let mut bytes_to_read = [0_u8; Fragmentation::BYTE_LEN];
118        bytes_to_read.copy_from_slice(&bytes[0..=1]);
119        Fragmentation::from_bytes(bytes_to_read)
120    }
121
122    fn write_bytes(&self, bytes: &mut [u8]) {
123        let bytes_to_write = self.into_bytes();
124        bytes[0] = bytes_to_write[0];
125        bytes[1] = bytes_to_write[1];
126    }
127}
128
129/// Combined IP version and header length in a single byte.
130#[bitfield(bits = 8)]
131#[derive(Clone, Copy, uDebug, Debug, Default, PartialEq, Eq)]
132pub struct VersionAndHeaderLength {
133    /// Length of IP header in 32-bit words (usually 5 words, or 20 bytes)
134    pub header_length: B4,
135    /// IP version number
136    pub version: B4,
137}
138
139impl ByteStructLen for VersionAndHeaderLength {
140    const BYTE_LEN: usize = 1;
141}
142
143impl ByteStruct for VersionAndHeaderLength {
144    fn read_bytes(bytes: &[u8]) -> Self {
145        // All bit patterns are valid, so this will never error
146        VersionAndHeaderLength::from_bytes([bytes[0]])
147    }
148
149    fn write_bytes(&self, bytes: &mut [u8]) {
150        bytes[0] = self.into_bytes()[0];
151    }
152}