use super::super::*;
use std::fmt::{Debug, Formatter};
use std::slice::from_raw_parts;
pub const IPV6_MAX_NUM_HEADER_EXTENSIONS: usize = 12;
#[derive(Clone)]
pub struct Ipv6RawExtensionHeader {
pub next_header: u8,
header_length: u8,
payload_buffer: [u8;0xff * 8 + 6],
}
impl Debug for Ipv6RawExtensionHeader {
fn fmt(&self, fotmatter: &mut Formatter) -> Result<(), std::fmt::Error> {
write!(fotmatter, "Ipv6RawExtensionHeader {{ next_header: {}, payload: {:?} }}",
self.next_header,
self.payload())
}
}
impl PartialEq for Ipv6RawExtensionHeader {
fn eq(&self, other: &Self) -> bool {
self.next_header == other.next_header &&
self.payload() == other.payload()
}
}
impl Eq for Ipv6RawExtensionHeader {}
impl Ipv6RawExtensionHeader {
pub const MIN_PAYLOAD_LEN: usize = 6;
pub const MAX_PAYLOAD_LEN: usize = 0xff*8 + 6;
pub fn header_type_supported(next_header: u8) -> bool {
use crate::ip_number::*;
matches!(next_header, IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6)
}
pub fn new_raw(next_header: u8, payload: &[u8]) -> Result<Ipv6RawExtensionHeader, ValueError> {
use ValueError::*;
if payload.len() < Self::MIN_PAYLOAD_LEN {
Err(Ipv6ExtensionPayloadTooSmall(payload.len()))
} else if payload.len() > Self::MAX_PAYLOAD_LEN {
Err(Ipv6ExtensionPayloadTooLarge(payload.len()))
} else if 0 != (payload.len() + 2) % 8 {
Err(Ipv6ExtensionPayloadLengthUnaligned(payload.len()))
} else {
let mut result = Ipv6RawExtensionHeader {
next_header,
header_length: ((payload.len() - 6) / 8) as u8,
payload_buffer: [0;Self::MAX_PAYLOAD_LEN]
};
result.payload_buffer[..payload.len()].copy_from_slice(payload);
Ok(result)
}
}
pub fn from_slice(slice: &[u8]) -> Result<(Ipv6RawExtensionHeader, &[u8]), ReadError> {
let s = Ipv6RawExtensionHeaderSlice::from_slice(slice)?;
let rest = &slice[s.slice().len()..];
let header = s.to_header();
Ok((
header,
rest
))
}
pub fn payload(&self) -> &[u8] {
&self.payload_buffer[..(6 + usize::from(self.header_length)*8)]
}
pub fn set_payload(&mut self, payload: &[u8]) -> Result<(), ValueError> {
use ValueError::*;
if payload.len() < Self::MIN_PAYLOAD_LEN {
Err(Ipv6ExtensionPayloadTooSmall(payload.len()))
} else if payload.len() > Self::MAX_PAYLOAD_LEN {
Err(Ipv6ExtensionPayloadTooLarge(payload.len()))
} else if 0 != (payload.len() + 2) % 8 {
Err(Ipv6ExtensionPayloadLengthUnaligned(payload.len()))
} else {
self.payload_buffer[..payload.len()].copy_from_slice(payload);
self.header_length = ((payload.len() - 6) / 8) as u8;
Ok(())
}
}
pub fn read<T: io::Read + io::Seek + Sized>(reader: &mut T) -> Result<Ipv6RawExtensionHeader, ReadError> {
let (next_header, header_length) = {
let mut d : [u8;2] = [0;2];
reader.read_exact(&mut d)?;
(d[0], d[1])
};
Ok(Ipv6RawExtensionHeader {
next_header,
header_length,
payload_buffer: {
let mut buffer = [0;0xff * 8 + 6];
reader.read_exact(&mut buffer[..usize::from(header_length)*8 + 6])?;
buffer
},
})
}
pub fn write<W: io::Write + Sized>(&self, writer: &mut W) -> Result<(), WriteError> {
writer.write_all(&[self.next_header, self.header_length])?;
writer.write_all(self.payload())?;
Ok(())
}
pub fn header_len(&self) -> usize {
2 + (6 + usize::from(self.header_length)*8)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Ipv6RawExtensionHeaderSlice<'a> {
slice: &'a [u8],
}
impl<'a> Ipv6RawExtensionHeaderSlice<'a> {
pub fn header_type_supported(next_header: u8) -> bool {
Ipv6RawExtensionHeader::header_type_supported(next_header)
}
pub fn from_slice(slice: &'a[u8]) -> Result<Ipv6RawExtensionHeaderSlice<'a>, ReadError> {
use crate::ReadError::*;
if slice.len() < 8 {
return Err(UnexpectedEndOfSlice(8));
}
let len = ((slice[1] as usize) + 1)*8;
if slice.len() < len {
return Err(UnexpectedEndOfSlice(len));
}
Ok(Ipv6RawExtensionHeaderSlice {
slice: unsafe {
from_raw_parts(
slice.as_ptr(),
len
)
}
})
}
pub unsafe fn from_slice_unchecked(slice: &'a[u8]) -> Ipv6RawExtensionHeaderSlice<'a> {
Ipv6RawExtensionHeaderSlice {
slice: from_raw_parts(
slice.as_ptr(),
((*slice.get_unchecked(1) as usize) + 1)*8
)
}
}
#[inline]
pub fn slice(&self) -> &'a[u8] {
self.slice
}
#[inline]
pub fn next_header(&self) -> u8 {
unsafe {
*self.slice.get_unchecked(0)
}
}
#[inline]
pub fn payload(&self) -> &'a[u8] {
unsafe {
from_raw_parts(
self.slice.as_ptr().add(2),
self.slice.len() - 2
)
}
}
pub fn to_header(&self) -> Ipv6RawExtensionHeader {
Ipv6RawExtensionHeader::new_raw(
self.next_header(),
self.payload()
).unwrap()
}
}