1use super::address::Ipv4Address;
2use super::packet::{HEADER_LENGTH, Ipv4PacketMut};
3use super::protocol::Ipv4Protocol;
4use crate::internet_checksum;
5use core::fmt;
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum Ipv4PacketBuildError {
9 MissingSource,
11 MissingDestination,
13 MissingProtocol,
15 MissingTtl,
17 InvalidOptionsLength,
19 TotalLengthTooLarge,
21 ReservedFlagSet,
23 BufferTooShort {
25 required: usize,
27 available: usize,
29 },
30}
31impl fmt::Display for Ipv4PacketBuildError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 Self::MissingSource => f.write_str("missing IPv4 source address"),
35 Self::MissingDestination => f.write_str("missing IPv4 destination address"),
36 Self::MissingProtocol => f.write_str("missing IPv4 protocol"),
37 Self::MissingTtl => f.write_str("missing IPv4 TTL"),
38 Self::InvalidOptionsLength => {
39 f.write_str("IPv4 options length must be a multiple of four and at most 40")
40 }
41 Self::TotalLengthTooLarge => f.write_str("IPv4 total length exceeds 65535"),
42 Self::ReservedFlagSet => f.write_str("IPv4 reserved flag bit is set"),
43 Self::BufferTooShort {
44 required,
45 available,
46 } => write!(
47 f,
48 "IPv4 buffer is too short: need {required} bytes, have {available}"
49 ),
50 }
51 }
52}
53pub struct Ipv4PacketBuilder<'buffer, 'input> {
55 buffer: &'buffer mut [u8],
56 payload: usize,
57 source: Option<Ipv4Address>,
58 destination: Option<Ipv4Address>,
59 protocol: Option<Ipv4Protocol>,
60 ttl: Option<u8>,
61 identification: u16,
62 flags: u16,
63 dscp: u8,
64 options: &'input [u8],
65}
66impl<'buffer, 'input> Ipv4PacketBuilder<'buffer, 'input> {
67 #[inline]
69 pub fn new(buffer: &'buffer mut [u8], payload: usize) -> Self {
70 Self {
71 buffer,
72 payload,
73 source: None,
74 destination: None,
75 protocol: None,
76 ttl: None,
77 identification: 0,
78 flags: 0,
79 dscp: 0,
80 options: &[],
81 }
82 }
83 #[inline]
85 pub fn source(mut self, v: Ipv4Address) -> Self {
86 self.source = Some(v);
87 self
88 }
89 #[inline]
91 pub fn destination(mut self, v: Ipv4Address) -> Self {
92 self.destination = Some(v);
93 self
94 }
95 #[inline]
97 pub fn protocol(mut self, v: Ipv4Protocol) -> Self {
98 self.protocol = Some(v);
99 self
100 }
101 #[inline]
103 pub fn ttl(mut self, v: u8) -> Self {
104 self.ttl = Some(v);
105 self
106 }
107 #[inline]
109 pub fn identification(mut self, v: u16) -> Self {
110 self.identification = v;
111 self
112 }
113 #[inline]
115 pub fn flags_fragment_offset(mut self, v: u16) -> Self {
116 self.flags = v;
117 self
118 }
119 #[inline]
121 pub fn dscp_ecn(mut self, v: u8) -> Self {
122 self.dscp = v;
123 self
124 }
125 #[inline]
127 pub fn options(mut self, v: &'input [u8]) -> Self {
128 self.options = v;
129 self
130 }
131 #[inline]
133 pub fn build(self) -> Result<Ipv4PacketMut<'buffer>, Ipv4PacketBuildError> {
134 let source = self.source.ok_or(Ipv4PacketBuildError::MissingSource)?;
135 let destination = self
136 .destination
137 .ok_or(Ipv4PacketBuildError::MissingDestination)?;
138 let protocol = self.protocol.ok_or(Ipv4PacketBuildError::MissingProtocol)?;
139 let ttl = self.ttl.ok_or(Ipv4PacketBuildError::MissingTtl)?;
140 if self.flags & 0x8000 != 0 {
141 return Err(Ipv4PacketBuildError::ReservedFlagSet);
142 }
143 if self.options.len() > 40 || !self.options.len().is_multiple_of(4) {
144 return Err(Ipv4PacketBuildError::InvalidOptionsLength);
145 }
146 let header = HEADER_LENGTH + self.options.len();
147 let total = header
148 .checked_add(self.payload)
149 .ok_or(Ipv4PacketBuildError::TotalLengthTooLarge)?;
150 if total > u16::MAX as usize {
151 return Err(Ipv4PacketBuildError::TotalLengthTooLarge);
152 }
153 if self.buffer.len() < total {
154 return Err(Ipv4PacketBuildError::BufferTooShort {
155 required: total,
156 available: self.buffer.len(),
157 });
158 }
159 let b = &mut self.buffer[..total];
160 b[0] = 0x40 | ((header / 4) as u8);
161 b[1] = self.dscp;
162 b[2..4].copy_from_slice(&(total as u16).to_be_bytes());
163 b[4..6].copy_from_slice(&self.identification.to_be_bytes());
164 b[6..8].copy_from_slice(&self.flags.to_be_bytes());
165 b[8] = ttl;
166 b[9] = protocol.raw();
167 b[10] = 0;
168 b[11] = 0;
169 b[12..16].copy_from_slice(&source.octets());
170 b[16..20].copy_from_slice(&destination.octets());
171 b[HEADER_LENGTH..header].copy_from_slice(self.options);
172 let checksum = !internet_checksum::sum(&b[..header]);
173 b[10..12].copy_from_slice(&checksum.to_be_bytes());
174 Ok(Ipv4PacketMut::from_validated(b, header))
175 }
176}