use crate::error::{CrafterError, Result};
use crate::field::Field;
use crate::packet::{Layer, LayerContext};
use super::super::constants::IPV6_EXTENSION_MIN_LEN;
use super::super::display::{
hex_bytes, ipv6_routing_type_label, ipv6_routing_type_status, next_header_summary,
routing_type_summary,
};
use super::super::{layer_ipv6_next_header, value_or_copy};
use super::{header_ext_len_from_total, round_up_to_8, validate_extension_total_len};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Ipv6RoutingTypeStatus {
Assigned,
Deprecated,
Experimental,
Reserved,
Unknown,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Ipv6RoutingHeader {
pub(in crate::protocols::ip::v6) next_header: Field<u8>,
pub(in crate::protocols::ip::v6) header_ext_len: Field<u8>,
pub(in crate::protocols::ip::v6) routing_type: Field<u8>,
pub(in crate::protocols::ip::v6) segments_left: Field<u8>,
pub(in crate::protocols::ip::v6) type_data: Vec<u8>,
}
impl Ipv6RoutingHeader {
pub fn new() -> Self {
Self {
next_header: Field::defaulted(0),
header_ext_len: Field::unset(),
routing_type: Field::defaulted(0),
segments_left: Field::defaulted(0),
type_data: Vec::new(),
}
}
pub fn next_header(mut self, next_header: u8) -> Self {
self.next_header.set_user(next_header);
self
}
pub fn nh(self, next_header: u8) -> Self {
self.next_header(next_header)
}
pub fn header_ext_len(mut self, header_ext_len: u8) -> Self {
self.header_ext_len.set_user(header_ext_len);
self
}
pub fn routing_type(mut self, routing_type: u8) -> Self {
self.routing_type.set_user(routing_type);
self
}
pub fn type_(self, routing_type: u8) -> Self {
self.routing_type(routing_type)
}
pub fn segments_left(mut self, segments_left: u8) -> Self {
self.segments_left.set_user(segments_left);
self
}
pub fn segleft(self, segments_left: u8) -> Self {
self.segments_left(segments_left)
}
pub fn type_data(mut self, type_data: impl Into<Vec<u8>>) -> Self {
self.type_data = type_data.into();
self
}
pub fn append_type_data(mut self, type_data: impl AsRef<[u8]>) -> Self {
self.type_data.extend_from_slice(type_data.as_ref());
self
}
pub fn next_header_value(&self) -> u8 {
value_or_copy(&self.next_header, 0)
}
pub fn header_ext_len_value(&self) -> Option<u8> {
self.header_ext_len.value().copied()
}
pub fn routing_type_value(&self) -> u8 {
value_or_copy(&self.routing_type, 0)
}
pub fn routing_type_label(&self) -> &'static str {
ipv6_routing_type_label(self.routing_type_value())
}
pub fn routing_type_status(&self) -> Ipv6RoutingTypeStatus {
ipv6_routing_type_status(self.routing_type_value())
}
pub fn segments_left_value(&self) -> u8 {
value_or_copy(&self.segments_left, 0)
}
pub fn type_data_bytes(&self) -> &[u8] {
&self.type_data
}
fn effective_total_len(&self) -> usize {
self.header_ext_len
.value()
.map(|value| IPV6_EXTENSION_MIN_LEN + *value as usize * 8)
.unwrap_or_else(|| routing_total_len_for_type_data(self.type_data.len()))
}
fn effective_header_ext_len(&self) -> Result<u8> {
header_ext_len_from_total("ipv6.routing.header_ext_len", self.effective_total_len())
}
fn effective_next_header(&self, next: Option<&dyn Layer>) -> u8 {
if self.next_header.is_user_set() {
return self.next_header_value();
}
next.and_then(layer_ipv6_next_header)
.or_else(|| self.next_header.value().copied())
.unwrap_or(0)
}
fn validate(&self) -> Result<()> {
validate_extension_total_len("ipv6.routing.header_ext_len", self.effective_total_len())?;
if self.effective_total_len() < 4 + self.type_data.len() {
return Err(CrafterError::invalid_field_value(
"ipv6.routing.type_data",
"type-specific data does not fit in the routing header length",
));
}
Ok(())
}
}
impl Default for Ipv6RoutingHeader {
fn default() -> Self {
Self::new()
}
}
impl Layer for Ipv6RoutingHeader {
fn name(&self) -> &'static str {
"Ipv6RoutingHeader"
}
fn summary(&self) -> String {
format!(
"Ipv6RoutingHeader(type={}, segleft={}, next={})",
routing_type_summary(self.routing_type_value()),
self.segments_left_value(),
next_header_summary(self.next_header_value())
)
}
fn inspection_fields(&self) -> Vec<(&'static str, String)> {
vec![
("next_header", next_header_summary(self.next_header_value())),
(
"header_ext_len",
self.header_ext_len_value()
.map(|value| value.to_string())
.unwrap_or_else(|| "auto".to_string()),
),
(
"routing_type",
routing_type_summary(self.routing_type_value()),
),
(
"routing_type_status",
format!("{:?}", self.routing_type_status()),
),
("segments_left", self.segments_left_value().to_string()),
("type_data", hex_bytes(&self.type_data)),
]
}
fn encoded_len(&self) -> usize {
self.effective_total_len()
}
fn compile(&self, ctx: &LayerContext<'_>, out: &mut Vec<u8>) -> Result<()> {
self.validate()?;
let start = out.len();
let total_len = self.effective_total_len();
out.push(self.effective_next_header(ctx.next()));
out.push(self.effective_header_ext_len()?);
out.push(self.routing_type_value());
out.push(self.segments_left_value());
out.extend_from_slice(&self.type_data);
out.resize(start + total_len, 0);
Ok(())
}
impl_ipv6_extension_layer_object!(Ipv6RoutingHeader);
}
impl_ipv6_extension_layer_div!(Ipv6RoutingHeader);
fn routing_total_len_for_type_data(type_data_len: usize) -> usize {
round_up_to_8(4 + type_data_len.max(4))
}