1 use super::{Error, Result}; 2 use core::fmt; 3 4 use byteorder::{ByteOrder, NetworkEndian}; 5 6 pub use super::IpProtocol as Protocol; 7 8 /// A read/write wrapper around an IPv6 Fragment Header. 9 #[derive(Debug, PartialEq, Eq)] 10 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 11 pub struct Header<T: AsRef<[u8]>> { 12 buffer: T, 13 } 14 15 // Format of the Fragment Header 16 // 17 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 18 // | Next Header | Reserved | Fragment Offset |Res|M| 19 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 20 // | Identification | 21 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 22 // 23 // See https://tools.ietf.org/html/rfc8200#section-4.5 for details. 24 mod field { 25 use crate::wire::field::*; 26 27 // 8-bit identifier of the header immediately following this header. 28 pub const NXT_HDR: usize = 0; 29 // 8-bit reserved field. 30 pub const RESERVED: usize = 1; 31 // 16-bit field containing the fragment offset, reserved and more fragments values. 32 pub const FR_OF_M: Field = 2..4; 33 // 32-bit field identifying the fragmented packet 34 pub const IDENT: Field = 4..8; 35 } 36 37 impl<T: AsRef<[u8]>> Header<T> { 38 /// Create a raw octet buffer with an IPv6 Fragment Header structure. new_unchecked(buffer: T) -> Header<T>39 pub const fn new_unchecked(buffer: T) -> Header<T> { 40 Header { buffer } 41 } 42 43 /// Shorthand for a combination of [new_unchecked] and [check_len]. 44 /// 45 /// [new_unchecked]: #method.new_unchecked 46 /// [check_len]: #method.check_len new_checked(buffer: T) -> Result<Header<T>>47 pub fn new_checked(buffer: T) -> Result<Header<T>> { 48 let header = Self::new_unchecked(buffer); 49 header.check_len()?; 50 Ok(header) 51 } 52 53 /// Ensure that no accessor method will panic if called. 54 /// Returns `Err(Error)` if the buffer is too short. check_len(&self) -> Result<()>55 pub fn check_len(&self) -> Result<()> { 56 let data = self.buffer.as_ref(); 57 let len = data.len(); 58 59 if len < field::IDENT.end { 60 Err(Error) 61 } else { 62 Ok(()) 63 } 64 } 65 66 /// Consume the header, returning the underlying buffer. into_inner(self) -> T67 pub fn into_inner(self) -> T { 68 self.buffer 69 } 70 71 /// Return the next header field. 72 #[inline] next_header(&self) -> Protocol73 pub fn next_header(&self) -> Protocol { 74 let data = self.buffer.as_ref(); 75 Protocol::from(data[field::NXT_HDR]) 76 } 77 78 /// Return the fragment offset field. 79 #[inline] frag_offset(&self) -> u1680 pub fn frag_offset(&self) -> u16 { 81 let data = self.buffer.as_ref(); 82 NetworkEndian::read_u16(&data[field::FR_OF_M]) >> 3 83 } 84 85 /// Return more fragment flag field. 86 #[inline] more_frags(&self) -> bool87 pub fn more_frags(&self) -> bool { 88 let data = self.buffer.as_ref(); 89 (data[3] & 0x1) == 1 90 } 91 92 /// Return the fragment identification value field. 93 #[inline] ident(&self) -> u3294 pub fn ident(&self) -> u32 { 95 let data = self.buffer.as_ref(); 96 NetworkEndian::read_u32(&data[field::IDENT]) 97 } 98 } 99 100 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> { 101 /// Set the next header field. 102 #[inline] set_next_header(&mut self, value: Protocol)103 pub fn set_next_header(&mut self, value: Protocol) { 104 let data = self.buffer.as_mut(); 105 data[field::NXT_HDR] = value.into(); 106 } 107 108 /// Set reserved fields. 109 /// 110 /// Set 8-bit reserved field after the next header field. 111 /// Set 2-bit reserved field between fragment offset and more fragments. 112 #[inline] clear_reserved(&mut self)113 pub fn clear_reserved(&mut self) { 114 let data = self.buffer.as_mut(); 115 116 data[field::RESERVED] = 0; 117 118 // Retain the higher order 5 bits and lower order 1 bit 119 data[3] &= 0xf9; 120 } 121 122 /// Set the fragment offset field. 123 #[inline] set_frag_offset(&mut self, value: u16)124 pub fn set_frag_offset(&mut self, value: u16) { 125 let data = self.buffer.as_mut(); 126 // Retain the lower order 3 bits 127 let raw = ((value & 0x1fff) << 3) | ((data[3] & 0x7) as u16); 128 NetworkEndian::write_u16(&mut data[field::FR_OF_M], raw); 129 } 130 131 /// Set the more fragments flag field. 132 #[inline] set_more_frags(&mut self, value: bool)133 pub fn set_more_frags(&mut self, value: bool) { 134 let data = self.buffer.as_mut(); 135 // Retain the high order 7 bits 136 let raw = (data[3] & 0xfe) | (value as u8 & 0x1); 137 data[3] = raw; 138 } 139 140 /// Set the fragmentation identification field. 141 #[inline] set_ident(&mut self, value: u32)142 pub fn set_ident(&mut self, value: u32) { 143 let data = self.buffer.as_mut(); 144 NetworkEndian::write_u32(&mut data[field::IDENT], value); 145 } 146 } 147 148 impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result149 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 150 match Repr::parse(self) { 151 Ok(repr) => write!(f, "{repr}"), 152 Err(err) => { 153 write!(f, "IPv6 Fragment ({err})")?; 154 Ok(()) 155 } 156 } 157 } 158 } 159 160 /// A high-level representation of an IPv6 Fragment header. 161 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 162 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 163 pub struct Repr { 164 /// The type of header immediately following the Fragment header. 165 pub next_header: Protocol, 166 /// The offset of the data following this header, relative to the start of the Fragmentable 167 /// Part of the original packet. 168 pub frag_offset: u16, 169 /// When there are more fragments following this header 170 pub more_frags: bool, 171 /// The identification for every packet that is fragmented. 172 pub ident: u32, 173 } 174 175 impl Repr { 176 /// Parse an IPv6 Fragment Header and return a high-level representation. parse<T>(header: &Header<&T>) -> Result<Repr> where T: AsRef<[u8]> + ?Sized,177 pub fn parse<T>(header: &Header<&T>) -> Result<Repr> 178 where 179 T: AsRef<[u8]> + ?Sized, 180 { 181 Ok(Repr { 182 next_header: header.next_header(), 183 frag_offset: header.frag_offset(), 184 more_frags: header.more_frags(), 185 ident: header.ident(), 186 }) 187 } 188 189 /// Return the length, in bytes, of a header that will be emitted from this high-level 190 /// representation. buffer_len(&self) -> usize191 pub const fn buffer_len(&self) -> usize { 192 field::IDENT.end 193 } 194 195 /// Emit a high-level representation into an IPv6 Fragment Header. emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>)196 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) { 197 header.set_next_header(self.next_header); 198 header.clear_reserved(); 199 header.set_frag_offset(self.frag_offset); 200 header.set_more_frags(self.more_frags); 201 header.set_ident(self.ident); 202 } 203 } 204 205 impl fmt::Display for Repr { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 207 write!( 208 f, 209 "IPv6 Fragment next_hdr={} offset={} more={} ident={}", 210 self.next_header, self.frag_offset, self.more_frags, self.ident 211 ) 212 } 213 } 214 215 #[cfg(test)] 216 mod test { 217 use super::*; 218 219 // A Fragment Header with more fragments remaining 220 static BYTES_HEADER_MORE_FRAG: [u8; 8] = [0x6, 0x0, 0x0, 0x1, 0x0, 0x0, 0x30, 0x39]; 221 222 // A Fragment Header with no more fragments remaining 223 static BYTES_HEADER_LAST_FRAG: [u8; 8] = [0x6, 0x0, 0xa, 0x0, 0x0, 0x1, 0x9, 0x32]; 224 225 #[test] test_check_len()226 fn test_check_len() { 227 // less than 8 bytes 228 assert_eq!( 229 Err(Error), 230 Header::new_unchecked(&BYTES_HEADER_MORE_FRAG[..7]).check_len() 231 ); 232 // valid 233 assert_eq!( 234 Ok(()), 235 Header::new_unchecked(&BYTES_HEADER_MORE_FRAG).check_len() 236 ); 237 } 238 239 #[test] test_header_deconstruct()240 fn test_header_deconstruct() { 241 let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG); 242 assert_eq!(header.next_header(), Protocol::Tcp); 243 assert_eq!(header.frag_offset(), 0); 244 assert!(header.more_frags()); 245 assert_eq!(header.ident(), 12345); 246 247 let header = Header::new_unchecked(&BYTES_HEADER_LAST_FRAG); 248 assert_eq!(header.next_header(), Protocol::Tcp); 249 assert_eq!(header.frag_offset(), 320); 250 assert!(!header.more_frags()); 251 assert_eq!(header.ident(), 67890); 252 } 253 254 #[test] test_repr_parse_valid()255 fn test_repr_parse_valid() { 256 let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG); 257 let repr = Repr::parse(&header).unwrap(); 258 assert_eq!( 259 repr, 260 Repr { 261 next_header: Protocol::Tcp, 262 frag_offset: 0, 263 more_frags: true, 264 ident: 12345 265 } 266 ); 267 268 let header = Header::new_unchecked(&BYTES_HEADER_LAST_FRAG); 269 let repr = Repr::parse(&header).unwrap(); 270 assert_eq!( 271 repr, 272 Repr { 273 next_header: Protocol::Tcp, 274 frag_offset: 320, 275 more_frags: false, 276 ident: 67890 277 } 278 ); 279 } 280 281 #[test] test_repr_emit()282 fn test_repr_emit() { 283 let repr = Repr { 284 next_header: Protocol::Tcp, 285 frag_offset: 0, 286 more_frags: true, 287 ident: 12345, 288 }; 289 let mut bytes = [0u8; 8]; 290 let mut header = Header::new_unchecked(&mut bytes); 291 repr.emit(&mut header); 292 assert_eq!(header.into_inner(), &BYTES_HEADER_MORE_FRAG[0..8]); 293 294 let repr = Repr { 295 next_header: Protocol::Tcp, 296 frag_offset: 320, 297 more_frags: false, 298 ident: 67890, 299 }; 300 let mut bytes = [0u8; 8]; 301 let mut header = Header::new_unchecked(&mut bytes); 302 repr.emit(&mut header); 303 assert_eq!(header.into_inner(), &BYTES_HEADER_LAST_FRAG[0..8]); 304 } 305 306 #[test] test_buffer_len()307 fn test_buffer_len() { 308 let header = Header::new_unchecked(&BYTES_HEADER_MORE_FRAG); 309 let repr = Repr::parse(&header).unwrap(); 310 assert_eq!(repr.buffer_len(), BYTES_HEADER_MORE_FRAG.len()); 311 } 312 } 313