1use core::fmt;
2
3use super::address::Ipv6Address;
4use super::next_header::Ipv6NextHeader;
5use super::packet::{HEADER_LENGTH, Ipv6PacketMut};
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub enum Ipv6PacketBuildError {
10 MissingNextHeader,
12 MissingHopLimit,
14 MissingSource,
16 MissingDestination,
18 FlowLabelTooLarge,
20 PayloadLengthTooLarge,
22 BufferTooShort {
24 required: usize,
26 available: usize,
28 },
29}
30
31impl fmt::Display for Ipv6PacketBuildError {
32 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 Self::MissingNextHeader => formatter.write_str("missing IPv6 Next Header value"),
35 Self::MissingHopLimit => formatter.write_str("missing IPv6 hop limit"),
36 Self::MissingSource => formatter.write_str("missing IPv6 source address"),
37 Self::MissingDestination => formatter.write_str("missing IPv6 destination address"),
38 Self::FlowLabelTooLarge => formatter.write_str("IPv6 flow label exceeds 20 bits"),
39 Self::PayloadLengthTooLarge => {
40 formatter.write_str("IPv6 payload length exceeds 65535 octets")
41 }
42 Self::BufferTooShort {
43 required,
44 available,
45 } => write!(
46 formatter,
47 "IPv6 buffer is too short: need {required} bytes, have {available}"
48 ),
49 }
50 }
51}
52
53pub struct Ipv6PacketBuilder<'buffer> {
58 buffer: &'buffer mut [u8],
59 payload_length: usize,
60 next_header: Option<Ipv6NextHeader>,
61 hop_limit: Option<u8>,
62 source: Option<Ipv6Address>,
63 destination: Option<Ipv6Address>,
64 traffic_class: u8,
65 flow_label: u32,
66}
67
68impl<'buffer> Ipv6PacketBuilder<'buffer> {
69 #[inline]
73 pub fn new(buffer: &'buffer mut [u8], payload_length: usize) -> Self {
74 Self {
75 buffer,
76 payload_length,
77 next_header: None,
78 hop_limit: None,
79 source: None,
80 destination: None,
81 traffic_class: 0,
82 flow_label: 0,
83 }
84 }
85
86 #[inline]
88 pub fn next_header(mut self, value: Ipv6NextHeader) -> Self {
89 self.next_header = Some(value);
90 self
91 }
92
93 #[inline]
95 pub fn hop_limit(mut self, value: u8) -> Self {
96 self.hop_limit = Some(value);
97 self
98 }
99
100 #[inline]
102 pub fn source(mut self, value: Ipv6Address) -> Self {
103 self.source = Some(value);
104 self
105 }
106
107 #[inline]
109 pub fn destination(mut self, value: Ipv6Address) -> Self {
110 self.destination = Some(value);
111 self
112 }
113
114 #[inline]
116 pub fn traffic_class(mut self, value: u8) -> Self {
117 self.traffic_class = value;
118 self
119 }
120
121 #[inline]
123 pub fn flow_label(mut self, value: u32) -> Self {
124 self.flow_label = value;
125 self
126 }
127
128 #[inline]
130 pub fn build(self) -> Result<Ipv6PacketMut<'buffer>, Ipv6PacketBuildError> {
131 let next_header = self
132 .next_header
133 .ok_or(Ipv6PacketBuildError::MissingNextHeader)?;
134 let hop_limit = self
135 .hop_limit
136 .ok_or(Ipv6PacketBuildError::MissingHopLimit)?;
137 let source = self.source.ok_or(Ipv6PacketBuildError::MissingSource)?;
138 let destination = self
139 .destination
140 .ok_or(Ipv6PacketBuildError::MissingDestination)?;
141 if self.flow_label > 0x000f_ffff {
142 return Err(Ipv6PacketBuildError::FlowLabelTooLarge);
143 }
144 if self.payload_length > u16::MAX as usize {
145 return Err(Ipv6PacketBuildError::PayloadLengthTooLarge);
146 }
147 let packet_length = HEADER_LENGTH + self.payload_length;
148 if self.buffer.len() < packet_length {
149 return Err(Ipv6PacketBuildError::BufferTooShort {
150 required: packet_length,
151 available: self.buffer.len(),
152 });
153 }
154
155 let bytes = &mut self.buffer[..packet_length];
156 bytes[0] = 0x60 | (self.traffic_class >> 4);
157 bytes[1] = (self.traffic_class << 4) | ((self.flow_label >> 16) as u8);
158 bytes[2] = (self.flow_label >> 8) as u8;
159 bytes[3] = self.flow_label as u8;
160 bytes[4..6].copy_from_slice(&(self.payload_length as u16).to_be_bytes());
161 bytes[6] = next_header.raw();
162 bytes[7] = hop_limit;
163 bytes[8..24].copy_from_slice(&source.octets());
164 bytes[24..40].copy_from_slice(&destination.octets());
165
166 Ok(Ipv6PacketMut::from_validated(bytes))
167 }
168}