use core::fmt;
use {Error, Result};
use super::IpProtocol as Protocol;
use super::Ipv6Address as Address;
enum_with_unknown! {
pub doc enum Type(u8) {
Type0 = 0,
Nimrod = 1,
Type2 = 2,
Rpl = 3,
Experiment1 = 253,
Experiment2 = 254,
Reserved = 252
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Type::Type0 => write!(f, "Type0"),
&Type::Nimrod => write!(f, "Nimrod"),
&Type::Type2 => write!(f, "Type2"),
&Type::Rpl => write!(f, "Rpl"),
&Type::Experiment1 => write!(f, "Experiment1"),
&Type::Experiment2 => write!(f, "Experiment2"),
&Type::Reserved => write!(f, "Reserved"),
&Type::Unknown(id) => write!(f, "{}", id)
}
}
}
#[derive(Debug, PartialEq)]
pub struct Header<T: AsRef<[u8]>> {
buffer: T
}
mod field {
#![allow(non_snake_case)]
use wire::field::*;
pub const MIN_HEADER_SIZE: usize = 4;
pub const NXT_HDR: usize = 0;
pub const LENGTH: usize = 1;
pub const TYPE: usize = 2;
pub const SEG_LEFT: usize = 3;
pub fn DATA(length_field: u8) -> Field {
let bytes = length_field * 8 + 8;
4..bytes as usize
}
pub const HOME_ADDRESS: Field = 8..24;
pub const CMPR: usize = 4;
pub const PAD: usize = 5;
pub fn ADDRESSES(length_field: u8) -> Field {
let data = DATA(length_field);
8..data.end
}
}
impl<T: AsRef<[u8]>> Header<T> {
pub fn new(buffer: T) -> Header<T> {
Header { buffer }
}
pub fn new_checked(buffer: T) -> Result<Header<T>> {
let header = Self::new(buffer);
header.check_len()?;
Ok(header)
}
pub fn check_len(&self) -> Result<()> {
let len = self.buffer.as_ref().len();
if len < field::MIN_HEADER_SIZE {
return Err(Error::Truncated);
}
if len < field::DATA(self.header_len()).end as usize {
return Err(Error::Truncated);
}
Ok(())
}
pub fn into_inner(self) -> T {
self.buffer
}
#[inline]
pub fn next_header(&self) -> Protocol {
let data = self.buffer.as_ref();
Protocol::from(data[field::NXT_HDR])
}
#[inline]
pub fn header_len(&self) -> u8 {
let data = self.buffer.as_ref();
data[field::LENGTH]
}
#[inline]
pub fn routing_type(&self) -> Type {
let data = self.buffer.as_ref();
Type::from(data[field::TYPE])
}
#[inline]
pub fn segments_left(&self) -> u8 {
let data = self.buffer.as_ref();
data[field::SEG_LEFT]
}
}
impl<T: AsRef<[u8]>> Header<T> {
pub fn home_address(&self) -> Address {
let data = self.buffer.as_ref();
Address::from_bytes(&data[field::HOME_ADDRESS])
}
}
impl<T: AsRef<[u8]>> Header<T> {
pub fn cmpr_i(&self) -> u8 {
let data = self.buffer.as_ref();
data[field::CMPR] >> 4
}
pub fn cmpr_e(&self) -> u8 {
let data = self.buffer.as_ref();
data[field::CMPR] & 0xf
}
pub fn pad(&self) -> u8 {
let data = self.buffer.as_ref();
data[field::PAD] >> 4
}
pub fn addresses(&self) -> &[u8] {
let data = self.buffer.as_ref();
&data[field::ADDRESSES(data[field::LENGTH])]
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
#[inline]
pub fn set_next_header(&mut self, value: Protocol) {
let data = self.buffer.as_mut();
data[field::NXT_HDR] = value.into();
}
#[inline]
pub fn set_header_len(&mut self, value: u8) {
let data = self.buffer.as_mut();
data[field::LENGTH] = value;
}
#[inline]
pub fn set_routing_type(&mut self, value: Type) {
let data = self.buffer.as_mut();
data[field::TYPE] = value.into();
}
#[inline]
pub fn set_segments_left(&mut self, value: u8) {
let data = self.buffer.as_mut();
data[field::SEG_LEFT] = value;
}
#[inline]
pub fn clear_reserved(&mut self) {
let routing_type = self.routing_type();
let data = self.buffer.as_mut();
match routing_type {
Type::Type2 => {
data[4] = 0;
data[5] = 0;
data[6] = 0;
data[7] = 0;
}
Type::Rpl => {
data[field::PAD] = data[field::PAD] & 0xF0;
data[6] = 0;
data[7] = 0;
}
_ => panic!("Unrecognized routing type when clearing reserved fields.")
}
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
pub fn set_home_address(&mut self, value: Address) {
let data = self.buffer.as_mut();
data[field::HOME_ADDRESS].copy_from_slice(value.as_bytes());
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
pub fn set_cmpr_i(&mut self, value: u8) {
let data = self.buffer.as_mut();
let raw = (value << 4) | (data[field::CMPR] & 0xF);
data[field::CMPR] = raw;
}
pub fn set_cmpr_e(&mut self, value: u8) {
let data = self.buffer.as_mut();
let raw = (value & 0xF) | (data[field::CMPR] & 0xF0);
data[field::CMPR] = raw;
}
pub fn set_pad(&mut self, value: u8) {
let data = self.buffer.as_mut();
data[field::PAD] = value << 4;
}
pub fn set_addresses(&mut self, value: &[u8]) {
let data = self.buffer.as_mut();
let len = data[field::LENGTH];
let addresses = &mut data[field::ADDRESSES(len)];
addresses.copy_from_slice(value);
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match Repr::parse(self) {
Ok(repr) => write!(f, "{}", repr),
Err(err) => {
write!(f, "IPv6 Routing ({})", err)?;
Ok(())
}
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Repr<'a> {
Type2 {
next_header: Protocol,
length: u8,
segments_left: u8,
home_address: Address,
},
Rpl {
next_header: Protocol,
length: u8,
segments_left: u8,
cmpr_i: u8,
cmpr_e: u8,
pad: u8,
addresses: &'a[u8],
},
#[doc(hidden)]
__Nonexhaustive
}
impl<'a> Repr<'a> {
pub fn parse<T>(header: &'a Header<&'a T>) -> Result<Repr<'a>> where T: AsRef<[u8]> + ?Sized {
match header.routing_type() {
Type::Type2 => {
Ok(Repr::Type2 {
next_header: header.next_header(),
length: header.header_len(),
segments_left: header.segments_left(),
home_address: header.home_address(),
})
}
Type::Rpl => {
Ok(Repr::Rpl {
next_header: header.next_header(),
length: header.header_len(),
segments_left: header.segments_left(),
cmpr_i: header.cmpr_i(),
cmpr_e: header.cmpr_e(),
pad: header.pad(),
addresses: header.addresses(),
})
}
_ => Err(Error::Unrecognized)
}
}
pub fn buffer_len(&self) -> usize {
match self {
&Repr::Rpl { length, .. } | &Repr::Type2 { length, .. } => {
field::DATA(length).end
}
&Repr::__Nonexhaustive => unreachable!()
}
}
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
match self {
&Repr::Type2 { next_header, length, segments_left, home_address } => {
header.set_next_header(next_header);
header.set_header_len(length);
header.set_routing_type(Type::Type2);
header.set_segments_left(segments_left);
header.clear_reserved();
header.set_home_address(home_address);
}
&Repr::Rpl { next_header, length, segments_left, cmpr_i, cmpr_e, pad, addresses } => {
header.set_next_header(next_header);
header.set_header_len(length);
header.set_routing_type(Type::Rpl);
header.set_segments_left(segments_left);
header.set_cmpr_i(cmpr_i);
header.set_cmpr_e(cmpr_e);
header.set_pad(pad);
header.clear_reserved();
header.set_addresses(addresses);
}
&Repr::__Nonexhaustive => unreachable!(),
}
}
}
impl<'a> fmt::Display for Repr<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Repr::Type2 { next_header, length, segments_left, home_address } => {
write!(f, "IPv6 Routing next_hdr={} length={} type={} seg_left={} home_address={}",
next_header, length, Type::Type2, segments_left, home_address)
}
&Repr::Rpl { next_header, length, segments_left, cmpr_i, cmpr_e, pad, .. } => {
write!(f, "IPv6 Routing next_hdr={} length={} type={} seg_left={} cmpr_i={} cmpr_e={} pad={}",
next_header, length, Type::Rpl, segments_left, cmpr_i, cmpr_e, pad)
}
&Repr::__Nonexhaustive => unreachable!(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
static BYTES_TYPE2: [u8; 24] = [0x6, 0x2, 0x2, 0x1,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x1];
static REPR_TYPE2: Repr = Repr::Type2 {
next_header: Protocol::Tcp,
length: 2,
segments_left: 1,
home_address: Address::LOOPBACK,
};
static BYTES_SRH_FULL: [u8; 40] = [0x6, 0x4, 0x3, 0x2,
0x0, 0x0, 0x0, 0x0,
0xfd, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2,
0xfd, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x3, 0x1];
static REPR_SRH_FULL: Repr = Repr::Rpl {
next_header: Protocol::Tcp,
length: 4,
segments_left: 2,
cmpr_i: 0,
cmpr_e: 0,
pad: 0,
addresses: &[0xfd, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x2,
0xfd, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x3, 0x1]
};
static BYTES_SRH_ELIDED: [u8; 16] = [0x6, 0x1, 0x3, 0x2,
0xfe, 0x50, 0x0, 0x0,
0x2, 0x3, 0x1, 0x0,
0x0, 0x0, 0x0, 0x0];
static REPR_SRH_ELIDED: Repr = Repr::Rpl {
next_header: Protocol::Tcp,
length: 1,
segments_left: 2,
cmpr_i: 15,
cmpr_e: 14,
pad: 5,
addresses: &[0x2, 0x3, 0x1, 0x0,
0x0, 0x0, 0x0, 0x0]
};
#[test]
fn test_check_len() {
assert_eq!(Err(Error::Truncated), Header::new(&BYTES_TYPE2[..3]).check_len());
assert_eq!(Err(Error::Truncated), Header::new(&BYTES_SRH_FULL[..3]).check_len());
assert_eq!(Err(Error::Truncated), Header::new(&BYTES_SRH_ELIDED[..3]).check_len());
assert_eq!(Err(Error::Truncated), Header::new(&BYTES_TYPE2[..23]).check_len());
assert_eq!(Err(Error::Truncated), Header::new(&BYTES_SRH_FULL[..39]).check_len());
assert_eq!(Err(Error::Truncated), Header::new(&BYTES_SRH_ELIDED[..11]).check_len());
assert_eq!(Ok(()), Header::new(&BYTES_TYPE2[..]).check_len());
assert_eq!(Ok(()), Header::new(&BYTES_SRH_FULL[..]).check_len());
assert_eq!(Ok(()), Header::new(&BYTES_SRH_ELIDED[..]).check_len());
}
#[test]
fn test_header_deconstruct() {
let header = Header::new(&BYTES_TYPE2[..]);
assert_eq!(header.next_header(), Protocol::Tcp);
assert_eq!(header.header_len(), 2);
assert_eq!(header.routing_type(), Type::Type2);
assert_eq!(header.segments_left(), 1);
assert_eq!(header.home_address(), Address::LOOPBACK);
let header = Header::new(&BYTES_SRH_FULL[..]);
assert_eq!(header.next_header(), Protocol::Tcp);
assert_eq!(header.header_len(), 4);
assert_eq!(header.routing_type(), Type::Rpl);
assert_eq!(header.segments_left(), 2);
assert_eq!(header.addresses(), &BYTES_SRH_FULL[8..]);
let header = Header::new(&BYTES_SRH_ELIDED[..]);
assert_eq!(header.next_header(), Protocol::Tcp);
assert_eq!(header.header_len(), 1);
assert_eq!(header.routing_type(), Type::Rpl);
assert_eq!(header.segments_left(), 2);
assert_eq!(header.addresses(), &BYTES_SRH_ELIDED[8..]);
}
#[test]
fn test_repr_parse_valid() {
let header = Header::new_checked(&BYTES_TYPE2[..]).unwrap();
let repr = Repr::parse(&header).unwrap();
assert_eq!(repr, REPR_TYPE2);
let header = Header::new_checked(&BYTES_SRH_FULL[..]).unwrap();
let repr = Repr::parse(&header).unwrap();
assert_eq!(repr, REPR_SRH_FULL);
let header = Header::new_checked(&BYTES_SRH_ELIDED[..]).unwrap();
let repr = Repr::parse(&header).unwrap();
assert_eq!(repr, REPR_SRH_ELIDED);
}
#[test]
fn test_repr_emit() {
let mut bytes = [0u8; 24];
let mut header = Header::new(&mut bytes[..]);
REPR_TYPE2.emit(&mut header);
assert_eq!(header.into_inner(), &BYTES_TYPE2[..]);
let mut bytes = [0u8; 40];
let mut header = Header::new(&mut bytes[..]);
REPR_SRH_FULL.emit(&mut header);
assert_eq!(header.into_inner(), &BYTES_SRH_FULL[..]);
let mut bytes = [0u8; 16];
let mut header = Header::new(&mut bytes[..]);
REPR_SRH_ELIDED.emit(&mut header);
assert_eq!(header.into_inner(), &BYTES_SRH_ELIDED[..]);
}
#[test]
fn test_buffer_len() {
assert_eq!(REPR_TYPE2.buffer_len(), 24);
assert_eq!(REPR_SRH_FULL.buffer_len(), 40);
assert_eq!(REPR_SRH_ELIDED.buffer_len(), 16);
}
}