use crate::ietf::icmpv4::{Checksum, Type};
use crate::{Buf, BufError, BufMut, BufResult};
const DESTINATION_UNREACHABLE_SIZE: usize = 36;
const SOURCE_QUENCH_SIZE: usize = 36;
const REDIRECT_SIZE: usize = 36;
const TIME_EXCEEDED_SIZE: usize = 36;
const PARAMETER_PROBLEM_SIZE: usize = 36;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EchoReplyMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> EchoReplyMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_identifier(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(4) }
}
pub fn read_sequence_number(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(6) }
}
}
impl<T: BufMut> EchoReplyMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_identifier(&mut self, identifier: u16) -> BufResult<()> {
if self.buffer.length() < 6 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(4, identifier) }
Ok(())
}
pub fn write_sequence_number(&mut self, sequence_number: u16) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, sequence_number) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DestinationUnreachableMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> DestinationUnreachableMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_unused(&self) -> [u8; 4] {
unsafe { self.buffer.get_array_unchecked::<4>(4) }
}
pub fn read_header(&self) -> [u8; 20] {
unsafe { self.buffer.get_array_unchecked::<20>(8) }
}
pub fn read_bytes(&self) -> [u8; 8] {
unsafe { self.buffer.get_array_unchecked::<8>(28) }
}
}
impl<T: BufMut> DestinationUnreachableMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_unused(&mut self) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<4>(4, &[0; 4]) }
Ok(())
}
pub fn write_header(&mut self, header: [u8; 20]) -> BufResult<()> {
if self.buffer.length() < DESTINATION_UNREACHABLE_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<20>(8, &header) }
Ok(())
}
pub fn write_bytes(&mut self, bytes: [u8; 8]) -> BufResult<()> {
if self.buffer.length() < DESTINATION_UNREACHABLE_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<8>(28, &bytes) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SourceQuenchMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> SourceQuenchMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_unused(&self) -> [u8; 4] {
unsafe { self.buffer.get_array_unchecked::<4>(4) }
}
pub fn read_header(&self) -> [u8; 20] {
unsafe { self.buffer.get_array_unchecked::<20>(8) }
}
pub fn read_bytes(&self) -> [u8; 8] {
unsafe { self.buffer.get_array_unchecked::<8>(28) }
}
}
impl<T: BufMut> SourceQuenchMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_unused(&mut self) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<4>(4, &[0; 4]) }
Ok(())
}
pub fn write_header(&mut self, header: [u8; 20]) -> BufResult<()> {
if self.buffer.length() < SOURCE_QUENCH_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<20>(8, &header) }
Ok(())
}
pub fn write_bytes(&mut self, bytes: [u8; 8]) -> BufResult<()> {
if self.buffer.length() < SOURCE_QUENCH_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<8>(28, &bytes) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RedirectMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> RedirectMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_gateway_address(&self) -> [u8; 4] {
unsafe { self.buffer.get_array_unchecked::<4>(4) }
}
pub fn read_header(&self) -> [u8; 20] {
unsafe { self.buffer.get_array_unchecked::<20>(8) }
}
pub fn read_bytes(&self) -> [u8; 8] {
unsafe { self.buffer.get_array_unchecked::<8>(28) }
}
}
impl<T: BufMut> RedirectMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_gateway_address(&mut self, addr: [u8; 4]) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<4>(4, &addr) }
Ok(())
}
pub fn write_header(&mut self, header: [u8; 20]) -> BufResult<()> {
if self.buffer.length() < REDIRECT_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<20>(8, &header) }
Ok(())
}
pub fn write_bytes(&mut self, bytes: [u8; 8]) -> BufResult<()> {
if self.buffer.length() < REDIRECT_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<8>(28, &bytes) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EchoMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> EchoMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_identifier(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(4) }
}
pub fn read_sequence_number(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(6) }
}
}
impl<T: BufMut> EchoMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_identifier(&mut self, identifier: u16) -> BufResult<()> {
if self.buffer.length() < 6 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(4, identifier) }
Ok(())
}
pub fn write_sequence_number(&mut self, sequence_number: u16) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, sequence_number) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TimeExceededMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> TimeExceededMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_unused(&self) -> [u8; 4] {
unsafe { self.buffer.get_array_unchecked::<4>(4) }
}
pub fn read_header(&self) -> [u8; 20] {
unsafe { self.buffer.get_array_unchecked::<20>(8) }
}
pub fn read_bytes(&self) -> [u8; 8] {
unsafe { self.buffer.get_array_unchecked::<8>(28) }
}
}
impl<T: BufMut> TimeExceededMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_unused(&mut self) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<4>(4, &[0; 4]) }
Ok(())
}
pub fn write_header(&mut self, header: [u8; 20]) -> BufResult<()> {
if self.buffer.length() < TIME_EXCEEDED_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<20>(8, &header) }
Ok(())
}
pub fn write_bytes(&mut self, bytes: [u8; 8]) -> BufResult<()> {
if self.buffer.length() < TIME_EXCEEDED_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<8>(28, &bytes) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ParameterProblemMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> ParameterProblemMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_pointer(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(4) }
}
pub fn read_unused(&self) -> [u8; 3] {
unsafe { self.buffer.get_array_unchecked::<3>(5) }
}
pub fn read_header(&self) -> [u8; 20] {
unsafe { self.buffer.get_array_unchecked::<20>(8) }
}
pub fn read_bytes(&self) -> [u8; 8] {
unsafe { self.buffer.get_array_unchecked::<8>(28) }
}
}
impl<T: BufMut> ParameterProblemMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_pointer(&mut self, pointer: u8) -> BufResult<()> {
if self.buffer.length() < 5 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(4, pointer) }
Ok(())
}
pub fn write_unused(&mut self) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<3>(5, &[0; 3]) }
Ok(())
}
pub fn write_header(&mut self, header: [u8; 20]) -> BufResult<()> {
if self.buffer.length() < PARAMETER_PROBLEM_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<20>(8, &header) }
Ok(())
}
pub fn write_bytes(&mut self, bytes: [u8; 8]) -> BufResult<()> {
if self.buffer.length() < PARAMETER_PROBLEM_SIZE {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_array_unchecked::<8>(28, &bytes) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TimestampMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> TimestampMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_identifier(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(4) }
}
pub fn read_sequence_number(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(6) }
}
pub fn read_originate_timestamp(&self) -> u32 {
unsafe { self.buffer.get_u32_be_unchecked(8) }
}
pub fn read_receive_timestamp(&self) -> u32 {
unsafe { self.buffer.get_u32_be_unchecked(12) }
}
pub fn read_transmit_timestamp(&self) -> u32 {
unsafe { self.buffer.get_u32_be_unchecked(16) }
}
}
impl<T: BufMut> TimestampMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_identifier(&mut self, identifier: u16) -> BufResult<()> {
if self.buffer.length() < 6 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(4, identifier) }
Ok(())
}
pub fn write_sequence_number(&mut self, sequence_number: u16) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, sequence_number) }
Ok(())
}
pub fn write_originate_timestamp(&mut self, timestamp: u32) -> BufResult<()> {
if self.buffer.length() < 12 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u32_be_unchecked(8, timestamp) }
Ok(())
}
pub fn write_receive_timestamp(&mut self, timestamp: u32) -> BufResult<()> {
if self.buffer.length() < 16 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u32_be_unchecked(12, timestamp) }
Ok(())
}
pub fn write_transmit_timestamp(&mut self, timestamp: u32) -> BufResult<()> {
if self.buffer.length() < 20 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u32_be_unchecked(16, timestamp) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TimestampReplyMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> TimestampReplyMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_identifier(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(4) }
}
pub fn read_sequence_number(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(6) }
}
pub fn read_originate_timestamp(&self) -> u32 {
unsafe { self.buffer.get_u32_be_unchecked(8) }
}
pub fn read_receive_timestamp(&self) -> u32 {
unsafe { self.buffer.get_u32_be_unchecked(12) }
}
pub fn read_transmit_timestamp(&self) -> u32 {
unsafe { self.buffer.get_u32_be_unchecked(16) }
}
}
impl<T: BufMut> TimestampReplyMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_identifier(&mut self, identifier: u16) -> BufResult<()> {
if self.buffer.length() < 6 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(4, identifier) }
Ok(())
}
pub fn write_sequence_number(&mut self, sequence_number: u16) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, sequence_number) }
Ok(())
}
pub fn write_originate_timestamp(&mut self, timestamp: u32) -> BufResult<()> {
if self.buffer.length() < 12 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u32_be_unchecked(8, timestamp) }
Ok(())
}
pub fn write_receive_timestamp(&mut self, timestamp: u32) -> BufResult<()> {
if self.buffer.length() < 16 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u32_be_unchecked(12, timestamp) }
Ok(())
}
pub fn write_transmit_timestamp(&mut self, timestamp: u32) -> BufResult<()> {
if self.buffer.length() < 20 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u32_be_unchecked(16, timestamp) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InformationRequestMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> InformationRequestMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_identifier(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(4) }
}
pub fn read_sequence_number(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(6) }
}
}
impl<T: BufMut> InformationRequestMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_identifier(&mut self, identifier: u16) -> BufResult<()> {
if self.buffer.length() < 6 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(4, identifier) }
Ok(())
}
pub fn write_sequence_number(&mut self, sequence_number: u16) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, sequence_number) }
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InformationReplyMapping<T: Buf> {
buffer: T,
}
impl<T: Buf> InformationReplyMapping<T> {
pub fn new(buffer: T) -> Self {
Self { buffer }
}
pub fn into_inner(self) -> T {
self.buffer
}
pub fn as_inner(&self) -> &T {
&self.buffer
}
pub fn read_type(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(0) }
}
pub fn read_code(&self) -> u8 {
unsafe { self.buffer.get_u8_unchecked(1) }
}
pub fn read_checksum(&self) -> Checksum {
unsafe { Checksum(self.buffer.get_u16_be_unchecked(2)) }
}
pub fn read_identifier(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(4) }
}
pub fn read_sequence_number(&self) -> u16 {
unsafe { self.buffer.get_u16_be_unchecked(6) }
}
}
impl<T: BufMut> InformationReplyMapping<T> {
pub fn write_type(&mut self, r#type: Type) -> BufResult<()> {
if self.buffer.length() < 1 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(0, r#type as u8) }
Ok(())
}
pub fn write_code(&mut self, code: u8) -> BufResult<()> {
if self.buffer.length() < 2 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u8_unchecked(1, code) }
Ok(())
}
pub fn write_checksum(&mut self, checksum: Checksum) -> BufResult<()> {
if self.buffer.length() < 4 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(2, checksum.0) }
Ok(())
}
pub fn write_identifier(&mut self, identifier: u16) -> BufResult<()> {
if self.buffer.length() < 6 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(4, identifier) }
Ok(())
}
pub fn write_sequence_number(&mut self, sequence_number: u16) -> BufResult<()> {
if self.buffer.length() < 8 {
return Err(BufError::BufferTooSmall);
}
unsafe { self.buffer.set_u16_be_unchecked(6, sequence_number) }
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn echo_reply_roundtrip() {
let mut buf = [0u8; 8];
let mut m = EchoReplyMapping::new(&mut buf[..]);
m.write_type(Type::EchoReply).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0x1234)).unwrap();
m.write_identifier(0x5678).unwrap();
m.write_sequence_number(0x9ABC).unwrap();
let read = EchoReplyMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x00);
assert_eq!(read.read_code(), 0);
assert_eq!(read.read_checksum(), Checksum(0x1234));
assert_eq!(read.read_identifier(), 0x5678);
assert_eq!(read.read_sequence_number(), 0x9ABC);
}
#[test]
fn destination_unreachable_roundtrip() {
let mut buf = [0u8; 36];
let mut m = DestinationUnreachableMapping::new(&mut buf[..]);
m.write_type(Type::DestinationUnreachable).unwrap();
m.write_code(1).unwrap();
m.write_checksum(Checksum(0xBEEF)).unwrap();
m.write_unused().unwrap();
m.write_header([0xAA; 20]).unwrap();
m.write_bytes([0xBB; 8]).unwrap();
let read = DestinationUnreachableMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x03);
assert_eq!(read.read_code(), 1);
assert_eq!(read.read_checksum(), Checksum(0xBEEF));
assert_eq!(read.read_unused(), [0; 4]);
assert_eq!(read.read_header(), [0xAA; 20]);
assert_eq!(read.read_bytes(), [0xBB; 8]);
}
#[test]
fn source_quench_roundtrip() {
let mut buf = [0u8; 36];
let mut m = SourceQuenchMapping::new(&mut buf[..]);
m.write_type(Type::SourceQuench).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0xCAFE)).unwrap();
m.write_unused().unwrap();
m.write_header([0xCC; 20]).unwrap();
m.write_bytes([0xDD; 8]).unwrap();
let read = SourceQuenchMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x04);
assert_eq!(read.read_header(), [0xCC; 20]);
assert_eq!(read.read_bytes(), [0xDD; 8]);
}
#[test]
fn redirect_roundtrip() {
let mut buf = [0u8; 36];
let mut m = RedirectMapping::new(&mut buf[..]);
m.write_type(Type::Redirect).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0xDEAD)).unwrap();
m.write_gateway_address([10, 0, 0, 1]).unwrap();
m.write_header([0xEE; 20]).unwrap();
m.write_bytes([0xFF; 8]).unwrap();
let read = RedirectMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x05);
assert_eq!(read.read_gateway_address(), [10, 0, 0, 1]);
assert_eq!(read.read_header(), [0xEE; 20]);
assert_eq!(read.read_bytes(), [0xFF; 8]);
}
#[test]
fn echo_roundtrip() {
let mut buf = [0u8; 8];
let mut m = EchoMapping::new(&mut buf[..]);
m.write_type(Type::Echo).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0xABCD)).unwrap();
m.write_identifier(1).unwrap();
m.write_sequence_number(2).unwrap();
let read = EchoMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x08);
assert_eq!(read.read_identifier(), 1);
assert_eq!(read.read_sequence_number(), 2);
}
#[test]
fn time_exceeded_roundtrip() {
let mut buf = [0u8; 36];
let mut m = TimeExceededMapping::new(&mut buf[..]);
m.write_type(Type::TimeExceeded).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0xBABE)).unwrap();
m.write_unused().unwrap();
m.write_header([0x11; 20]).unwrap();
m.write_bytes([0x22; 8]).unwrap();
let read = TimeExceededMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x0B);
assert_eq!(read.read_unused(), [0; 4]);
}
#[test]
fn parameter_problem_roundtrip() {
let mut buf = [0u8; 36];
let mut m = ParameterProblemMapping::new(&mut buf[..]);
m.write_type(Type::ParameterProblem).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0xFACE)).unwrap();
m.write_pointer(5).unwrap();
m.write_unused().unwrap();
m.write_header([0x33; 20]).unwrap();
m.write_bytes([0x44; 8]).unwrap();
let read = ParameterProblemMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x0C);
assert_eq!(read.read_pointer(), 5);
assert_eq!(read.read_unused(), [0; 3]);
}
#[test]
fn timestamp_roundtrip() {
let mut buf = [0u8; 20];
let mut m = TimestampMapping::new(&mut buf[..]);
m.write_type(Type::Timestamp).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0x1234)).unwrap();
m.write_identifier(1).unwrap();
m.write_sequence_number(2).unwrap();
m.write_originate_timestamp(100).unwrap();
m.write_receive_timestamp(200).unwrap();
m.write_transmit_timestamp(300).unwrap();
let read = TimestampMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x0D);
assert_eq!(read.read_originate_timestamp(), 100);
assert_eq!(read.read_receive_timestamp(), 200);
assert_eq!(read.read_transmit_timestamp(), 300);
}
#[test]
fn timestamp_reply_roundtrip() {
let mut buf = [0u8; 20];
let mut m = TimestampReplyMapping::new(&mut buf[..]);
m.write_type(Type::TimestampReply).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0x5678)).unwrap();
m.write_identifier(3).unwrap();
m.write_sequence_number(4).unwrap();
m.write_originate_timestamp(400).unwrap();
m.write_receive_timestamp(500).unwrap();
m.write_transmit_timestamp(600).unwrap();
let read = TimestampReplyMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x0E);
assert_eq!(read.read_transmit_timestamp(), 600);
}
#[test]
fn information_request_roundtrip() {
let mut buf = [0u8; 8];
let mut m = InformationRequestMapping::new(&mut buf[..]);
m.write_type(Type::InformationRequest).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0x9ABC)).unwrap();
m.write_identifier(5).unwrap();
m.write_sequence_number(6).unwrap();
let read = InformationRequestMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x0F);
assert_eq!(read.read_identifier(), 5);
}
#[test]
fn information_reply_roundtrip() {
let mut buf = [0u8; 8];
let mut m = InformationReplyMapping::new(&mut buf[..]);
m.write_type(Type::InformationReply).unwrap();
m.write_code(0).unwrap();
m.write_checksum(Checksum(0xDEF0)).unwrap();
m.write_identifier(7).unwrap();
m.write_sequence_number(8).unwrap();
let read = InformationReplyMapping::new(&buf[..]);
assert_eq!(read.read_type(), 0x10);
assert_eq!(read.read_sequence_number(), 8);
}
#[test]
fn buffer_too_small() {
let mut buf = [0u8; 2];
let mut m = EchoMapping::new(&mut buf[..]);
assert!(m.write_checksum(Checksum(0)).is_err());
}
}