use core::convert::From;
use core::fmt;
use super::{Error, Result};
use crate::phy::ChecksumCapabilities;
#[cfg(feature = "proto-ipv4")]
use crate::wire::{Ipv4Address, Ipv4Cidr, Ipv4Packet, Ipv4Repr};
#[cfg(feature = "proto-ipv6")]
use crate::wire::{Ipv6Address, Ipv6Cidr, Ipv6Packet, Ipv6Repr};
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Version {
#[cfg(feature = "proto-ipv4")]
Ipv4,
#[cfg(feature = "proto-ipv6")]
Ipv6,
}
impl Version {
pub const fn of_packet(data: &[u8]) -> Result<Version> {
match data[0] >> 4 {
#[cfg(feature = "proto-ipv4")]
4 => Ok(Version::Ipv4),
#[cfg(feature = "proto-ipv6")]
6 => Ok(Version::Ipv6),
_ => Err(Error),
}
}
}
impl fmt::Display for Version {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
#[cfg(feature = "proto-ipv4")]
Version::Ipv4 => write!(f, "IPv4"),
#[cfg(feature = "proto-ipv6")]
Version::Ipv6 => write!(f, "IPv6"),
}
}
}
enum_with_unknown! {
pub enum Protocol(u8) {
HopByHop = 0x00,
Icmp = 0x01,
Igmp = 0x02,
Tcp = 0x06,
Udp = 0x11,
Ipv6Route = 0x2b,
Ipv6Frag = 0x2c,
IpSecEsp = 0x32,
IpSecAh = 0x33,
Icmpv6 = 0x3a,
Ipv6NoNxt = 0x3b,
Ipv6Opts = 0x3c
}
}
impl fmt::Display for Protocol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Protocol::HopByHop => write!(f, "Hop-by-Hop"),
Protocol::Icmp => write!(f, "ICMP"),
Protocol::Igmp => write!(f, "IGMP"),
Protocol::Tcp => write!(f, "TCP"),
Protocol::Udp => write!(f, "UDP"),
Protocol::Ipv6Route => write!(f, "IPv6-Route"),
Protocol::Ipv6Frag => write!(f, "IPv6-Frag"),
Protocol::IpSecEsp => write!(f, "IPsec-ESP"),
Protocol::IpSecAh => write!(f, "IPsec-AH"),
Protocol::Icmpv6 => write!(f, "ICMPv6"),
Protocol::Ipv6NoNxt => write!(f, "IPv6-NoNxt"),
Protocol::Ipv6Opts => write!(f, "IPv6-Opts"),
Protocol::Unknown(id) => write!(f, "0x{id:02x}"),
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Address {
#[cfg(feature = "proto-ipv4")]
Ipv4(Ipv4Address),
#[cfg(feature = "proto-ipv6")]
Ipv6(Ipv6Address),
}
impl Address {
#[cfg(feature = "proto-ipv4")]
pub const fn v4(a0: u8, a1: u8, a2: u8, a3: u8) -> Address {
Address::Ipv4(Ipv4Address::new(a0, a1, a2, a3))
}
#[cfg(feature = "proto-ipv6")]
#[allow(clippy::too_many_arguments)]
pub fn v6(a0: u16, a1: u16, a2: u16, a3: u16, a4: u16, a5: u16, a6: u16, a7: u16) -> Address {
Address::Ipv6(Ipv6Address::new(a0, a1, a2, a3, a4, a5, a6, a7))
}
pub const fn version(&self) -> Version {
match self {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(_) => Version::Ipv4,
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(_) => Version::Ipv6,
}
}
pub const fn as_bytes(&self) -> &[u8] {
match self {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(addr) => addr.as_bytes(),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(addr) => addr.as_bytes(),
}
}
pub fn is_unicast(&self) -> bool {
match self {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(addr) => addr.is_unicast(),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(addr) => addr.is_unicast(),
}
}
pub const fn is_multicast(&self) -> bool {
match self {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(addr) => addr.is_multicast(),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(addr) => addr.is_multicast(),
}
}
pub fn is_broadcast(&self) -> bool {
match self {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(addr) => addr.is_broadcast(),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(_) => false,
}
}
pub fn is_unspecified(&self) -> bool {
match self {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(addr) => addr.is_unspecified(),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(addr) => addr.is_unspecified(),
}
}
pub fn prefix_len(&self) -> Option<u8> {
let mut ones = true;
let mut prefix_len = 0;
for byte in self.as_bytes() {
let mut mask = 0x80;
for _ in 0..8 {
let one = *byte & mask != 0;
if ones {
if one {
prefix_len += 1;
} else {
ones = false;
}
} else if one {
return None;
}
mask >>= 1;
}
}
Some(prefix_len)
}
}
#[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
impl From<::std::net::IpAddr> for Address {
fn from(x: ::std::net::IpAddr) -> Address {
match x {
::std::net::IpAddr::V4(ipv4) => Address::Ipv4(ipv4.into()),
::std::net::IpAddr::V6(ipv6) => Address::Ipv6(ipv6.into()),
}
}
}
#[cfg(feature = "std")]
impl From<Address> for ::std::net::IpAddr {
fn from(x: Address) -> ::std::net::IpAddr {
match x {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(ipv4) => ::std::net::IpAddr::V4(ipv4.into()),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(ipv6) => ::std::net::IpAddr::V6(ipv6.into()),
}
}
}
#[cfg(all(feature = "std", feature = "proto-ipv4"))]
impl From<::std::net::Ipv4Addr> for Address {
fn from(ipv4: ::std::net::Ipv4Addr) -> Address {
Address::Ipv4(ipv4.into())
}
}
#[cfg(all(feature = "std", feature = "proto-ipv6"))]
impl From<::std::net::Ipv6Addr> for Address {
fn from(ipv6: ::std::net::Ipv6Addr) -> Address {
Address::Ipv6(ipv6.into())
}
}
#[cfg(feature = "proto-ipv4")]
impl From<Ipv4Address> for Address {
fn from(addr: Ipv4Address) -> Self {
Address::Ipv4(addr)
}
}
#[cfg(feature = "proto-ipv6")]
impl From<Ipv6Address> for Address {
fn from(addr: Ipv6Address) -> Self {
Address::Ipv6(addr)
}
}
impl fmt::Display for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(addr) => write!(f, "{addr}"),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(addr) => write!(f, "{addr}"),
}
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for Address {
fn format(&self, f: defmt::Formatter) {
match self {
#[cfg(feature = "proto-ipv4")]
&Address::Ipv4(addr) => defmt::write!(f, "{:?}", addr),
#[cfg(feature = "proto-ipv6")]
&Address::Ipv6(addr) => defmt::write!(f, "{:?}", addr),
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Cidr {
#[cfg(feature = "proto-ipv4")]
Ipv4(Ipv4Cidr),
#[cfg(feature = "proto-ipv6")]
Ipv6(Ipv6Cidr),
}
impl Cidr {
pub fn new(addr: Address, prefix_len: u8) -> Cidr {
match addr {
#[cfg(feature = "proto-ipv4")]
Address::Ipv4(addr) => Cidr::Ipv4(Ipv4Cidr::new(addr, prefix_len)),
#[cfg(feature = "proto-ipv6")]
Address::Ipv6(addr) => Cidr::Ipv6(Ipv6Cidr::new(addr, prefix_len)),
}
}
pub const fn address(&self) -> Address {
match *self {
#[cfg(feature = "proto-ipv4")]
Cidr::Ipv4(cidr) => Address::Ipv4(cidr.address()),
#[cfg(feature = "proto-ipv6")]
Cidr::Ipv6(cidr) => Address::Ipv6(cidr.address()),
}
}
pub const fn prefix_len(&self) -> u8 {
match *self {
#[cfg(feature = "proto-ipv4")]
Cidr::Ipv4(cidr) => cidr.prefix_len(),
#[cfg(feature = "proto-ipv6")]
Cidr::Ipv6(cidr) => cidr.prefix_len(),
}
}
pub fn contains_addr(&self, addr: &Address) -> bool {
match (self, addr) {
#[cfg(feature = "proto-ipv4")]
(Cidr::Ipv4(cidr), Address::Ipv4(addr)) => cidr.contains_addr(addr),
#[cfg(feature = "proto-ipv6")]
(Cidr::Ipv6(cidr), Address::Ipv6(addr)) => cidr.contains_addr(addr),
#[allow(unreachable_patterns)]
_ => false,
}
}
pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
match (self, subnet) {
#[cfg(feature = "proto-ipv4")]
(Cidr::Ipv4(cidr), Cidr::Ipv4(other)) => cidr.contains_subnet(other),
#[cfg(feature = "proto-ipv6")]
(Cidr::Ipv6(cidr), Cidr::Ipv6(other)) => cidr.contains_subnet(other),
#[allow(unreachable_patterns)]
_ => false,
}
}
}
#[cfg(feature = "proto-ipv4")]
impl From<Ipv4Cidr> for Cidr {
fn from(addr: Ipv4Cidr) -> Self {
Cidr::Ipv4(addr)
}
}
#[cfg(feature = "proto-ipv6")]
impl From<Ipv6Cidr> for Cidr {
fn from(addr: Ipv6Cidr) -> Self {
Cidr::Ipv6(addr)
}
}
impl fmt::Display for Cidr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
#[cfg(feature = "proto-ipv4")]
Cidr::Ipv4(cidr) => write!(f, "{cidr}"),
#[cfg(feature = "proto-ipv6")]
Cidr::Ipv6(cidr) => write!(f, "{cidr}"),
}
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for Cidr {
fn format(&self, f: defmt::Formatter) {
match self {
#[cfg(feature = "proto-ipv4")]
&Cidr::Ipv4(cidr) => defmt::write!(f, "{:?}", cidr),
#[cfg(feature = "proto-ipv6")]
&Cidr::Ipv6(cidr) => defmt::write!(f, "{:?}", cidr),
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct Endpoint {
pub addr: Address,
pub port: u16,
}
impl Endpoint {
pub const fn new(addr: Address, port: u16) -> Endpoint {
Endpoint { addr: addr, port }
}
}
#[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
impl From<::std::net::SocketAddr> for Endpoint {
fn from(x: ::std::net::SocketAddr) -> Endpoint {
Endpoint {
addr: x.ip().into(),
port: x.port(),
}
}
}
#[cfg(all(feature = "std", feature = "proto-ipv4"))]
impl From<::std::net::SocketAddrV4> for Endpoint {
fn from(x: ::std::net::SocketAddrV4) -> Endpoint {
Endpoint {
addr: (*x.ip()).into(),
port: x.port(),
}
}
}
#[cfg(all(feature = "std", feature = "proto-ipv6"))]
impl From<::std::net::SocketAddrV6> for Endpoint {
fn from(x: ::std::net::SocketAddrV6) -> Endpoint {
Endpoint {
addr: (*x.ip()).into(),
port: x.port(),
}
}
}
impl fmt::Display for Endpoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.addr, self.port)
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for Endpoint {
fn format(&self, f: defmt::Formatter) {
defmt::write!(f, "{:?}:{=u16}", self.addr, self.port);
}
}
impl<T: Into<Address>> From<(T, u16)> for Endpoint {
fn from((addr, port): (T, u16)) -> Endpoint {
Endpoint {
addr: addr.into(),
port,
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
pub struct ListenEndpoint {
pub addr: Option<Address>,
pub port: u16,
}
impl ListenEndpoint {
pub const fn is_specified(&self) -> bool {
self.addr.is_some() && self.port != 0
}
}
#[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
impl From<::std::net::SocketAddr> for ListenEndpoint {
fn from(x: ::std::net::SocketAddr) -> ListenEndpoint {
ListenEndpoint {
addr: Some(x.ip().into()),
port: x.port(),
}
}
}
#[cfg(all(feature = "std", feature = "proto-ipv4"))]
impl From<::std::net::SocketAddrV4> for ListenEndpoint {
fn from(x: ::std::net::SocketAddrV4) -> ListenEndpoint {
ListenEndpoint {
addr: Some((*x.ip()).into()),
port: x.port(),
}
}
}
#[cfg(all(feature = "std", feature = "proto-ipv6"))]
impl From<::std::net::SocketAddrV6> for ListenEndpoint {
fn from(x: ::std::net::SocketAddrV6) -> ListenEndpoint {
ListenEndpoint {
addr: Some((*x.ip()).into()),
port: x.port(),
}
}
}
impl fmt::Display for ListenEndpoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(addr) = self.addr {
write!(f, "{}:{}", addr, self.port)
} else {
write!(f, "*:{}", self.port)
}
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for ListenEndpoint {
fn format(&self, f: defmt::Formatter) {
defmt::write!(f, "{:?}:{=u16}", self.addr, self.port);
}
}
impl From<u16> for ListenEndpoint {
fn from(port: u16) -> ListenEndpoint {
ListenEndpoint { addr: None, port }
}
}
impl From<Endpoint> for ListenEndpoint {
fn from(endpoint: Endpoint) -> ListenEndpoint {
ListenEndpoint {
addr: Some(endpoint.addr),
port: endpoint.port,
}
}
}
impl<T: Into<Address>> From<(T, u16)> for ListenEndpoint {
fn from((addr, port): (T, u16)) -> ListenEndpoint {
ListenEndpoint {
addr: Some(addr.into()),
port,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Repr {
#[cfg(feature = "proto-ipv4")]
Ipv4(Ipv4Repr),
#[cfg(feature = "proto-ipv6")]
Ipv6(Ipv6Repr),
}
#[cfg(feature = "proto-ipv4")]
impl From<Ipv4Repr> for Repr {
fn from(repr: Ipv4Repr) -> Repr {
Repr::Ipv4(repr)
}
}
#[cfg(feature = "proto-ipv6")]
impl From<Ipv6Repr> for Repr {
fn from(repr: Ipv6Repr) -> Repr {
Repr::Ipv6(repr)
}
}
impl Repr {
pub fn new(
src_addr: Address,
dst_addr: Address,
next_header: Protocol,
payload_len: usize,
hop_limit: u8,
) -> Self {
match (src_addr, dst_addr) {
#[cfg(feature = "proto-ipv4")]
(Address::Ipv4(src_addr), Address::Ipv4(dst_addr)) => Self::Ipv4(Ipv4Repr {
src_addr,
dst_addr,
next_header,
payload_len,
hop_limit,
}),
#[cfg(feature = "proto-ipv6")]
(Address::Ipv6(src_addr), Address::Ipv6(dst_addr)) => Self::Ipv6(Ipv6Repr {
src_addr,
dst_addr,
next_header,
payload_len,
hop_limit,
}),
#[allow(unreachable_patterns)]
_ => panic!("IP version mismatch: src={src_addr:?} dst={dst_addr:?}"),
}
}
pub const fn version(&self) -> Version {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(_) => Version::Ipv4,
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(_) => Version::Ipv6,
}
}
pub const fn src_addr(&self) -> Address {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(repr) => Address::Ipv4(repr.src_addr),
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(repr) => Address::Ipv6(repr.src_addr),
}
}
pub const fn dst_addr(&self) -> Address {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(repr) => Address::Ipv4(repr.dst_addr),
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(repr) => Address::Ipv6(repr.dst_addr),
}
}
pub const fn next_header(&self) -> Protocol {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(repr) => repr.next_header,
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(repr) => repr.next_header,
}
}
pub const fn payload_len(&self) -> usize {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(repr) => repr.payload_len,
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(repr) => repr.payload_len,
}
}
pub fn set_payload_len(&mut self, length: usize) {
match self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(Ipv4Repr { payload_len, .. }) => *payload_len = length,
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(Ipv6Repr { payload_len, .. }) => *payload_len = length,
}
}
pub const fn hop_limit(&self) -> u8 {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(Ipv4Repr { hop_limit, .. }) => hop_limit,
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(Ipv6Repr { hop_limit, .. }) => hop_limit,
}
}
pub const fn header_len(&self) -> usize {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(repr) => repr.buffer_len(),
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(repr) => repr.buffer_len(),
}
}
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(
&self,
buffer: T,
_checksum_caps: &ChecksumCapabilities,
) {
match *self {
#[cfg(feature = "proto-ipv4")]
Repr::Ipv4(repr) => repr.emit(&mut Ipv4Packet::new_unchecked(buffer), _checksum_caps),
#[cfg(feature = "proto-ipv6")]
Repr::Ipv6(repr) => repr.emit(&mut Ipv6Packet::new_unchecked(buffer)),
}
}
pub const fn buffer_len(&self) -> usize {
self.header_len() + self.payload_len()
}
}
pub mod checksum {
use byteorder::{ByteOrder, NetworkEndian};
use super::*;
const fn propagate_carries(word: u32) -> u16 {
let sum = (word >> 16) + (word & 0xffff);
((sum >> 16) as u16) + (sum as u16)
}
pub fn data(mut data: &[u8]) -> u16 {
let mut accum = 0;
const CHUNK_SIZE: usize = 32;
while data.len() >= CHUNK_SIZE {
let mut d = &data[..CHUNK_SIZE];
while d.len() >= 2 {
accum += NetworkEndian::read_u16(d) as u32;
d = &d[2..];
}
data = &data[CHUNK_SIZE..];
}
while data.len() >= 2 {
accum += NetworkEndian::read_u16(data) as u32;
data = &data[2..];
}
if let Some(&value) = data.first() {
accum += (value as u32) << 8;
}
propagate_carries(accum)
}
pub fn combine(checksums: &[u16]) -> u16 {
let mut accum: u32 = 0;
for &word in checksums {
accum += word as u32;
}
propagate_carries(accum)
}
pub fn pseudo_header(
src_addr: &Address,
dst_addr: &Address,
next_header: Protocol,
length: u32,
) -> u16 {
match (src_addr, dst_addr) {
#[cfg(feature = "proto-ipv4")]
(&Address::Ipv4(src_addr), &Address::Ipv4(dst_addr)) => {
let mut proto_len = [0u8; 4];
proto_len[1] = next_header.into();
NetworkEndian::write_u16(&mut proto_len[2..4], length as u16);
combine(&[
data(src_addr.as_bytes()),
data(dst_addr.as_bytes()),
data(&proto_len[..]),
])
}
#[cfg(feature = "proto-ipv6")]
(&Address::Ipv6(src_addr), &Address::Ipv6(dst_addr)) => {
let mut proto_len = [0u8; 8];
proto_len[7] = next_header.into();
NetworkEndian::write_u32(&mut proto_len[0..4], length);
combine(&[
data(src_addr.as_bytes()),
data(dst_addr.as_bytes()),
data(&proto_len[..]),
])
}
#[allow(unreachable_patterns)]
_ => panic!("Unexpected pseudo header addresses: {src_addr}, {dst_addr}"),
}
}
pub(crate) fn format_checksum(f: &mut fmt::Formatter, correct: bool) -> fmt::Result {
if !correct {
write!(f, " (checksum incorrect)")
} else {
Ok(())
}
}
}
use crate::wire::pretty_print::PrettyIndent;
pub fn pretty_print_ip_payload<T: Into<Repr>>(
f: &mut fmt::Formatter,
indent: &mut PrettyIndent,
ip_repr: T,
payload: &[u8],
) -> fmt::Result {
#[cfg(feature = "proto-ipv4")]
use super::pretty_print::PrettyPrint;
use crate::wire::ip::checksum::format_checksum;
#[cfg(feature = "proto-ipv4")]
use crate::wire::Icmpv4Packet;
use crate::wire::{TcpPacket, TcpRepr, UdpPacket, UdpRepr};
let checksum_caps = ChecksumCapabilities::ignored();
let repr = ip_repr.into();
match repr.next_header() {
#[cfg(feature = "proto-ipv4")]
Protocol::Icmp => {
indent.increase(f)?;
Icmpv4Packet::<&[u8]>::pretty_print(&payload, f, indent)
}
Protocol::Udp => {
indent.increase(f)?;
match UdpPacket::<&[u8]>::new_checked(payload) {
Err(err) => write!(f, "{indent}({err})"),
Ok(udp_packet) => {
match UdpRepr::parse(
&udp_packet,
&repr.src_addr(),
&repr.dst_addr(),
&checksum_caps,
) {
Err(err) => write!(f, "{indent}{udp_packet} ({err})"),
Ok(udp_repr) => {
write!(
f,
"{}{} len={}",
indent,
udp_repr,
udp_packet.payload().len()
)?;
let valid =
udp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
format_checksum(f, valid)
}
}
}
}
}
Protocol::Tcp => {
indent.increase(f)?;
match TcpPacket::<&[u8]>::new_checked(payload) {
Err(err) => write!(f, "{indent}({err})"),
Ok(tcp_packet) => {
match TcpRepr::parse(
&tcp_packet,
&repr.src_addr(),
&repr.dst_addr(),
&checksum_caps,
) {
Err(err) => write!(f, "{indent}{tcp_packet} ({err})"),
Ok(tcp_repr) => {
write!(f, "{indent}{tcp_repr}")?;
let valid =
tcp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
format_checksum(f, valid)
}
}
}
}
}
_ => Ok(()),
}
}
#[cfg(test)]
pub(crate) mod test {
#![allow(unused)]
#[cfg(feature = "proto-ipv6")]
pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
]));
#[cfg(feature = "proto-ipv6")]
pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
]));
#[cfg(feature = "proto-ipv6")]
pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
]));
#[cfg(feature = "proto-ipv6")]
pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv6(Ipv6Address([
0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
]));
#[cfg(feature = "proto-ipv6")]
pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv6(Ipv6Address::UNSPECIFIED);
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
pub(crate) const MOCK_IP_ADDR_1: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 1]));
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
pub(crate) const MOCK_IP_ADDR_2: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 2]));
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
pub(crate) const MOCK_IP_ADDR_3: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 3]));
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
pub(crate) const MOCK_IP_ADDR_4: IpAddress = IpAddress::Ipv4(Ipv4Address([192, 168, 1, 4]));
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
pub(crate) const MOCK_UNSPECIFIED: IpAddress = IpAddress::Ipv4(Ipv4Address::UNSPECIFIED);
use super::*;
use crate::wire::{IpAddress, IpCidr, IpProtocol};
#[cfg(feature = "proto-ipv4")]
use crate::wire::{Ipv4Address, Ipv4Repr};
#[test]
#[cfg(feature = "proto-ipv4")]
fn to_prefix_len_ipv4() {
fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
assert_eq!(Some(prefix_len), mask.into().prefix_len());
}
test_eq(0, Ipv4Address::new(0, 0, 0, 0));
test_eq(1, Ipv4Address::new(128, 0, 0, 0));
test_eq(2, Ipv4Address::new(192, 0, 0, 0));
test_eq(3, Ipv4Address::new(224, 0, 0, 0));
test_eq(4, Ipv4Address::new(240, 0, 0, 0));
test_eq(5, Ipv4Address::new(248, 0, 0, 0));
test_eq(6, Ipv4Address::new(252, 0, 0, 0));
test_eq(7, Ipv4Address::new(254, 0, 0, 0));
test_eq(8, Ipv4Address::new(255, 0, 0, 0));
test_eq(9, Ipv4Address::new(255, 128, 0, 0));
test_eq(10, Ipv4Address::new(255, 192, 0, 0));
test_eq(11, Ipv4Address::new(255, 224, 0, 0));
test_eq(12, Ipv4Address::new(255, 240, 0, 0));
test_eq(13, Ipv4Address::new(255, 248, 0, 0));
test_eq(14, Ipv4Address::new(255, 252, 0, 0));
test_eq(15, Ipv4Address::new(255, 254, 0, 0));
test_eq(16, Ipv4Address::new(255, 255, 0, 0));
test_eq(17, Ipv4Address::new(255, 255, 128, 0));
test_eq(18, Ipv4Address::new(255, 255, 192, 0));
test_eq(19, Ipv4Address::new(255, 255, 224, 0));
test_eq(20, Ipv4Address::new(255, 255, 240, 0));
test_eq(21, Ipv4Address::new(255, 255, 248, 0));
test_eq(22, Ipv4Address::new(255, 255, 252, 0));
test_eq(23, Ipv4Address::new(255, 255, 254, 0));
test_eq(24, Ipv4Address::new(255, 255, 255, 0));
test_eq(25, Ipv4Address::new(255, 255, 255, 128));
test_eq(26, Ipv4Address::new(255, 255, 255, 192));
test_eq(27, Ipv4Address::new(255, 255, 255, 224));
test_eq(28, Ipv4Address::new(255, 255, 255, 240));
test_eq(29, Ipv4Address::new(255, 255, 255, 248));
test_eq(30, Ipv4Address::new(255, 255, 255, 252));
test_eq(31, Ipv4Address::new(255, 255, 255, 254));
test_eq(32, Ipv4Address::new(255, 255, 255, 255));
}
#[test]
#[cfg(feature = "proto-ipv4")]
fn to_prefix_len_ipv4_error() {
assert_eq!(
None,
IpAddress::from(Ipv4Address::new(255, 255, 255, 1)).prefix_len()
);
}
#[test]
#[cfg(feature = "proto-ipv6")]
fn to_prefix_len_ipv6() {
fn test_eq<A: Into<Address>>(prefix_len: u8, mask: A) {
assert_eq!(Some(prefix_len), mask.into().prefix_len());
}
test_eq(0, Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 0));
test_eq(
128,
Ipv6Address::new(
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
),
);
}
#[test]
#[cfg(feature = "proto-ipv6")]
fn to_prefix_len_ipv6_error() {
assert_eq!(
None,
IpAddress::from(Ipv6Address::new(
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0, 1
))
.prefix_len()
);
}
}