1 use super::{Error, Result}; 2 use core::fmt; 3 4 use crate::wire::IpProtocol as Protocol; 5 use crate::wire::Ipv6Address as Address; 6 7 enum_with_unknown! { 8 /// IPv6 Extension Routing Header Routing Type 9 pub enum Type(u8) { 10 /// Source Route (DEPRECATED) 11 /// 12 /// See https://tools.ietf.org/html/rfc5095 for details. 13 Type0 = 0, 14 /// Nimrod (DEPRECATED 2009-05-06) 15 Nimrod = 1, 16 /// Type 2 Routing Header for Mobile IPv6 17 /// 18 /// See https://tools.ietf.org/html/rfc6275#section-6.4 for details. 19 Type2 = 2, 20 /// RPL Source Routing Header 21 /// 22 /// See https://tools.ietf.org/html/rfc6554 for details. 23 Rpl = 3, 24 /// RFC3692-style Experiment 1 25 /// 26 /// See https://tools.ietf.org/html/rfc4727 for details. 27 Experiment1 = 253, 28 /// RFC3692-style Experiment 2 29 /// 30 /// See https://tools.ietf.org/html/rfc4727 for details. 31 Experiment2 = 254, 32 /// Reserved for future use 33 Reserved = 252 34 } 35 } 36 37 impl fmt::Display for Type { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 39 match *self { 40 Type::Type0 => write!(f, "Type0"), 41 Type::Nimrod => write!(f, "Nimrod"), 42 Type::Type2 => write!(f, "Type2"), 43 Type::Rpl => write!(f, "Rpl"), 44 Type::Experiment1 => write!(f, "Experiment1"), 45 Type::Experiment2 => write!(f, "Experiment2"), 46 Type::Reserved => write!(f, "Reserved"), 47 Type::Unknown(id) => write!(f, "{id}"), 48 } 49 } 50 } 51 52 /// A read/write wrapper around an IPv6 Routing Header buffer. 53 #[derive(Debug, PartialEq, Eq)] 54 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 55 pub struct Header<T: AsRef<[u8]>> { 56 buffer: T, 57 } 58 59 // Format of the Routing Header 60 // 61 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 62 // | Next Header | Hdr Ext Len | Routing Type | Segments Left | 63 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 64 // | | 65 // . . 66 // . type-specific data . 67 // . . 68 // | | 69 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 70 // 71 // 72 // See https://tools.ietf.org/html/rfc8200#section-4.4 for details. 73 mod field { 74 #![allow(non_snake_case)] 75 76 use crate::wire::field::*; 77 78 // Minimum size of the header. 79 pub const MIN_HEADER_SIZE: usize = 4; 80 81 // 8-bit identifier of the header immediately following this header. 82 pub const NXT_HDR: usize = 0; 83 // 8-bit unsigned integer. Length of the DATA field in 8-octet units, 84 // not including the first 8 octets. 85 pub const LENGTH: usize = 1; 86 // 8-bit identifier of a particular Routing header variant. 87 pub const TYPE: usize = 2; 88 // 8-bit unsigned integer. The number of route segments remaining. 89 pub const SEG_LEFT: usize = 3; 90 // Variable-length field. Routing-Type-specific data. 91 // 92 // Length of the header is in 8-octet units, not including the first 8 octets. The first four 93 // octets are the next header type, the header length, routing type and segments left. DATA(length_field: u8) -> Field94 pub const fn DATA(length_field: u8) -> Field { 95 let bytes = length_field as usize * 8 + 8; 96 4..bytes 97 } 98 99 // The Type 2 Routing Header has the following format: 100 // 101 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 102 // | Next Header | Hdr Ext Len=2 | Routing Type=2|Segments Left=1| 103 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 104 // | Reserved | 105 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 106 // | | 107 // + + 108 // | | 109 // + Home Address + 110 // | | 111 // + + 112 // | | 113 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 114 115 // 16-byte field containing the home address of the destination mobile node. 116 pub const HOME_ADDRESS: Field = 8..24; 117 118 // The RPL Source Routing Header has the following format: 119 // 120 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 121 // | Next Header | Hdr Ext Len | Routing Type | Segments Left | 122 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 123 // | CmprI | CmprE | Pad | Reserved | 124 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 125 // | | 126 // . . 127 // . Addresses[1..n] . 128 // . . 129 // | | 130 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 131 132 // 8-bit field containing the CmprI and CmprE values. 133 pub const CMPR: usize = 4; 134 // 8-bit field containing the Pad value. 135 pub const PAD: usize = 5; 136 // Variable length field containing addresses ADDRESSES(length_field: u8) -> Field137 pub const fn ADDRESSES(length_field: u8) -> Field { 138 let data = DATA(length_field); 139 8..data.end 140 } 141 } 142 143 /// Core getter methods relevant to any routing type. 144 impl<T: AsRef<[u8]>> Header<T> { 145 /// Create a raw octet buffer with an IPv6 Routing Header structure. new(buffer: T) -> Header<T>146 pub const fn new(buffer: T) -> Header<T> { 147 Header { buffer } 148 } 149 150 /// Shorthand for a combination of [new_unchecked] and [check_len]. 151 /// 152 /// [new_unchecked]: #method.new_unchecked 153 /// [check_len]: #method.check_len new_checked(buffer: T) -> Result<Header<T>>154 pub fn new_checked(buffer: T) -> Result<Header<T>> { 155 let header = Self::new(buffer); 156 header.check_len()?; 157 Ok(header) 158 } 159 160 /// Ensure that no accessor method will panic if called. 161 /// Returns `Err(Error)` if the buffer is too short. 162 /// 163 /// The result of this check is invalidated by calling [set_header_len]. 164 /// 165 /// [set_header_len]: #method.set_header_len check_len(&self) -> Result<()>166 pub fn check_len(&self) -> Result<()> { 167 let len = self.buffer.as_ref().len(); 168 if len < field::MIN_HEADER_SIZE { 169 return Err(Error); 170 } 171 172 if len < field::DATA(self.header_len()).end { 173 return Err(Error); 174 } 175 176 // The header lenght field could be wrong and thus we need to check this as well: 177 if matches!(self.routing_type(), Type::Type2) 178 && field::DATA(self.header_len()).end != field::HOME_ADDRESS.end 179 { 180 return Err(Error); 181 } 182 183 Ok(()) 184 } 185 186 /// Consume the header, returning the underlying buffer. into_inner(self) -> T187 pub fn into_inner(self) -> T { 188 self.buffer 189 } 190 191 /// Return the next header field. 192 #[inline] next_header(&self) -> Protocol193 pub fn next_header(&self) -> Protocol { 194 let data = self.buffer.as_ref(); 195 Protocol::from(data[field::NXT_HDR]) 196 } 197 198 /// Return the header length field. Length of the Routing header in 8-octet units, 199 /// not including the first 8 octets. 200 #[inline] header_len(&self) -> u8201 pub fn header_len(&self) -> u8 { 202 let data = self.buffer.as_ref(); 203 data[field::LENGTH] 204 } 205 206 /// Return the routing type field. 207 #[inline] routing_type(&self) -> Type208 pub fn routing_type(&self) -> Type { 209 let data = self.buffer.as_ref(); 210 Type::from(data[field::TYPE]) 211 } 212 213 /// Return the segments left field. 214 #[inline] segments_left(&self) -> u8215 pub fn segments_left(&self) -> u8 { 216 let data = self.buffer.as_ref(); 217 data[field::SEG_LEFT] 218 } 219 } 220 221 /// Getter methods for the Type 2 Routing Header routing type. 222 impl<T: AsRef<[u8]>> Header<T> { 223 /// Return the IPv6 Home Address 224 /// 225 /// # Panics 226 /// This function may panic if this header is not the Type2 Routing Header routing type. home_address(&self) -> Address227 pub fn home_address(&self) -> Address { 228 let data = self.buffer.as_ref(); 229 Address::from_bytes(&data[field::HOME_ADDRESS]) 230 } 231 } 232 233 /// Getter methods for the RPL Source Routing Header routing type. 234 impl<T: AsRef<[u8]>> Header<T> { 235 /// Return the number of prefix octets elided from addresses[1..n-1]. 236 /// 237 /// # Panics 238 /// This function may panic if this header is not the RPL Source Routing Header routing type. cmpr_i(&self) -> u8239 pub fn cmpr_i(&self) -> u8 { 240 let data = self.buffer.as_ref(); 241 data[field::CMPR] >> 4 242 } 243 244 /// Return the number of prefix octets elided from the last address (`addresses[n]`). 245 /// 246 /// # Panics 247 /// This function may panic if this header is not the RPL Source Routing Header routing type. cmpr_e(&self) -> u8248 pub fn cmpr_e(&self) -> u8 { 249 let data = self.buffer.as_ref(); 250 data[field::CMPR] & 0xf 251 } 252 253 /// Return the number of octets used for padding after `addresses[n]`. 254 /// 255 /// # Panics 256 /// This function may panic if this header is not the RPL Source Routing Header routing type. pad(&self) -> u8257 pub fn pad(&self) -> u8 { 258 let data = self.buffer.as_ref(); 259 data[field::PAD] >> 4 260 } 261 262 /// Return the address vector in bytes 263 /// 264 /// # Panics 265 /// This function may panic if this header is not the RPL Source Routing Header routing type. addresses(&self) -> &[u8]266 pub fn addresses(&self) -> &[u8] { 267 let data = self.buffer.as_ref(); 268 &data[field::ADDRESSES(data[field::LENGTH])] 269 } 270 } 271 272 /// Core setter methods relevant to any routing type. 273 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> { 274 /// Set the next header field. 275 #[inline] set_next_header(&mut self, value: Protocol)276 pub fn set_next_header(&mut self, value: Protocol) { 277 let data = self.buffer.as_mut(); 278 data[field::NXT_HDR] = value.into(); 279 } 280 281 /// Set the option data length. Length of the Routing header in 8-octet units. 282 #[inline] set_header_len(&mut self, value: u8)283 pub fn set_header_len(&mut self, value: u8) { 284 let data = self.buffer.as_mut(); 285 data[field::LENGTH] = value; 286 } 287 288 /// Set the routing type. 289 #[inline] set_routing_type(&mut self, value: Type)290 pub fn set_routing_type(&mut self, value: Type) { 291 let data = self.buffer.as_mut(); 292 data[field::TYPE] = value.into(); 293 } 294 295 /// Set the segments left field. 296 #[inline] set_segments_left(&mut self, value: u8)297 pub fn set_segments_left(&mut self, value: u8) { 298 let data = self.buffer.as_mut(); 299 data[field::SEG_LEFT] = value; 300 } 301 302 /// Initialize reserved fields to 0. 303 /// 304 /// # Panics 305 /// This function may panic if the routing type is not set. 306 #[inline] clear_reserved(&mut self)307 pub fn clear_reserved(&mut self) { 308 let routing_type = self.routing_type(); 309 let data = self.buffer.as_mut(); 310 311 match routing_type { 312 Type::Type2 => { 313 data[4] = 0; 314 data[5] = 0; 315 data[6] = 0; 316 data[7] = 0; 317 } 318 Type::Rpl => { 319 // Retain the higher order 4 bits of the padding field 320 data[field::PAD] &= 0xF0; 321 data[6] = 0; 322 data[7] = 0; 323 } 324 325 _ => panic!("Unrecognized routing type when clearing reserved fields."), 326 } 327 } 328 } 329 330 /// Setter methods for the RPL Source Routing Header routing type. 331 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> { 332 /// Set the Ipv6 Home Address 333 /// 334 /// # Panics 335 /// This function may panic if this header is not the Type 2 Routing Header routing type. set_home_address(&mut self, value: Address)336 pub fn set_home_address(&mut self, value: Address) { 337 let data = self.buffer.as_mut(); 338 data[field::HOME_ADDRESS].copy_from_slice(value.as_bytes()); 339 } 340 } 341 342 /// Setter methods for the RPL Source Routing Header routing type. 343 impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> { 344 /// Set the number of prefix octets elided from addresses[1..n-1]. 345 /// 346 /// # Panics 347 /// This function may panic if this header is not the RPL Source Routing Header routing type. set_cmpr_i(&mut self, value: u8)348 pub fn set_cmpr_i(&mut self, value: u8) { 349 let data = self.buffer.as_mut(); 350 let raw = (value << 4) | (data[field::CMPR] & 0xF); 351 data[field::CMPR] = raw; 352 } 353 354 /// Set the number of prefix octets elided from the last address (`addresses[n]`). 355 /// 356 /// # Panics 357 /// This function may panic if this header is not the RPL Source Routing Header routing type. set_cmpr_e(&mut self, value: u8)358 pub fn set_cmpr_e(&mut self, value: u8) { 359 let data = self.buffer.as_mut(); 360 let raw = (value & 0xF) | (data[field::CMPR] & 0xF0); 361 data[field::CMPR] = raw; 362 } 363 364 /// Set the number of octets used for padding after `addresses[n]`. 365 /// 366 /// # Panics 367 /// This function may panic if this header is not the RPL Source Routing Header routing type. set_pad(&mut self, value: u8)368 pub fn set_pad(&mut self, value: u8) { 369 let data = self.buffer.as_mut(); 370 data[field::PAD] = value << 4; 371 } 372 373 /// Set address data 374 /// 375 /// # Panics 376 /// This function may panic if this header is not the RPL Source Routing Header routing type. set_addresses(&mut self, value: &[u8])377 pub fn set_addresses(&mut self, value: &[u8]) { 378 let data = self.buffer.as_mut(); 379 let len = data[field::LENGTH]; 380 let addresses = &mut data[field::ADDRESSES(len)]; 381 addresses.copy_from_slice(value); 382 } 383 } 384 385 impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result386 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 387 match Repr::parse(self) { 388 Ok(repr) => write!(f, "{repr}"), 389 Err(err) => { 390 write!(f, "IPv6 Routing ({err})")?; 391 Ok(()) 392 } 393 } 394 } 395 } 396 397 /// A high-level representation of an IPv6 Routing Header. 398 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 399 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 400 #[non_exhaustive] 401 pub enum Repr<'a> { 402 Type2 { 403 /// The type of header immediately following the Routing header. 404 next_header: Protocol, 405 /// Length of the Routing header in 8-octet units, not including the first 8 octets. 406 length: u8, 407 /// Number of route segments remaining. 408 segments_left: u8, 409 /// The home address of the destination mobile node. 410 home_address: Address, 411 }, 412 Rpl { 413 /// The type of header immediately following the Routing header. 414 next_header: Protocol, 415 /// Length of the Routing header in 8-octet units, not including the first 8 octets. 416 length: u8, 417 /// Number of route segments remaining. 418 segments_left: u8, 419 /// Number of prefix octets from each segment, except the last segment, that are elided. 420 cmpr_i: u8, 421 /// Number of prefix octets from the last segment that are elided. 422 cmpr_e: u8, 423 /// Number of octets that are used for padding after `address[n]` at the end of the 424 /// RPL Source Route Header. 425 pad: u8, 426 /// Vector of addresses, numbered 1 to `n`. 427 addresses: &'a [u8], 428 }, 429 } 430 431 impl<'a> Repr<'a> { 432 /// Parse an IPv6 Routing Header and return a high-level representation. parse<T>(header: &'a Header<&'a T>) -> Result<Repr<'a>> where T: AsRef<[u8]> + ?Sized,433 pub fn parse<T>(header: &'a Header<&'a T>) -> Result<Repr<'a>> 434 where 435 T: AsRef<[u8]> + ?Sized, 436 { 437 match header.routing_type() { 438 Type::Type2 => Ok(Repr::Type2 { 439 next_header: header.next_header(), 440 length: header.header_len(), 441 segments_left: header.segments_left(), 442 home_address: header.home_address(), 443 }), 444 Type::Rpl => Ok(Repr::Rpl { 445 next_header: header.next_header(), 446 length: header.header_len(), 447 segments_left: header.segments_left(), 448 cmpr_i: header.cmpr_i(), 449 cmpr_e: header.cmpr_e(), 450 pad: header.pad(), 451 addresses: header.addresses(), 452 }), 453 454 _ => Err(Error), 455 } 456 } 457 458 /// Return the length, in bytes, of a header that will be emitted from this high-level 459 /// representation. buffer_len(&self) -> usize460 pub const fn buffer_len(&self) -> usize { 461 match self { 462 &Repr::Rpl { length, .. } | &Repr::Type2 { length, .. } => field::DATA(length).end, 463 } 464 } 465 466 /// Emit a high-level representation into an IPv6 Routing Header. emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>)467 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) { 468 match *self { 469 Repr::Type2 { 470 next_header, 471 length, 472 segments_left, 473 home_address, 474 } => { 475 header.set_next_header(next_header); 476 header.set_header_len(length); 477 header.set_routing_type(Type::Type2); 478 header.set_segments_left(segments_left); 479 header.clear_reserved(); 480 header.set_home_address(home_address); 481 } 482 Repr::Rpl { 483 next_header, 484 length, 485 segments_left, 486 cmpr_i, 487 cmpr_e, 488 pad, 489 addresses, 490 } => { 491 header.set_next_header(next_header); 492 header.set_header_len(length); 493 header.set_routing_type(Type::Rpl); 494 header.set_segments_left(segments_left); 495 header.set_cmpr_i(cmpr_i); 496 header.set_cmpr_e(cmpr_e); 497 header.set_pad(pad); 498 header.clear_reserved(); 499 header.set_addresses(addresses); 500 } 501 } 502 } 503 } 504 505 impl<'a> fmt::Display for Repr<'a> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result506 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 507 match *self { 508 Repr::Type2 { 509 next_header, 510 length, 511 segments_left, 512 home_address, 513 } => { 514 write!( 515 f, 516 "IPv6 Routing next_hdr={} length={} type={} seg_left={} home_address={}", 517 next_header, 518 length, 519 Type::Type2, 520 segments_left, 521 home_address 522 ) 523 } 524 Repr::Rpl { 525 next_header, 526 length, 527 segments_left, 528 cmpr_i, 529 cmpr_e, 530 pad, 531 .. 532 } => { 533 write!(f, "IPv6 Routing next_hdr={} length={} type={} seg_left={} cmpr_i={} cmpr_e={} pad={}", 534 next_header, length, Type::Rpl, segments_left, cmpr_i, cmpr_e, pad) 535 } 536 } 537 } 538 } 539 540 #[cfg(test)] 541 mod test { 542 use super::*; 543 544 // A Type 2 Routing Header 545 static BYTES_TYPE2: [u8; 24] = [ 546 0x6, 0x2, 0x2, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 547 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 548 ]; 549 550 // A representation of a Type 2 Routing header 551 static REPR_TYPE2: Repr = Repr::Type2 { 552 next_header: Protocol::Tcp, 553 length: 2, 554 segments_left: 1, 555 home_address: Address::LOOPBACK, 556 }; 557 558 // A Source Routing Header with full IPv6 addresses in bytes 559 static BYTES_SRH_FULL: [u8; 40] = [ 560 0x6, 0x4, 0x3, 0x2, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 561 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 562 0x0, 0x0, 0x3, 0x1, 563 ]; 564 565 // A representation of a Source Routing Header with full IPv6 addresses 566 static REPR_SRH_FULL: Repr = Repr::Rpl { 567 next_header: Protocol::Tcp, 568 length: 4, 569 segments_left: 2, 570 cmpr_i: 0, 571 cmpr_e: 0, 572 pad: 0, 573 addresses: &[ 574 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 575 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x1, 576 ], 577 }; 578 579 // A Source Routing Header with elided IPv6 addresses in bytes 580 static BYTES_SRH_ELIDED: [u8; 16] = [ 581 0x6, 0x1, 0x3, 0x2, 0xfe, 0x50, 0x0, 0x0, 0x2, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 582 ]; 583 584 // A representation of a Source Routing Header with elided IPv6 addresses 585 static REPR_SRH_ELIDED: Repr = Repr::Rpl { 586 next_header: Protocol::Tcp, 587 length: 1, 588 segments_left: 2, 589 cmpr_i: 15, 590 cmpr_e: 14, 591 pad: 5, 592 addresses: &[0x2, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0], 593 }; 594 595 #[test] test_check_len()596 fn test_check_len() { 597 // less than min header size 598 assert_eq!(Err(Error), Header::new(&BYTES_TYPE2[..3]).check_len()); 599 assert_eq!(Err(Error), Header::new(&BYTES_SRH_FULL[..3]).check_len()); 600 assert_eq!(Err(Error), Header::new(&BYTES_SRH_ELIDED[..3]).check_len()); 601 // less than specified length field 602 assert_eq!(Err(Error), Header::new(&BYTES_TYPE2[..23]).check_len()); 603 assert_eq!(Err(Error), Header::new(&BYTES_SRH_FULL[..39]).check_len()); 604 assert_eq!(Err(Error), Header::new(&BYTES_SRH_ELIDED[..11]).check_len()); 605 // valid 606 assert_eq!(Ok(()), Header::new(&BYTES_TYPE2[..]).check_len()); 607 assert_eq!(Ok(()), Header::new(&BYTES_SRH_FULL[..]).check_len()); 608 assert_eq!(Ok(()), Header::new(&BYTES_SRH_ELIDED[..]).check_len()); 609 } 610 611 #[test] test_header_deconstruct()612 fn test_header_deconstruct() { 613 let header = Header::new(&BYTES_TYPE2[..]); 614 assert_eq!(header.next_header(), Protocol::Tcp); 615 assert_eq!(header.header_len(), 2); 616 assert_eq!(header.routing_type(), Type::Type2); 617 assert_eq!(header.segments_left(), 1); 618 assert_eq!(header.home_address(), Address::LOOPBACK); 619 620 let header = Header::new(&BYTES_SRH_FULL[..]); 621 assert_eq!(header.next_header(), Protocol::Tcp); 622 assert_eq!(header.header_len(), 4); 623 assert_eq!(header.routing_type(), Type::Rpl); 624 assert_eq!(header.segments_left(), 2); 625 assert_eq!(header.addresses(), &BYTES_SRH_FULL[8..]); 626 627 let header = Header::new(&BYTES_SRH_ELIDED[..]); 628 assert_eq!(header.next_header(), Protocol::Tcp); 629 assert_eq!(header.header_len(), 1); 630 assert_eq!(header.routing_type(), Type::Rpl); 631 assert_eq!(header.segments_left(), 2); 632 assert_eq!(header.addresses(), &BYTES_SRH_ELIDED[8..]); 633 } 634 635 #[test] test_repr_parse_valid()636 fn test_repr_parse_valid() { 637 let header = Header::new_checked(&BYTES_TYPE2[..]).unwrap(); 638 let repr = Repr::parse(&header).unwrap(); 639 assert_eq!(repr, REPR_TYPE2); 640 641 let header = Header::new_checked(&BYTES_SRH_FULL[..]).unwrap(); 642 let repr = Repr::parse(&header).unwrap(); 643 assert_eq!(repr, REPR_SRH_FULL); 644 645 let header = Header::new_checked(&BYTES_SRH_ELIDED[..]).unwrap(); 646 let repr = Repr::parse(&header).unwrap(); 647 assert_eq!(repr, REPR_SRH_ELIDED); 648 } 649 650 #[test] test_repr_emit()651 fn test_repr_emit() { 652 let mut bytes = [0u8; 24]; 653 let mut header = Header::new(&mut bytes[..]); 654 REPR_TYPE2.emit(&mut header); 655 assert_eq!(header.into_inner(), &BYTES_TYPE2[..]); 656 657 let mut bytes = [0u8; 40]; 658 let mut header = Header::new(&mut bytes[..]); 659 REPR_SRH_FULL.emit(&mut header); 660 assert_eq!(header.into_inner(), &BYTES_SRH_FULL[..]); 661 662 let mut bytes = [0u8; 16]; 663 let mut header = Header::new(&mut bytes[..]); 664 REPR_SRH_ELIDED.emit(&mut header); 665 assert_eq!(header.into_inner(), &BYTES_SRH_ELIDED[..]); 666 } 667 668 #[test] test_buffer_len()669 fn test_buffer_len() { 670 assert_eq!(REPR_TYPE2.buffer_len(), 24); 671 assert_eq!(REPR_SRH_FULL.buffer_len(), 40); 672 assert_eq!(REPR_SRH_ELIDED.buffer_len(), 16); 673 } 674 } 675