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