diff --git a/.travis.yml b/.travis.yml index 41d5a7f1f..5e3e4952b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,28 +10,31 @@ matrix: ### Test default configurations - rust: nightly env: FEATURES='default' MODE='test' - - rust: nightly - env: FEATURES='default proto-ipv6' MODE='test' ### Test select feature permutations, chosen to be as orthogonal as possible - rust: nightly - env: FEATURES='std phy-raw_socket socket-udp' MODE='test' + env: FEATURES='std phy-raw_socket proto-ipv6 socket-udp' MODE='test' + - rust: nightly + env: FEATURES='std phy-tap_interface proto-ipv6 socket-udp' MODE='test' - rust: nightly - env: FEATURES='std phy-tap_interface socket-udp' MODE='test' + env: FEATURES='std proto-ipv4 socket-raw' MODE='test' - rust: nightly - env: FEATURES='std socket-raw' MODE='test' + env: FEATURES='std proto-ipv6 socket-udp' MODE='test' - rust: nightly - env: FEATURES='std socket-udp' MODE='test' + env: FEATURES='std proto-ipv6 socket-tcp' MODE='test' - rust: nightly - env: FEATURES='std socket-tcp' MODE='test' + env: FEATURES='std proto-ipv4 socket-icmp socket-tcp' MODE='test' - rust: nightly - env: FEATURES='std socket-icmp' MODE='test' + env: FEATURES='std proto-ipv6 socket-icmp socket-tcp' MODE='test' ### Test select feature permutations, chosen to be as aggressive as possible - rust: nightly - env: FEATURES='socket-raw socket-udp socket-tcp socket-icmp std' MODE='test' + env: FEATURES='proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp std' + MODE='test' - rust: nightly - env: FEATURES='socket-raw socket-udp socket-tcp socket-icmp alloc' MODE='test' + env: FEATURES='proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp alloc' + MODE='test' - rust: nightly - env: FEATURES='socket-raw socket-udp socket-tcp socket-icmp' MODE='build' + env: FEATURES='proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp' + MODE='build' script: - cargo "$MODE" --no-default-features --features "$FEATURES" notifications: diff --git a/Cargo.toml b/Cargo.toml index 23e49c1e5..fa7967431 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ alloc = ["managed/alloc"] verbose = [] "phy-raw_socket" = ["std", "libc"] "phy-tap_interface" = ["std", "libc"] +"proto-ipv4" = [] "proto-ipv6" = [] "socket-raw" = [] "socket-udp" = [] @@ -42,36 +43,37 @@ verbose = [] default = [ "std", "log", # needed for `cargo test --no-default-features --features default` :/ "phy-raw_socket", "phy-tap_interface", + "proto-ipv4", "proto-ipv6", "socket-raw", "socket-icmp", "socket-udp", "socket-tcp" ] [[example]] name = "tcpdump" -required-features = ["std", "phy-raw_socket"] +required-features = ["std", "phy-raw_socket", "proto-ipv4"] [[example]] name = "httpclient" -required-features = ["std", "phy-tap_interface", "socket-tcp"] +required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-tcp"] [[example]] name = "ping" -required-features = ["std", "phy-tap_interface", "socket-icmp"] +required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-icmp"] [[example]] name = "server" -required-features = ["std", "phy-tap_interface", "socket-tcp", "socket-udp"] +required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-tcp", "socket-udp"] [[example]] name = "client" -required-features = ["std", "phy-tap_interface", "socket-tcp", "socket-udp"] +required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-tcp", "socket-udp"] [[example]] name = "loopback" -required-features = ["log", "socket-tcp"] +required-features = ["log", "proto-ipv4", "socket-tcp"] [[example]] name = "benchmark" -required-features = ["std", "phy-tap_interface", "socket-tcp"] +required-features = ["std", "phy-tap_interface", "proto-ipv4", "socket-tcp"] [profile.release] debug = 2 diff --git a/README.md b/README.md index 6c1aecd1a..0f3e47858 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,13 @@ and `smoltcp::socket::TcpSocket`, respectively. These features are enabled by default. +### Features `proto-ipv4` and `proto-ipv6` + +Enable [IPv4] and [IPv6] respectively. + +[IPv4]: https://tools.ietf.org/rfc/rfc791.txt +[IPv6]: https://tools.ietf.org/rfc/rfc8200.txt + ## Hosted usage examples _smoltcp_, being a freestanding networking stack, needs to be able to transmit and receive diff --git a/src/iface/ethernet.rs b/src/iface/ethernet.rs index 1cb341088..ad5d3200d 100644 --- a/src/iface/ethernet.rs +++ b/src/iface/ethernet.rs @@ -8,10 +8,14 @@ use {Error, Result}; use phy::{Device, DeviceCapabilities, RxToken, TxToken}; use wire::pretty_print::PrettyPrinter; use wire::{EthernetAddress, EthernetProtocol, EthernetFrame}; +#[cfg(feature = "proto-ipv4")] use wire::{Ipv4Address}; use wire::{IpAddress, IpProtocol, IpRepr, IpCidr}; +#[cfg(feature = "proto-ipv4")] use wire::{ArpPacket, ArpRepr, ArpOperation}; +#[cfg(feature = "proto-ipv4")] use wire::{Ipv4Packet, Ipv4Repr}; +#[cfg(feature = "proto-ipv4")] use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable}; #[cfg(feature = "socket-udp")] use wire::{UdpPacket, UdpRepr}; @@ -21,7 +25,7 @@ use wire::{TcpPacket, TcpRepr, TcpControl}; use socket::{Socket, SocketSet, AnySocket}; #[cfg(feature = "socket-raw")] use socket::RawSocket; -#[cfg(feature = "socket-icmp")] +#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] use socket::IcmpSocket; #[cfg(feature = "socket-udp")] use socket::UdpSocket; @@ -50,6 +54,7 @@ struct InterfaceInner<'b, 'c> { neighbor_cache: NeighborCache<'b>, ethernet_addr: EthernetAddress, ip_addrs: ManagedSlice<'c, IpCidr>, + #[cfg(feature = "proto-ipv4")] ipv4_gateway: Option, device_capabilities: DeviceCapabilities, } @@ -61,6 +66,7 @@ pub struct InterfaceBuilder <'b, 'c, DeviceT: for<'d> Device<'d>> { ethernet_addr: Option, neighbor_cache: Option>, ip_addrs: ManagedSlice<'c, IpCidr>, + #[cfg(feature = "proto-ipv4")] ipv4_gateway: Option, } @@ -97,6 +103,7 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT> ethernet_addr: None, neighbor_cache: None, ip_addrs: ManagedSlice::Borrowed(&mut []), + #[cfg(feature = "proto-ipv4")] ipv4_gateway: None } } @@ -122,7 +129,7 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT> /// /// [ip_addrs]: struct.EthernetInterface.html#method.ip_addrs pub fn ip_addrs(mut self, ip_addrs: T) -> InterfaceBuilder<'b, 'c, DeviceT> - where T: Into> + where T: Into> { let ip_addrs = ip_addrs.into(); InterfaceInner::check_ip_addrs(&ip_addrs); @@ -137,8 +144,9 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT> /// This function panics if the given address is not unicast. /// /// [ipv4_gateway]: struct.EthernetInterface.html#method.ipv4_gateway + #[cfg(feature = "proto-ipv4")] pub fn ipv4_gateway(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT> - where T: Into + where T: Into { let addr = gateway.into(); InterfaceInner::check_gateway_addr(&addr); @@ -172,7 +180,9 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT> device: self.device, inner: InterfaceInner { ethernet_addr, device_capabilities, neighbor_cache, - ip_addrs: self.ip_addrs, ipv4_gateway: self.ipv4_gateway, + ip_addrs: self.ip_addrs, + #[cfg(feature = "proto-ipv4")] + ipv4_gateway: self.ipv4_gateway, } } }, @@ -184,7 +194,9 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT> #[derive(Debug, PartialEq)] enum Packet<'a> { None, + #[cfg(feature = "proto-ipv4")] Arp(ArpRepr), + #[cfg(feature = "proto-ipv4")] Icmpv4((Ipv4Repr, Icmpv4Repr<'a>)), #[cfg(feature = "socket-raw")] Raw((IpRepr, &'a [u8])), @@ -197,7 +209,10 @@ enum Packet<'a> { impl<'a> Packet<'a> { fn neighbor_addr(&self) -> Option { match self { - &Packet::None | &Packet::Arp(_) => None, + &Packet::None => None, + #[cfg(feature = "proto-ipv4")] + &Packet::Arp(_) => None, + #[cfg(feature = "proto-ipv4")] &Packet::Icmpv4((ref ipv4_repr, _)) => Some(ipv4_repr.dst_addr.into()), #[cfg(feature = "socket-raw")] &Packet::Raw((ref ip_repr, _)) => Some(ip_repr.dst_addr()), @@ -245,6 +260,7 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> } /// Get the IPv4 gateway of the interface. + #[cfg(feature = "proto-ipv4")] pub fn ipv4_gateway(&self) -> Option { self.inner.ipv4_gateway } @@ -253,6 +269,7 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> /// /// # Panics /// This function panics if the given address is not unicast. + #[cfg(feature = "proto-ipv4")] pub fn set_ipv4_gateway(&mut self, gateway: GatewayAddrT) where GatewayAddrT: Into> { self.inner.ipv4_gateway = gateway.into(); @@ -376,11 +393,12 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> device_result = inner.dispatch(tx_token, timestamp, response); device_result }, &caps.checksum), - #[cfg(feature = "socket-icmp")] + #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] Socket::Icmp(ref mut socket) => socket.dispatch(&caps, |response| { let tx_token = device.transmit().ok_or(Error::Exhausted)?; device_result = match response { + #[cfg(feature = "proto-ipv4")] (IpRepr::Ipv4(ipv4_repr), icmpv4_repr) => { let response = Packet::Icmpv4((ipv4_repr, icmpv4_repr)); neighbor_addr = response.neighbor_addr(); @@ -449,6 +467,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } } + #[cfg(feature = "proto-ipv4")] fn check_gateway_addr(addr: &Ipv4Address) { if !addr.is_unicast() { panic!("gateway IP address {} is not unicast", addr); @@ -474,8 +493,10 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } match eth_frame.ethertype() { + #[cfg(feature = "proto-ipv4")] EthernetProtocol::Arp => self.process_arp(timestamp, ð_frame), + #[cfg(feature = "proto-ipv4")] EthernetProtocol::Ipv4 => self.process_ipv4(sockets, timestamp, ð_frame), // Drop all other traffic. @@ -483,6 +504,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } } + #[cfg(feature = "proto-ipv4")] fn process_arp<'frame, T: AsRef<[u8]>> (&mut self, timestamp: u64, eth_frame: &EthernetFrame<&'frame T>) -> Result> @@ -524,6 +546,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } } + #[cfg(feature = "proto-ipv4")] fn process_ipv4<'frame, T: AsRef<[u8]>> (&mut self, sockets: &mut SocketSet, timestamp: u64, eth_frame: &EthernetFrame<&'frame T>) -> @@ -603,6 +626,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } } + #[cfg(feature = "proto-ipv4")] fn process_icmpv4<'frame>(&self, _sockets: &mut SocketSet, ip_repr: IpRepr, ip_payload: &'frame [u8]) -> Result> { @@ -613,7 +637,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { #[cfg(feature = "socket-icmp")] let mut handled_by_icmp_socket = false; - #[cfg(feature = "socket-icmp")] + #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] for mut icmp_socket in _sockets.iter_mut().filter_map(IcmpSocket::downcast) { if !icmp_socket.accepts(&ip_repr, &icmp_repr, &checksum_caps) { continue } @@ -654,6 +678,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } } + #[cfg(feature = "proto-ipv4")] fn icmpv4_reply<'frame, 'icmp: 'frame> (&self, ipv4_repr: Ipv4Repr, icmp_repr: Icmpv4Repr<'icmp>) -> Packet<'frame> @@ -696,6 +721,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { // The packet wasn't handled by a socket, send an ICMP port unreachable packet. match ip_repr { + #[cfg(feature = "proto-ipv4")] IpRepr::Ipv4(ipv4_repr) => { // Send back as much of the original payload as we can let payload_len = cmp::min( @@ -710,8 +736,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { #[cfg(feature = "proto-ipv6")] IpRepr::Ipv6(_) => Err(Error::Unaddressable), IpRepr::Unspecified { .. } | - IpRepr::__Nonexhaustive => - unreachable!() + IpRepr::__Nonexhaustive => Err(Error::Unaddressable), } } @@ -752,6 +777,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { { let checksum_caps = self.device_capabilities.checksum.clone(); match packet { + #[cfg(feature = "proto-ipv4")] Packet::Arp(arp_repr) => { let dst_hardware_addr = match arp_repr { @@ -767,6 +793,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { arp_repr.emit(&mut packet); }) }, + #[cfg(feature = "proto-ipv4")] Packet::Icmpv4((ipv4_repr, icmpv4_repr)) => { self.dispatch_ip(tx_token, timestamp, IpRepr::Ipv4(ipv4_repr), |_ip_repr, payload| { @@ -849,8 +876,12 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } // Route via a gateway. - match (addr, self.ipv4_gateway) { - (&IpAddress::Ipv4(_), Some(gateway)) => Ok(gateway.into()), + match addr { + #[cfg(feature = "proto-ipv4")] + &IpAddress::Ipv4(_) => match self.ipv4_gateway { + Some(gateway) => Ok(gateway.into()), + None => Err(Error::Unaddressable), + } _ => Err(Error::Unaddressable) } } @@ -882,6 +913,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } match (src_addr, dst_addr) { + #[cfg(feature = "proto-ipv4")] (&IpAddress::Ipv4(src_addr), IpAddress::Ipv4(dst_addr)) => { net_debug!("address {} not in neighbor cache, sending ARP request", dst_addr); @@ -903,7 +935,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { Err(Error::Unaddressable) } - _ => unreachable!() + _ => Err(Error::Unaddressable) } } @@ -921,8 +953,11 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { self.dispatch_ethernet(tx_token, timestamp, ip_repr.total_len(), |mut frame| { frame.set_dst_addr(dst_hardware_addr); match ip_repr { + #[cfg(feature = "proto-ipv4")] IpRepr::Ipv4(_) => frame.set_ethertype(EthernetProtocol::Ipv4), - _ => unreachable!() + #[cfg(feature = "proto-ipv6")] + IpRepr::Ipv6(_) => frame.set_ethertype(EthernetProtocol::Ipv6), + _ => return } ip_repr.emit(frame.payload_mut(), &checksum_caps); @@ -934,6 +969,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> { } #[cfg(test)] +#[cfg(feature = "proto-ipv4")] mod test { use std::collections::BTreeMap; use {Result, Error}; @@ -1300,7 +1336,7 @@ mod test { } #[test] - #[cfg(feature = "socket-icmp")] + #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] fn test_icmpv4_socket() { use socket::{IcmpPacketBuffer, IcmpSocket, IcmpSocketBuffer, IcmpEndpoint}; use wire::Icmpv4Packet; diff --git a/src/iface/neighbor.rs b/src/iface/neighbor.rs index fbfd527e4..3261247ae 100644 --- a/src/iface/neighbor.rs +++ b/src/iface/neighbor.rs @@ -157,81 +157,80 @@ impl<'a> Cache<'a> { #[cfg(test)] mod test { - use wire::Ipv4Address; use super::*; + use wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3, MOCK_IP_ADDR_4}; const HADDR_A: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 1]); const HADDR_B: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 2]); const HADDR_C: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 3]); const HADDR_D: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 4]); - const PADDR_A: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 1])); - const PADDR_B: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 2])); - const PADDR_C: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 3])); - const PADDR_D: IpAddress = IpAddress::Ipv4(Ipv4Address([1, 0, 0, 4])); - #[test] + #[cfg(feature = "proto-ipv4")] fn test_fill() { let mut cache_storage = [Default::default(); 3]; let mut cache = Cache::new(&mut cache_storage[..]); - assert_eq!(cache.lookup_pure(&PADDR_A, 0), None); - assert_eq!(cache.lookup_pure(&PADDR_B, 0), None); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), None); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 0), None); - cache.fill(PADDR_A, HADDR_A, 0); - assert_eq!(cache.lookup_pure(&PADDR_A, 0), Some(HADDR_A)); - assert_eq!(cache.lookup_pure(&PADDR_B, 0), None); - assert_eq!(cache.lookup_pure(&PADDR_A, 2 * Cache::ENTRY_LIFETIME), None); + cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_A)); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 0), None); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 2 * Cache::ENTRY_LIFETIME), None); - cache.fill(PADDR_A, HADDR_A, 0); - assert_eq!(cache.lookup_pure(&PADDR_B, 0), None); + cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 0), None); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_expire() { let mut cache_storage = [Default::default(); 3]; let mut cache = Cache::new(&mut cache_storage[..]); - cache.fill(PADDR_A, HADDR_A, 0); - assert_eq!(cache.lookup_pure(&PADDR_A, 0), Some(HADDR_A)); - assert_eq!(cache.lookup_pure(&PADDR_A, 2 * Cache::ENTRY_LIFETIME), None); + cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_A)); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 2 * Cache::ENTRY_LIFETIME), None); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_replace() { let mut cache_storage = [Default::default(); 3]; let mut cache = Cache::new(&mut cache_storage[..]); - cache.fill(PADDR_A, HADDR_A, 0); - assert_eq!(cache.lookup_pure(&PADDR_A, 0), Some(HADDR_A)); - cache.fill(PADDR_A, HADDR_B, 0); - assert_eq!(cache.lookup_pure(&PADDR_A, 0), Some(HADDR_B)); + cache.fill(MOCK_IP_ADDR_1, HADDR_A, 0); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_A)); + cache.fill(MOCK_IP_ADDR_1, HADDR_B, 0); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_1, 0), Some(HADDR_B)); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_evict() { let mut cache_storage = [Default::default(); 3]; let mut cache = Cache::new(&mut cache_storage[..]); - cache.fill(PADDR_A, HADDR_A, 100); - cache.fill(PADDR_B, HADDR_B, 50); - cache.fill(PADDR_C, HADDR_C, 200); - assert_eq!(cache.lookup_pure(&PADDR_B, 1000), Some(HADDR_B)); - assert_eq!(cache.lookup_pure(&PADDR_D, 1000), None); + cache.fill(MOCK_IP_ADDR_1, HADDR_A, 100); + cache.fill(MOCK_IP_ADDR_2, HADDR_B, 50); + cache.fill(MOCK_IP_ADDR_3, HADDR_C, 200); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 1000), Some(HADDR_B)); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_4, 1000), None); - cache.fill(PADDR_D, HADDR_D, 300); - assert_eq!(cache.lookup_pure(&PADDR_B, 1000), None); - assert_eq!(cache.lookup_pure(&PADDR_D, 1000), Some(HADDR_D)); + cache.fill(MOCK_IP_ADDR_4, HADDR_D, 300); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_2, 1000), None); + assert_eq!(cache.lookup_pure(&MOCK_IP_ADDR_4, 1000), Some(HADDR_D)); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_hush() { let mut cache_storage = [Default::default(); 3]; let mut cache = Cache::new(&mut cache_storage[..]); - assert_eq!(cache.lookup(&PADDR_A, 0), Answer::NotFound); - assert_eq!(cache.lookup(&PADDR_A, 100), Answer::RateLimited); - assert_eq!(cache.lookup(&PADDR_A, 2000), Answer::NotFound); + assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, 0), Answer::NotFound); + assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, 100), Answer::RateLimited); + assert_eq!(cache.lookup(&MOCK_IP_ADDR_1, 2000), Answer::NotFound); } } - diff --git a/src/lib.rs b/src/lib.rs index 90f980d57..54ef59bd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ #![cfg_attr(feature = "alloc", feature(alloc))] #![no_std] -#![deny(unsafe_code, unused)] +#![deny(unsafe_code)] +// TODO: Change this to enable deny(unused) if IPv6 or IPv4 are enabled +#![cfg_attr(feature = "proto-ipv4", deny(unused))] //! The _smoltcp_ library is built in a layered structure, with the layers corresponding //! to the levels of API abstraction. Only the highest layers would be used by a typical diff --git a/src/parsers.rs b/src/parsers.rs index 8315c08dc..3522dc4f4 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -1,9 +1,10 @@ -#![cfg_attr(not(feature = "proto-ipv6"), allow(dead_code))] +#![cfg_attr(not(all(feature = "proto-ipv6", feature = "proto-ipv4")), allow(dead_code))] use core::str::FromStr; use core::result; use wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint}; +#[cfg(feature = "proto-ipv4")] use wire::{Ipv4Address, Ipv4Cidr}; #[cfg(feature = "proto-ipv6")] use wire::{Ipv6Address, Ipv6Cidr}; @@ -236,6 +237,7 @@ impl<'a> Parser<'a> { Ok(Ipv6Address::from_parts(&addr)) } + #[cfg(feature = "proto-ipv4")] fn accept_ipv4(&mut self) -> Result { let mut octets = [0u8; 4]; for n in 0..4 { @@ -248,8 +250,10 @@ impl<'a> Parser<'a> { } fn accept_ip(&mut self) -> Result { - if let Some(ipv4) = self.try(|p| p.accept_ipv4()) { - return Ok(IpAddress::Ipv4(ipv4)) + #[cfg(feature = "proto-ipv4")] + match self.try(|p| p.accept_ipv4()) { + Some(ipv4) => return Ok(IpAddress::Ipv4(ipv4)), + None => () } #[cfg(feature = "proto-ipv6")] @@ -261,6 +265,7 @@ impl<'a> Parser<'a> { Err(()) } + #[cfg(feature = "proto-ipv4")] fn accept_ipv4_endpoint(&mut self) -> Result { let ip = self.accept_ipv4()?; @@ -275,7 +280,7 @@ impl<'a> Parser<'a> { } #[cfg(feature = "proto-ipv6")] - fn accept_ipv6_endpoint(&mut self, is_cidr: bool) -> Result { + fn accept_ipv6_endpoint(&mut self) -> Result { if self.lookahead_char(b'[') { self.accept_char(b'[')?; let ip = self.accept_ipv6(false)?; @@ -285,18 +290,20 @@ impl<'a> Parser<'a> { Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: port as u16 }) } else { - let ip = self.accept_ipv6(is_cidr)?; + let ip = self.accept_ipv6(false)?; Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: 0 }) } } fn accept_ip_endpoint(&mut self) -> Result { - if let Some(ipv4) = self.try(|p| p.accept_ipv4_endpoint()) { - return Ok(ipv4) + #[cfg(feature = "proto-ipv4")] + match self.try(|p| p.accept_ipv4_endpoint()) { + Some(ipv4) => return Ok(ipv4), + None => () } #[cfg(feature = "proto-ipv6")] - match self.try(|p| p.accept_ipv6_endpoint(false)) { + match self.try(|p| p.accept_ipv6_endpoint()) { Some(ipv6) => return Ok(ipv6), None => () } @@ -314,6 +321,7 @@ impl FromStr for EthernetAddress { } } +#[cfg(feature = "proto-ipv4")] impl FromStr for Ipv4Address { type Err = (); @@ -342,6 +350,7 @@ impl FromStr for IpAddress { } } +#[cfg(feature = "proto-ipv4")] impl FromStr for Ipv4Cidr { type Err = (); @@ -377,8 +386,10 @@ impl FromStr for IpCidr { /// Parse a string representation of an IP CIDR. fn from_str(s: &str) -> Result { - if let Ok(ipv4) = Ipv4Cidr::from_str(s) { - return Ok(IpCidr::Ipv4(ipv4)) + #[cfg(feature = "proto-ipv4")] + match Ipv4Cidr::from_str(s) { + Ok(cidr) => return Ok(IpCidr::Ipv4(cidr)), + Err(_) => () } #[cfg(feature = "proto-ipv6")] @@ -419,6 +430,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_mac() { assert_eq!(EthernetAddress::from_str(""), Err(())); assert_eq!(EthernetAddress::from_str("02:00:00:00:00:00"), @@ -440,6 +452,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_ipv4() { assert_eq!(Ipv4Address::from_str(""), Err(())); assert_eq!(Ipv4Address::from_str("1.2.3.4"), @@ -500,6 +513,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_ip_ipv4() { assert_eq!(IpAddress::from_str(""), Err(())); assert_eq!(IpAddress::from_str("1.2.3.4"), @@ -517,6 +531,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_cidr_ipv4() { let tests = [ ("127.0.0.1/8", @@ -564,6 +579,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_endpoint_ipv4() { assert_eq!(IpEndpoint::from_str(""), Err(())); assert_eq!(IpEndpoint::from_str("x"), Err(())); diff --git a/src/socket/mod.rs b/src/socket/mod.rs index f3e355f6e..1a6d2b442 100644 --- a/src/socket/mod.rs +++ b/src/socket/mod.rs @@ -15,7 +15,7 @@ use core::marker::PhantomData; mod meta; #[cfg(feature = "socket-raw")] mod raw; -#[cfg(feature = "socket-icmp")] +#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] mod icmp; #[cfg(feature = "socket-udp")] mod udp; @@ -31,7 +31,7 @@ pub use self::raw::{PacketBuffer as RawPacketBuffer, SocketBuffer as RawSocketBuffer, RawSocket}; -#[cfg(feature = "socket-icmp")] +#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] pub use self::icmp::{PacketBuffer as IcmpPacketBuffer, SocketBuffer as IcmpSocketBuffer, Endpoint as IcmpEndpoint, @@ -67,7 +67,7 @@ pub(crate) use self::ref_::Session as SocketSession; pub enum Socket<'a, 'b: 'a> { #[cfg(feature = "socket-raw")] Raw(RawSocket<'a, 'b>), - #[cfg(feature = "socket-icmp")] + #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] Icmp(IcmpSocket<'a, 'b>), #[cfg(feature = "socket-udp")] Udp(UdpSocket<'a, 'b>), @@ -82,7 +82,7 @@ macro_rules! dispatch_socket { match $self_ { #[cfg(feature = "socket-raw")] &$( $mut_ )* Socket::Raw(ref $( $mut_ )* $socket) => $code, - #[cfg(feature = "socket-icmp")] + #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] &$( $mut_ )* Socket::Icmp(ref $( $mut_ )* $socket) => $code, #[cfg(feature = "socket-udp")] &$( $mut_ )* Socket::Udp(ref $( $mut_ )* $socket) => $code, @@ -141,7 +141,7 @@ macro_rules! from_socket { #[cfg(feature = "socket-raw")] from_socket!(RawSocket<'a, 'b>, Raw); -#[cfg(feature = "socket-icmp")] +#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] from_socket!(IcmpSocket<'a, 'b>, Icmp); #[cfg(feature = "socket-udp")] from_socket!(UdpSocket<'a, 'b>, Udp); diff --git a/src/socket/raw.rs b/src/socket/raw.rs index 014d04738..7408b0715 100644 --- a/src/socket/raw.rs +++ b/src/socket/raw.rs @@ -3,7 +3,9 @@ use managed::Managed; use {Error, Result}; use phy::ChecksumCapabilities; -use wire::{IpVersion, IpRepr, IpProtocol, Ipv4Repr, Ipv4Packet}; +use wire::{IpVersion, IpRepr, IpProtocol}; +#[cfg(feature = "proto-ipv4")] +use wire::{Ipv4Repr, Ipv4Packet}; use socket::{Socket, SocketMeta, SocketHandle}; use storage::{Resettable, RingBuffer}; @@ -187,6 +189,7 @@ impl<'a, 'b> RawSocket<'a, 'b> { fn prepare<'a>(protocol: IpProtocol, buffer: &'a mut [u8], checksum_caps: &ChecksumCapabilities) -> Result<(IpRepr, &'a [u8])> { match IpVersion::of_packet(buffer.as_ref())? { + #[cfg(feature = "proto-ipv4")] IpVersion::Ipv4 => { let mut packet = Ipv4Packet::new_checked(buffer.as_mut())?; if packet.protocol() != protocol { return Err(Error::Unaddressable) } @@ -241,6 +244,7 @@ impl<'a, 'b> RawSocket<'a, 'b> { #[cfg(test)] mod test { + #[cfg(feature = "proto-ipv4")] use wire::{Ipv4Address, IpRepr, Ipv4Repr}; use super::*; @@ -252,81 +256,89 @@ mod test { SocketBuffer::new(storage) } - fn socket(rx_buffer: SocketBuffer<'static, 'static>, - tx_buffer: SocketBuffer<'static, 'static>) - -> RawSocket<'static, 'static> { - match RawSocket::new(IpVersion::Ipv4, IpProtocol::Unknown(IP_PROTO), - rx_buffer, tx_buffer) { - Socket::Raw(socket) => socket, - _ => unreachable!() + #[cfg(feature = "proto-ipv4")] + mod ipv4_locals { + use super::*; + + pub fn socket(rx_buffer: SocketBuffer<'static, 'static>, + tx_buffer: SocketBuffer<'static, 'static>) + -> RawSocket<'static, 'static> { + match RawSocket::new(IpVersion::Ipv4, IpProtocol::Unknown(IP_PROTO), + rx_buffer, tx_buffer) { + Socket::Raw(socket) => socket, + _ => unreachable!() + } } - } - const IP_PROTO: u8 = 63; - const HEADER_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr { - src_addr: Ipv4Address([10, 0, 0, 1]), - dst_addr: Ipv4Address([10, 0, 0, 2]), - protocol: IpProtocol::Unknown(IP_PROTO), - payload_len: 4, - hop_limit: 64 - }); - const PACKET_BYTES: [u8; 24] = [ - 0x45, 0x00, 0x00, 0x18, - 0x00, 0x00, 0x40, 0x00, - 0x40, 0x3f, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x01, - 0x0a, 0x00, 0x00, 0x02, - 0xaa, 0x00, 0x00, 0xff - ]; - const PACKET_PAYLOAD: [u8; 4] = [ - 0xaa, 0x00, 0x00, 0xff - ]; + pub const IP_PROTO: u8 = 63; + pub const HEADER_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr { + src_addr: Ipv4Address([10, 0, 0, 1]), + dst_addr: Ipv4Address([10, 0, 0, 2]), + protocol: IpProtocol::Unknown(IP_PROTO), + payload_len: 4, + hop_limit: 64 + }); + pub const PACKET_BYTES: [u8; 24] = [ + 0x45, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x40, 0x00, + 0x40, 0x3f, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x01, + 0x0a, 0x00, 0x00, 0x02, + 0xaa, 0x00, 0x00, 0xff + ]; + pub const PACKET_PAYLOAD: [u8; 4] = [ + 0xaa, 0x00, 0x00, 0xff + ]; + } #[test] + #[cfg(feature = "proto-ipv4")] fn test_send_truncated() { - let mut socket = socket(buffer(0), buffer(1)); + let mut socket = ipv4_locals::socket(buffer(0), buffer(1)); assert_eq!(socket.send_slice(&[0; 32][..]), Err(Error::Truncated)); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_send_dispatch() { - let mut socket = socket(buffer(0), buffer(1)); + let mut socket = ipv4_locals::socket(buffer(0), buffer(1)); assert!(socket.can_send()); assert_eq!(socket.dispatch(|_| unreachable!(), &ChecksumCapabilities::default()), Err(Error::Exhausted)); - assert_eq!(socket.send_slice(&PACKET_BYTES[..]), Ok(())); + assert_eq!(socket.send_slice(&ipv4_locals::PACKET_BYTES[..]), Ok(())); assert_eq!(socket.send_slice(b""), Err(Error::Exhausted)); assert!(!socket.can_send()); assert_eq!(socket.dispatch(|(ip_repr, ip_payload)| { - assert_eq!(ip_repr, HEADER_REPR); - assert_eq!(ip_payload, &PACKET_PAYLOAD); + assert_eq!(ip_repr, ipv4_locals::HEADER_REPR); + assert_eq!(ip_payload, &ipv4_locals::PACKET_PAYLOAD); Err(Error::Unaddressable) }, &ChecksumCapabilities::default()), Err(Error::Unaddressable)); assert!(!socket.can_send()); assert_eq!(socket.dispatch(|(ip_repr, ip_payload)| { - assert_eq!(ip_repr, HEADER_REPR); - assert_eq!(ip_payload, &PACKET_PAYLOAD); + assert_eq!(ip_repr, ipv4_locals::HEADER_REPR); + assert_eq!(ip_payload, &ipv4_locals::PACKET_PAYLOAD); Ok(()) }, &ChecksumCapabilities::default()), Ok(())); assert!(socket.can_send()); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_send_illegal() { - let mut socket = socket(buffer(0), buffer(1)); + let mut socket = ipv4_locals::socket(buffer(0), buffer(1)); - let mut wrong_version = PACKET_BYTES.clone(); + let mut wrong_version = ipv4_locals::PACKET_BYTES.clone(); Ipv4Packet::new(&mut wrong_version).set_version(5); assert_eq!(socket.send_slice(&wrong_version[..]), Ok(())); assert_eq!(socket.dispatch(|_| unreachable!(), &ChecksumCapabilities::default()), Ok(())); - let mut wrong_protocol = PACKET_BYTES.clone(); + let mut wrong_protocol = ipv4_locals::PACKET_BYTES.clone(); Ipv4Packet::new(&mut wrong_protocol).set_protocol(IpProtocol::Tcp); assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(())); @@ -335,59 +347,65 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_recv_process() { - let mut socket = socket(buffer(1), buffer(0)); + let mut socket = ipv4_locals::socket(buffer(1), buffer(0)); assert!(!socket.can_recv()); - let mut cksumd_packet = PACKET_BYTES.clone(); + let mut cksumd_packet = ipv4_locals::PACKET_BYTES.clone(); Ipv4Packet::new(&mut cksumd_packet).fill_checksum(); assert_eq!(socket.recv(), Err(Error::Exhausted)); - assert!(socket.accepts(&HEADER_REPR)); - assert_eq!(socket.process(&HEADER_REPR, &PACKET_PAYLOAD, &ChecksumCapabilities::default()), + assert!(socket.accepts(&ipv4_locals::HEADER_REPR)); + assert_eq!(socket.process(&ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD, + &ChecksumCapabilities::default()), Ok(())); assert!(socket.can_recv()); - assert!(socket.accepts(&HEADER_REPR)); - assert_eq!(socket.process(&HEADER_REPR, &PACKET_PAYLOAD, &ChecksumCapabilities::default()), + assert!(socket.accepts(&ipv4_locals::HEADER_REPR)); + assert_eq!(socket.process(&ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD, + &ChecksumCapabilities::default()), Err(Error::Exhausted)); assert_eq!(socket.recv(), Ok(&cksumd_packet[..])); assert!(!socket.can_recv()); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_recv_truncated_slice() { - let mut socket = socket(buffer(1), buffer(0)); + let mut socket = ipv4_locals::socket(buffer(1), buffer(0)); - assert!(socket.accepts(&HEADER_REPR)); - assert_eq!(socket.process(&HEADER_REPR, &PACKET_PAYLOAD, &ChecksumCapabilities::default()), - Ok(())); + assert!(socket.accepts(&ipv4_locals::HEADER_REPR)); + assert_eq!(socket.process(&ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD, + &ChecksumCapabilities::default()), Ok(())); let mut slice = [0; 4]; assert_eq!(socket.recv_slice(&mut slice[..]), Ok(4)); - assert_eq!(&slice, &PACKET_BYTES[..slice.len()]); + assert_eq!(&slice, &ipv4_locals::PACKET_BYTES[..slice.len()]); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_recv_truncated_packet() { - let mut socket = socket(buffer(1), buffer(0)); + let mut socket = ipv4_locals::socket(buffer(1), buffer(0)); let mut buffer = vec![0; 128]; - buffer[..PACKET_BYTES.len()].copy_from_slice(&PACKET_BYTES[..]); + buffer[..ipv4_locals::PACKET_BYTES.len()].copy_from_slice(&ipv4_locals::PACKET_BYTES[..]); - assert!(socket.accepts(&HEADER_REPR)); - assert_eq!(socket.process(&HEADER_REPR, &buffer, &ChecksumCapabilities::default()), + assert!(socket.accepts(&ipv4_locals::HEADER_REPR)); + assert_eq!(socket.process(&ipv4_locals::HEADER_REPR, &buffer, &ChecksumCapabilities::default()), Err(Error::Truncated)); } #[test] + #[cfg(feature = "proto-ipv4")] fn test_doesnt_accept_wrong_proto() { let socket = match RawSocket::new(IpVersion::Ipv4, - IpProtocol::Unknown(IP_PROTO+1), + IpProtocol::Unknown(ipv4_locals::IP_PROTO+1), buffer(1), buffer(1)) { Socket::Raw(socket) => socket, _ => unreachable!() }; - assert!(!socket.accepts(&HEADER_REPR)); + assert!(!socket.accepts(&ipv4_locals::HEADER_REPR)); } } diff --git a/src/socket/ref_.rs b/src/socket/ref_.rs index c91860b81..beef7483f 100644 --- a/src/socket/ref_.rs +++ b/src/socket/ref_.rs @@ -2,7 +2,7 @@ use core::ops::{Deref, DerefMut}; #[cfg(feature = "socket-raw")] use socket::RawSocket; -#[cfg(feature = "socket-icmp")] +#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] use socket::IcmpSocket; #[cfg(feature = "socket-udp")] use socket::UdpSocket; @@ -21,7 +21,7 @@ pub trait Session { #[cfg(feature = "socket-raw")] impl<'a, 'b> Session for RawSocket<'a, 'b> {} -#[cfg(feature = "socket-icmp")] +#[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] impl<'a, 'b> Session for IcmpSocket<'a, 'b> {} #[cfg(feature = "socket-udp")] impl<'a, 'b> Session for UdpSocket<'a, 'b> {} diff --git a/src/socket/set.rs b/src/socket/set.rs index d622bcad4..793a8d935 100644 --- a/src/socket/set.rs +++ b/src/socket/set.rs @@ -140,7 +140,7 @@ impl<'a, 'b: 'a, 'c: 'a + 'b> Set<'a, 'b, 'c> { #[cfg(feature = "socket-raw")] &mut Socket::Raw(_) => may_remove = true, - #[cfg(feature = "socket-icmp")] + #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))] &mut Socket::Icmp(_) => may_remove = true, #[cfg(feature = "socket-udp")] diff --git a/src/socket/tcp.rs b/src/socket/tcp.rs index 392b0eb5b..b2dfff537 100644 --- a/src/socket/tcp.rs +++ b/src/socket/tcp.rs @@ -1498,39 +1498,23 @@ impl<'a> fmt::Write for TcpSocket<'a> { #[cfg(test)] mod test { use core::i32; - use wire::{IpAddress, IpRepr}; - use wire::{Ipv4Address, IpCidr, Ipv4Repr}; + use wire::{IpAddress, IpRepr, IpCidr}; + use wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3, MOCK_UNSPECIFIED}; use super::*; - #[test] - fn test_timer_retransmit() { - let mut r = Timer::default(); - assert_eq!(r.should_retransmit(1000), None); - r.set_for_retransmit(1000); - assert_eq!(r.should_retransmit(1000), None); - assert_eq!(r.should_retransmit(1050), None); - assert_eq!(r.should_retransmit(1101), Some(101)); - r.set_for_retransmit(1101); - assert_eq!(r.should_retransmit(1101), None); - assert_eq!(r.should_retransmit(1150), None); - assert_eq!(r.should_retransmit(1200), None); - assert_eq!(r.should_retransmit(1301), Some(300)); - r.set_for_idle(1301, None); - assert_eq!(r.should_retransmit(1350), None); - } + // =========================================================================================// + // Constants + // =========================================================================================// - const LOCAL_IP: IpAddress = IpAddress::Ipv4(Ipv4Address([10, 0, 0, 1])); - const REMOTE_IP: IpAddress = IpAddress::Ipv4(Ipv4Address([10, 0, 0, 2])); - const OTHER_IP: IpAddress = IpAddress::Ipv4(Ipv4Address([10, 0, 0, 3])); const LOCAL_PORT: u16 = 80; const REMOTE_PORT: u16 = 49500; - const LOCAL_END: IpEndpoint = IpEndpoint { addr: LOCAL_IP, port: LOCAL_PORT }; - const REMOTE_END: IpEndpoint = IpEndpoint { addr: REMOTE_IP, port: REMOTE_PORT }; + const LOCAL_END: IpEndpoint = IpEndpoint { addr: MOCK_IP_ADDR_1, port: LOCAL_PORT }; + const REMOTE_END: IpEndpoint = IpEndpoint { addr: MOCK_IP_ADDR_2, port: REMOTE_PORT }; const LOCAL_SEQ: TcpSeqNumber = TcpSeqNumber(10000); const REMOTE_SEQ: TcpSeqNumber = TcpSeqNumber(-10000); const SEND_IP_TEMPL: IpRepr = IpRepr::Unspecified { - src_addr: LOCAL_IP, dst_addr: REMOTE_IP, + src_addr: MOCK_IP_ADDR_1, dst_addr: MOCK_IP_ADDR_2, protocol: IpProtocol::Tcp, payload_len: 20, hop_limit: 64 }; @@ -1542,7 +1526,7 @@ mod test { payload: &[] }; const _RECV_IP_TEMPL: IpRepr = IpRepr::Unspecified { - src_addr: REMOTE_IP, dst_addr: LOCAL_IP, + src_addr: MOCK_IP_ADDR_1, dst_addr: MOCK_IP_ADDR_2, protocol: IpProtocol::Tcp, payload_len: 20, hop_limit: 64 }; @@ -1554,11 +1538,20 @@ mod test { payload: &[] }; + #[cfg(feature = "proto-ipv6")] + const BASE_MSS: u16 = 1460; + #[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))] + const BASE_MSS: u16 = 1480; + + // =========================================================================================// + // Helper functions + // =========================================================================================// + fn send(socket: &mut TcpSocket, timestamp: u64, repr: &TcpRepr) -> Result>> { let ip_repr = IpRepr::Unspecified { - src_addr: REMOTE_IP, - dst_addr: LOCAL_IP, + src_addr: MOCK_IP_ADDR_2, + dst_addr: MOCK_IP_ADDR_1, protocol: IpProtocol::Tcp, payload_len: repr.buffer_len(), hop_limit: 64 @@ -1584,8 +1577,8 @@ mod test { let ip_repr = ip_repr.lower(&[IpCidr::new(LOCAL_END.addr, 24)]).unwrap(); assert_eq!(ip_repr.protocol(), IpProtocol::Tcp); - assert_eq!(ip_repr.src_addr(), LOCAL_IP); - assert_eq!(ip_repr.dst_addr(), REMOTE_IP); + assert_eq!(ip_repr.src_addr(), MOCK_IP_ADDR_1); + assert_eq!(ip_repr.dst_addr(), MOCK_IP_ADDR_2); assert_eq!(ip_repr.payload_len(), tcp_repr.buffer_len()); net_trace!("recv: {}", tcp_repr); @@ -1682,6 +1675,102 @@ mod test { } } + fn socket_syn_received() -> TcpSocket<'static> { + let mut s = socket(); + s.state = State::SynReceived; + s.local_endpoint = LOCAL_END; + s.remote_endpoint = REMOTE_END; + s.local_seq_no = LOCAL_SEQ; + s.remote_seq_no = REMOTE_SEQ + 1; + s.remote_last_seq = LOCAL_SEQ; + s.remote_win_len = 256; + s + } + + fn socket_syn_sent() -> TcpSocket<'static> { + let mut s = socket(); + s.state = State::SynSent; + s.local_endpoint = IpEndpoint::new(MOCK_UNSPECIFIED, LOCAL_PORT); + s.remote_endpoint = REMOTE_END; + s.local_seq_no = LOCAL_SEQ; + s.remote_last_seq = LOCAL_SEQ; + s + } + + fn socket_established() -> TcpSocket<'static> { + let mut s = socket_syn_received(); + s.state = State::Established; + s.local_seq_no = LOCAL_SEQ + 1; + s.remote_last_seq = LOCAL_SEQ + 1; + s.remote_last_ack = Some(REMOTE_SEQ + 1); + s.remote_last_win = 64; + s + } + + fn socket_fin_wait_1() -> TcpSocket<'static> { + let mut s = socket_established(); + s.state = State::FinWait1; + s + } + + fn socket_fin_wait_2() -> TcpSocket<'static> { + let mut s = socket_fin_wait_1(); + s.state = State::FinWait2; + s.local_seq_no = LOCAL_SEQ + 1 + 1; + s.remote_last_seq = LOCAL_SEQ + 1 + 1; + s + } + + fn socket_closing() -> TcpSocket<'static> { + let mut s = socket_fin_wait_1(); + s.state = State::Closing; + s.remote_last_seq = LOCAL_SEQ + 1 + 1; + s.remote_seq_no = REMOTE_SEQ + 1 + 1; + s + } + + fn socket_time_wait(from_closing: bool) -> TcpSocket<'static> { + let mut s = socket_fin_wait_2(); + s.state = State::TimeWait; + s.remote_seq_no = REMOTE_SEQ + 1 + 1; + if from_closing { + s.remote_last_ack = Some(REMOTE_SEQ + 1 + 1); + } + s.timer = Timer::Close { expires_at: 1_000 + CLOSE_DELAY }; + s + } + + fn socket_close_wait() -> TcpSocket<'static> { + let mut s = socket_established(); + s.state = State::CloseWait; + s.remote_seq_no = REMOTE_SEQ + 1 + 1; + s.remote_last_ack = Some(REMOTE_SEQ + 1 + 1); + s + } + + fn socket_last_ack() -> TcpSocket<'static> { + let mut s = socket_close_wait(); + s.state = State::LastAck; + s + } + + fn socket_recved() -> TcpSocket<'static> { + let mut s = socket_established(); + send!(s, TcpRepr { + seq_number: REMOTE_SEQ + 1, + ack_number: Some(LOCAL_SEQ + 1), + payload: &b"abcdef"[..], + ..SEND_TEMPL + }); + recv!(s, [TcpRepr { + seq_number: LOCAL_SEQ + 1, + ack_number: Some(REMOTE_SEQ + 1 + 6), + window_len: 58, + ..RECV_TEMPL + }]); + s + } + // =========================================================================================// // Tests for the CLOSED state. // =========================================================================================// @@ -1795,17 +1884,6 @@ mod test { // =========================================================================================// // Tests for the SYN-RECEIVED state. // =========================================================================================// - fn socket_syn_received() -> TcpSocket<'static> { - let mut s = socket(); - s.state = State::SynReceived; - s.local_endpoint = LOCAL_END; - s.remote_endpoint = REMOTE_END; - s.local_seq_no = LOCAL_SEQ; - s.remote_seq_no = REMOTE_SEQ + 1; - s.remote_last_seq = LOCAL_SEQ; - s.remote_win_len = 256; - s - } #[test] fn test_syn_received_ack() { @@ -1814,7 +1892,7 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: Some(REMOTE_SEQ + 1), - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL }]); send!(s, TcpRepr { @@ -1833,7 +1911,7 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: Some(REMOTE_SEQ + 1), - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL }]); send!(s, TcpRepr { @@ -1864,7 +1942,7 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: Some(REMOTE_SEQ + 1), - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL }]); send!(s, TcpRepr { @@ -1888,24 +1966,15 @@ mod test { // =========================================================================================// // Tests for the SYN-SENT state. // =========================================================================================// - fn socket_syn_sent() -> TcpSocket<'static> { - let mut s = socket(); - s.state = State::SynSent; - s.local_endpoint = IpEndpoint::new(IpAddress::v4(0, 0, 0, 0), LOCAL_PORT); - s.remote_endpoint = REMOTE_END; - s.local_seq_no = LOCAL_SEQ; - s.remote_last_seq = LOCAL_SEQ; - s - } #[test] fn test_connect_validation() { let mut s = socket(); - assert_eq!(s.connect((IpAddress::v4(0, 0, 0, 0), 80), LOCAL_END), + assert_eq!(s.connect((IpAddress::Unspecified, 80), LOCAL_END), Err(Error::Unaddressable)); - assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(10, 0, 0, 0), 0)), + assert_eq!(s.connect(REMOTE_END, (MOCK_UNSPECIFIED, 0)), Err(Error::Unaddressable)); - assert_eq!(s.connect((IpAddress::v4(10, 0, 0, 0), 0), LOCAL_END), + assert_eq!(s.connect((MOCK_UNSPECIFIED, 0), LOCAL_END), Err(Error::Unaddressable)); assert_eq!(s.connect((IpAddress::Unspecified, 80), LOCAL_END), Err(Error::Unaddressable)); @@ -1916,19 +1985,19 @@ mod test { let mut s = socket(); s.local_seq_no = LOCAL_SEQ; s.connect(REMOTE_END, LOCAL_END.port).unwrap(); - assert_eq!(s.local_endpoint, IpEndpoint::new(IpAddress::v4(0, 0, 0, 0), LOCAL_END.port)); + assert_eq!(s.local_endpoint, IpEndpoint::new(MOCK_UNSPECIFIED, LOCAL_END.port)); recv!(s, [TcpRepr { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: None, - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL }]); send!(s, TcpRepr { control: TcpControl::Syn, seq_number: REMOTE_SEQ, ack_number: Some(LOCAL_SEQ + 1), - max_seg_size: Some(1400), + max_seg_size: Some(BASE_MSS - 80), ..SEND_TEMPL }); assert_eq!(s.local_endpoint, LOCAL_END); @@ -1937,7 +2006,7 @@ mod test { #[test] fn test_connect_unspecified_local() { let mut s = socket(); - assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(0, 0, 0, 0), 80)), + assert_eq!(s.connect(REMOTE_END, (MOCK_UNSPECIFIED, 80)), Ok(())); s.abort(); assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)), @@ -1948,7 +2017,7 @@ mod test { #[test] fn test_connect_specified_local() { let mut s = socket(); - assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(10, 0, 0, 2), 80)), + assert_eq!(s.connect(REMOTE_END, (MOCK_IP_ADDR_2, 80)), Ok(())); } @@ -1976,14 +2045,14 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: None, - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL }]); send!(s, TcpRepr { control: TcpControl::Syn, seq_number: REMOTE_SEQ, ack_number: Some(LOCAL_SEQ + 1), - max_seg_size: Some(1400), + max_seg_size: Some(BASE_MSS - 80), ..SEND_TEMPL }); recv!(s, [TcpRepr { @@ -2042,15 +2111,6 @@ mod test { // =========================================================================================// // Tests for the ESTABLISHED state. // =========================================================================================// - fn socket_established() -> TcpSocket<'static> { - let mut s = socket_syn_received(); - s.state = State::Established; - s.local_seq_no = LOCAL_SEQ + 1; - s.remote_last_seq = LOCAL_SEQ + 1; - s.remote_last_ack = Some(REMOTE_SEQ + 1); - s.remote_last_win = 64; - s - } #[test] fn test_established_recv() { @@ -2295,11 +2355,6 @@ mod test { // =========================================================================================// // Tests for the FIN-WAIT-1 state. // =========================================================================================// - fn socket_fin_wait_1() -> TcpSocket<'static> { - let mut s = socket_established(); - s.state = State::FinWait1; - s - } #[test] fn test_fin_wait_1_fin_ack() { @@ -2368,13 +2423,6 @@ mod test { // =========================================================================================// // Tests for the FIN-WAIT-2 state. // =========================================================================================// - fn socket_fin_wait_2() -> TcpSocket<'static> { - let mut s = socket_fin_wait_1(); - s.state = State::FinWait2; - s.local_seq_no = LOCAL_SEQ + 1 + 1; - s.remote_last_seq = LOCAL_SEQ + 1 + 1; - s - } #[test] fn test_fin_wait_2_fin() { @@ -2399,13 +2447,6 @@ mod test { // =========================================================================================// // Tests for the CLOSING state. // =========================================================================================// - fn socket_closing() -> TcpSocket<'static> { - let mut s = socket_fin_wait_1(); - s.state = State::Closing; - s.remote_last_seq = LOCAL_SEQ + 1 + 1; - s.remote_seq_no = REMOTE_SEQ + 1 + 1; - s - } #[test] fn test_closing_ack_fin() { @@ -2434,16 +2475,6 @@ mod test { // =========================================================================================// // Tests for the TIME-WAIT state. // =========================================================================================// - fn socket_time_wait(from_closing: bool) -> TcpSocket<'static> { - let mut s = socket_fin_wait_2(); - s.state = State::TimeWait; - s.remote_seq_no = REMOTE_SEQ + 1 + 1; - if from_closing { - s.remote_last_ack = Some(REMOTE_SEQ + 1 + 1); - } - s.timer = Timer::Close { expires_at: 1_000 + CLOSE_DELAY }; - s - } #[test] fn test_time_wait_from_fin_wait_2_ack() { @@ -2505,13 +2536,6 @@ mod test { // =========================================================================================// // Tests for the CLOSE-WAIT state. // =========================================================================================// - fn socket_close_wait() -> TcpSocket<'static> { - let mut s = socket_established(); - s.state = State::CloseWait; - s.remote_seq_no = REMOTE_SEQ + 1 + 1; - s.remote_last_ack = Some(REMOTE_SEQ + 1 + 1); - s - } #[test] fn test_close_wait_ack() { @@ -2541,12 +2565,6 @@ mod test { // =========================================================================================// // Tests for the LAST-ACK state. // =========================================================================================// - fn socket_last_ack() -> TcpSocket<'static> { - let mut s = socket_close_wait(); - s.state = State::LastAck; - s - } - #[test] fn test_last_ack_fin_ack() { let mut s = socket_last_ack(); @@ -2575,6 +2593,7 @@ mod test { // =========================================================================================// // Tests for transitioning through multiple states. // =========================================================================================// + #[test] fn test_listen() { let mut s = socket(); @@ -2598,7 +2617,7 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: Some(REMOTE_SEQ + 1), - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL }]); send!(s, TcpRepr { @@ -2802,22 +2821,6 @@ mod test { // =========================================================================================// // Tests for retransmission on packet loss. // =========================================================================================// - fn socket_recved() -> TcpSocket<'static> { - let mut s = socket_established(); - send!(s, TcpRepr { - seq_number: REMOTE_SEQ + 1, - ack_number: Some(LOCAL_SEQ + 1), - payload: &b"abcdef"[..], - ..SEND_TEMPL - }); - recv!(s, [TcpRepr { - seq_number: LOCAL_SEQ + 1, - ack_number: Some(REMOTE_SEQ + 1 + 6), - window_len: 58, - ..RECV_TEMPL - }]); - s - } #[test] fn test_duplicate_seq_ack() { @@ -2907,14 +2910,14 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: Some(REMOTE_SEQ + 1), - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL })); recv!(s, time 150, Ok(TcpRepr { // retransmit control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: Some(REMOTE_SEQ + 1), - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL })); send!(s, TcpRepr { @@ -3140,7 +3143,7 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: Some(REMOTE_SEQ + 1), - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL }]); send!(s, TcpRepr { @@ -3317,7 +3320,7 @@ mod test { control: TcpControl::Syn, seq_number: LOCAL_SEQ, ack_number: None, - max_seg_size: Some(1480), + max_seg_size: Some(BASE_MSS), ..RECV_TEMPL })); assert_eq!(s.state, State::SynSent); @@ -3533,13 +3536,7 @@ mod test { s.set_hop_limit(Some(0x2a)); assert_eq!(s.dispatch(0, &caps, |(ip_repr, _)| { - assert_eq!(ip_repr, IpRepr::Ipv4(Ipv4Repr { - src_addr: Ipv4Address([10, 0, 0, 1]), - dst_addr: Ipv4Address([10, 0, 0, 2]), - protocol: IpProtocol::Tcp, - payload_len: 24, - hop_limit: 0x2a, - })); + assert_eq!(ip_repr.hop_limit(), 0x2a); Ok(()) }), Ok(())); } @@ -3686,8 +3683,8 @@ mod test { }; let ip_repr = IpRepr::Unspecified { - src_addr: REMOTE_IP, - dst_addr: LOCAL_IP, + src_addr: MOCK_IP_ADDR_2, + dst_addr: MOCK_IP_ADDR_1, protocol: IpProtocol::Tcp, payload_len: tcp_repr.buffer_len(), hop_limit: 64 @@ -3695,8 +3692,8 @@ mod test { assert!(s.accepts(&ip_repr, &tcp_repr)); let ip_repr_wrong_src = IpRepr::Unspecified { - src_addr: OTHER_IP, - dst_addr: LOCAL_IP, + src_addr: MOCK_IP_ADDR_3, + dst_addr: MOCK_IP_ADDR_1, protocol: IpProtocol::Tcp, payload_len: tcp_repr.buffer_len(), hop_limit: 64 @@ -3704,12 +3701,34 @@ mod test { assert!(!s.accepts(&ip_repr_wrong_src, &tcp_repr)); let ip_repr_wrong_dst = IpRepr::Unspecified { - src_addr: REMOTE_IP, - dst_addr: OTHER_IP, + src_addr: MOCK_IP_ADDR_2, + dst_addr: MOCK_IP_ADDR_3, protocol: IpProtocol::Tcp, payload_len: tcp_repr.buffer_len(), hop_limit: 64 }; assert!(!s.accepts(&ip_repr_wrong_dst, &tcp_repr)); } + + // =========================================================================================// + // Timer tests + // =========================================================================================// + + #[test] + fn test_timer_retransmit() { + let mut r = Timer::default(); + assert_eq!(r.should_retransmit(1000), None); + r.set_for_retransmit(1000); + assert_eq!(r.should_retransmit(1000), None); + assert_eq!(r.should_retransmit(1050), None); + assert_eq!(r.should_retransmit(1101), Some(101)); + r.set_for_retransmit(1101); + assert_eq!(r.should_retransmit(1101), None); + assert_eq!(r.should_retransmit(1150), None); + assert_eq!(r.should_retransmit(1200), None); + assert_eq!(r.should_retransmit(1301), Some(300)); + r.set_for_idle(1301, None); + assert_eq!(r.should_retransmit(1350), None); + } + } diff --git a/src/socket/udp.rs b/src/socket/udp.rs index f7e54eb69..ec63f219d 100644 --- a/src/socket/udp.rs +++ b/src/socket/udp.rs @@ -258,7 +258,12 @@ impl<'a, 'b> UdpSocket<'a, 'b> { #[cfg(test)] mod test { - use wire::{IpAddress, Ipv4Address, IpRepr, Ipv4Repr, UdpRepr}; + use wire::{IpAddress, IpRepr, UdpRepr}; + #[cfg(feature = "proto-ipv4")] + use wire::Ipv4Repr; + #[cfg(feature = "proto-ipv6")] + use wire::Ipv6Repr; + use wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2, MOCK_IP_ADDR_3}; use super::*; fn buffer(packets: usize) -> SocketBuffer<'static, 'static> { @@ -278,12 +283,53 @@ mod test { } } - const LOCAL_IP: IpAddress = IpAddress::Ipv4(Ipv4Address([10, 0, 0, 1])); - const REMOTE_IP: IpAddress = IpAddress::Ipv4(Ipv4Address([10, 0, 0, 2])); const LOCAL_PORT: u16 = 53; const REMOTE_PORT: u16 = 49500; - const LOCAL_END: IpEndpoint = IpEndpoint { addr: LOCAL_IP, port: LOCAL_PORT }; - const REMOTE_END: IpEndpoint = IpEndpoint { addr: REMOTE_IP, port: REMOTE_PORT }; + + pub const LOCAL_END: IpEndpoint = IpEndpoint { addr: MOCK_IP_ADDR_1, port: LOCAL_PORT }; + pub const REMOTE_END: IpEndpoint = IpEndpoint { addr: MOCK_IP_ADDR_2, port: REMOTE_PORT }; + + pub const LOCAL_IP_REPR: IpRepr = IpRepr::Unspecified { + src_addr: MOCK_IP_ADDR_1, + dst_addr: MOCK_IP_ADDR_2, + protocol: IpProtocol::Udp, + payload_len: 8 + 6, + hop_limit: 64, + }; + + const LOCAL_UDP_REPR: UdpRepr = UdpRepr { + src_port: LOCAL_PORT, + dst_port: REMOTE_PORT, + payload: b"abcdef" + }; + + const REMOTE_UDP_REPR: UdpRepr = UdpRepr { + src_port: REMOTE_PORT, + dst_port: LOCAL_PORT, + payload: b"abcdef" + }; + + fn remote_ip_repr() -> IpRepr { + match (MOCK_IP_ADDR_2, MOCK_IP_ADDR_1) { + #[cfg(feature = "proto-ipv4")] + (IpAddress::Ipv4(src), IpAddress::Ipv4(dst)) => IpRepr::Ipv4(Ipv4Repr { + src_addr: src, + dst_addr: dst, + protocol: IpProtocol::Udp, + payload_len: 8 + 6, + hop_limit: 64 + }), + #[cfg(feature = "proto-ipv6")] + (IpAddress::Ipv6(src), IpAddress::Ipv6(dst)) => IpRepr::Ipv6(Ipv6Repr { + src_addr: src, + dst_addr: dst, + next_header: IpProtocol::Udp, + payload_len: 8 + 6, + hop_limit: 64 + }), + _ => unreachable!() + } + } #[test] fn test_bind_unaddressable() { @@ -298,18 +344,12 @@ mod test { assert_eq!(socket.bind(2), Err(Error::Illegal)); } - const LOCAL_IP_REPR: IpRepr = IpRepr::Unspecified { - src_addr: LOCAL_IP, - dst_addr: REMOTE_IP, - protocol: IpProtocol::Udp, - payload_len: 8 + 6, - hop_limit: 64, - }; - const LOCAL_UDP_REPR: UdpRepr = UdpRepr { - src_port: LOCAL_PORT, - dst_port: REMOTE_PORT, - payload: b"abcdef" - }; + #[test] + #[should_panic(expected = "the time-to-live value of a packet must not be zero")] + fn test_set_hop_limit_zero() { + let mut s = socket(buffer(0), buffer(1)); + s.set_hop_limit(Some(0)); + } #[test] fn test_send_unaddressable() { @@ -361,19 +401,6 @@ mod test { assert!(socket.can_send()); } - const REMOTE_IP_REPR: IpRepr = IpRepr::Ipv4(Ipv4Repr { - src_addr: Ipv4Address([10, 0, 0, 2]), - dst_addr: Ipv4Address([10, 0, 0, 1]), - protocol: IpProtocol::Udp, - payload_len: 8 + 6, - hop_limit: 64 - }); - const REMOTE_UDP_REPR: UdpRepr = UdpRepr { - src_port: REMOTE_PORT, - dst_port: LOCAL_PORT, - payload: b"abcdef" - }; - #[test] fn test_recv_process() { let mut socket = socket(buffer(1), buffer(0)); @@ -382,13 +409,13 @@ mod test { assert!(!socket.can_recv()); assert_eq!(socket.recv(), Err(Error::Exhausted)); - assert!(socket.accepts(&REMOTE_IP_REPR, &REMOTE_UDP_REPR)); - assert_eq!(socket.process(&REMOTE_IP_REPR, &REMOTE_UDP_REPR), + assert!(socket.accepts(&remote_ip_repr(), &REMOTE_UDP_REPR)); + assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR), Ok(())); assert!(socket.can_recv()); - assert!(socket.accepts(&REMOTE_IP_REPR, &REMOTE_UDP_REPR)); - assert_eq!(socket.process(&REMOTE_IP_REPR, &REMOTE_UDP_REPR), + assert!(socket.accepts(&remote_ip_repr(), &REMOTE_UDP_REPR)); + assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR), Err(Error::Exhausted)); assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END))); assert!(!socket.can_recv()); @@ -399,8 +426,8 @@ mod test { let mut socket = socket(buffer(1), buffer(0)); assert_eq!(socket.bind(LOCAL_PORT), Ok(())); - assert!(socket.accepts(&REMOTE_IP_REPR, &REMOTE_UDP_REPR)); - assert_eq!(socket.process(&REMOTE_IP_REPR, &REMOTE_UDP_REPR), + assert!(socket.accepts(&remote_ip_repr(), &REMOTE_UDP_REPR)); + assert_eq!(socket.process(&remote_ip_repr(), &REMOTE_UDP_REPR), Ok(())); let mut slice = [0; 4]; @@ -414,8 +441,8 @@ mod test { assert_eq!(socket.bind(LOCAL_PORT), Ok(())); let udp_repr = UdpRepr { payload: &[0; 100][..], ..REMOTE_UDP_REPR }; - assert!(socket.accepts(&REMOTE_IP_REPR, &udp_repr)); - assert_eq!(socket.process(&REMOTE_IP_REPR, &udp_repr), + assert!(socket.accepts(&remote_ip_repr(), &udp_repr)); + assert_eq!(socket.process(&remote_ip_repr(), &udp_repr), Err(Error::Truncated)); } @@ -428,8 +455,8 @@ mod test { assert_eq!(s.send_slice(b"abcdef", REMOTE_END), Ok(())); assert_eq!(s.dispatch(|(ip_repr, _)| { assert_eq!(ip_repr, IpRepr::Unspecified{ - src_addr: LOCAL_IP, - dst_addr: REMOTE_IP, + src_addr: MOCK_IP_ADDR_1, + dst_addr: MOCK_IP_ADDR_2, protocol: IpProtocol::Udp, payload_len: 8 + 6, hop_limit: 0x2a, @@ -438,40 +465,47 @@ mod test { }), Ok(())); } - #[test] - #[should_panic(expected = "the time-to-live value of a packet must not be zero")] - fn test_set_hop_limit_zero() { - let mut s = socket(buffer(0), buffer(1)); - s.set_hop_limit(Some(0)); - } - #[test] fn test_doesnt_accept_wrong_port() { let mut socket = socket(buffer(1), buffer(0)); assert_eq!(socket.bind(LOCAL_PORT), Ok(())); let mut udp_repr = REMOTE_UDP_REPR; - assert!(socket.accepts(&REMOTE_IP_REPR, &udp_repr)); + assert!(socket.accepts(&remote_ip_repr(), &udp_repr)); udp_repr.dst_port += 1; - assert!(!socket.accepts(&REMOTE_IP_REPR, &udp_repr)); + assert!(!socket.accepts(&remote_ip_repr(), &udp_repr)); } #[test] fn test_doesnt_accept_wrong_ip() { - let ip_repr = IpRepr::Ipv4(Ipv4Repr { - src_addr: Ipv4Address([10, 0, 0, 2]), - dst_addr: Ipv4Address([10, 0, 0, 10]), - protocol: IpProtocol::Udp, - payload_len: 8 + 6, - hop_limit: 64 - }); + fn generate_bad_repr() -> IpRepr { + match (MOCK_IP_ADDR_2, MOCK_IP_ADDR_3) { + #[cfg(feature = "proto-ipv4")] + (IpAddress::Ipv4(src), IpAddress::Ipv4(dst)) => IpRepr::Ipv4(Ipv4Repr { + src_addr: src, + dst_addr: dst, + protocol: IpProtocol::Udp, + payload_len: 8 + 6, + hop_limit: 64 + }), + #[cfg(feature = "proto-ipv6")] + (IpAddress::Ipv6(src), IpAddress::Ipv6(dst)) => IpRepr::Ipv6(Ipv6Repr { + src_addr: src, + dst_addr: dst, + next_header: IpProtocol::Udp, + payload_len: 8 + 6, + hop_limit: 64 + }), + _ => unreachable!() + } + } let mut port_bound_socket = socket(buffer(1), buffer(0)); assert_eq!(port_bound_socket.bind(LOCAL_PORT), Ok(())); - assert!(port_bound_socket.accepts(&ip_repr, &REMOTE_UDP_REPR)); + assert!(port_bound_socket.accepts(&generate_bad_repr(), &REMOTE_UDP_REPR)); let mut ip_bound_socket = socket(buffer(1), buffer(0)); assert_eq!(ip_bound_socket.bind(LOCAL_END), Ok(())); - assert!(!ip_bound_socket.accepts(&ip_repr, &REMOTE_UDP_REPR)); + assert!(!ip_bound_socket.accepts(&generate_bad_repr(), &REMOTE_UDP_REPR)); } } diff --git a/src/wire/ethernet.rs b/src/wire/ethernet.rs index 18bf36934..a83ffa818 100644 --- a/src/wire/ethernet.rs +++ b/src/wire/ethernet.rs @@ -217,10 +217,12 @@ impl> PrettyPrint for Frame { write!(f, "{}{}", indent, frame)?; match frame.ethertype() { + #[cfg(feature = "proto-ipv4")] EtherType::Arp => { indent.increase(f)?; super::ArpPacket::<&[u8]>::pretty_print(&frame.payload(), f, indent) } + #[cfg(feature = "proto-ipv4")] EtherType::Ipv4 => { indent.increase(f)?; super::Ipv4Packet::<&[u8]>::pretty_print(&frame.payload(), f, indent) diff --git a/src/wire/ip.rs b/src/wire/ip.rs index 1a7e8fb0b..fd6ba7adb 100644 --- a/src/wire/ip.rs +++ b/src/wire/ip.rs @@ -3,6 +3,7 @@ use core::convert::From; use {Error, Result}; use phy::ChecksumCapabilities; +#[cfg(feature = "proto-ipv4")] use super::{Ipv4Address, Ipv4Packet, Ipv4Repr, Ipv4Cidr}; #[cfg(feature = "proto-ipv6")] use super::{Ipv6Address, Ipv6Cidr, Ipv6Packet, Ipv6Repr}; @@ -11,6 +12,7 @@ use super::{Ipv6Address, Ipv6Cidr, Ipv6Packet, Ipv6Repr}; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Version { Unspecified, + #[cfg(feature = "proto-ipv4")] Ipv4, #[cfg(feature = "proto-ipv6")] Ipv6, @@ -25,6 +27,7 @@ impl Version { /// unknown versions result in `Err(Error::Unrecognized)`. pub fn of_packet(data: &[u8]) -> Result { match data[0] >> 4 { + #[cfg(feature = "proto-ipv4")] 4 => Ok(Version::Ipv4), #[cfg(feature = "proto-ipv6")] 6 => Ok(Version::Ipv6), @@ -37,6 +40,7 @@ impl fmt::Display for Version { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &Version::Unspecified => write!(f, "IPv?"), + #[cfg(feature = "proto-ipv4")] &Version::Ipv4 => write!(f, "IPv4"), #[cfg(feature = "proto-ipv6")] &Version::Ipv6 => write!(f, "IPv6"), @@ -84,6 +88,7 @@ pub enum Address { /// May be used as a placeholder for storage where the address is not assigned yet. Unspecified, /// An IPv4 address. + #[cfg(feature = "proto-ipv4")] Ipv4(Ipv4Address), /// An IPv6 address. #[cfg(feature = "proto-ipv6")] @@ -94,6 +99,7 @@ pub enum Address { impl Address { /// Create an address wrapping an IPv4 address with the given octets. + #[cfg(feature = "proto-ipv4")] pub fn v4(a0: u8, a1: u8, a2: u8, a3: u8) -> Address { Address::Ipv4(Ipv4Address::new(a0, a1, a2, a3)) } @@ -109,6 +115,7 @@ impl Address { pub fn is_unicast(&self) -> bool { match self { &Address::Unspecified => false, + #[cfg(feature = "proto-ipv4")] &Address::Ipv4(addr) => addr.is_unicast(), #[cfg(feature = "proto-ipv6")] &Address::Ipv6(addr) => addr.is_unicast(), @@ -120,6 +127,7 @@ impl Address { pub fn is_broadcast(&self) -> bool { match self { &Address::Unspecified => false, + #[cfg(feature = "proto-ipv4")] &Address::Ipv4(addr) => addr.is_broadcast(), #[cfg(feature = "proto-ipv6")] &Address::Ipv6(_) => false, @@ -131,6 +139,7 @@ impl Address { pub fn is_unspecified(&self) -> bool { match self { &Address::Unspecified => true, + #[cfg(feature = "proto-ipv4")] &Address::Ipv4(addr) => addr.is_unspecified(), #[cfg(feature = "proto-ipv6")] &Address::Ipv6(addr) => addr.is_unspecified(), @@ -142,6 +151,7 @@ impl Address { pub fn to_unspecified(&self) -> Address { match self { &Address::Unspecified => Address::Unspecified, + #[cfg(feature = "proto-ipv4")] &Address::Ipv4(_) => Address::Ipv4(Ipv4Address::UNSPECIFIED), #[cfg(feature = "proto-ipv6")] &Address::Ipv6(_) => Address::Ipv6(Ipv6Address::UNSPECIFIED), @@ -156,6 +166,7 @@ impl Default for Address { } } +#[cfg(feature = "proto-ipv4")] impl From for Address { fn from(addr: Ipv4Address) -> Self { Address::Ipv4(addr) @@ -173,6 +184,7 @@ impl fmt::Display for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &Address::Unspecified => write!(f, "*"), + #[cfg(feature = "proto-ipv4")] &Address::Ipv4(addr) => write!(f, "{}", addr), #[cfg(feature = "proto-ipv6")] &Address::Ipv6(addr) => write!(f, "{}", addr), @@ -185,6 +197,7 @@ impl fmt::Display for Address { /// subnet masking prefix length. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Cidr { + #[cfg(feature = "proto-ipv4")] Ipv4(Ipv4Cidr), #[cfg(feature = "proto-ipv6")] Ipv6(Ipv6Cidr), @@ -200,6 +213,7 @@ impl Cidr { /// the given prefix length is invalid for the given address. 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)), @@ -213,6 +227,7 @@ impl Cidr { /// Return the IP address of this CIDR block. pub 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()), @@ -223,6 +238,7 @@ impl Cidr { /// Return the prefix length of this CIDR block. pub 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(), @@ -234,12 +250,13 @@ impl Cidr { /// the given address. pub fn contains_addr(&self, addr: &Address) -> bool { match (self, addr) { + #[cfg(feature = "proto-ipv4")] (&Cidr::Ipv4(ref cidr), &Address::Ipv4(ref addr)) => cidr.contains_addr(addr), #[cfg(feature = "proto-ipv6")] (&Cidr::Ipv6(ref cidr), &Address::Ipv6(ref addr)) => cidr.contains_addr(addr), - #[cfg(feature = "proto-ipv6")] + #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))] (&Cidr::Ipv4(_), &Address::Ipv6(_)) | (&Cidr::Ipv6(_), &Address::Ipv4(_)) => false, (_, &Address::Unspecified) => @@ -256,12 +273,13 @@ impl Cidr { /// the subnetwork described by the given CIDR block. pub fn contains_subnet(&self, subnet: &Cidr) -> bool { match (self, subnet) { + #[cfg(feature = "proto-ipv4")] (&Cidr::Ipv4(ref cidr), &Cidr::Ipv4(ref other)) => cidr.contains_subnet(other), #[cfg(feature = "proto-ipv6")] (&Cidr::Ipv6(ref cidr), &Cidr::Ipv6(ref other)) => cidr.contains_subnet(other), - #[cfg(feature = "proto-ipv6")] + #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))] (&Cidr::Ipv4(_), &Cidr::Ipv6(_)) | (&Cidr::Ipv6(_), &Cidr::Ipv4(_)) => false, (&Cidr::__Nonexhaustive, _) | @@ -274,6 +292,7 @@ impl Cidr { 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), @@ -338,6 +357,7 @@ pub enum Repr { payload_len: usize, hop_limit: u8 }, + #[cfg(feature = "proto-ipv4")] Ipv4(Ipv4Repr), #[cfg(feature = "proto-ipv6")] Ipv6(Ipv6Repr), @@ -345,6 +365,7 @@ pub enum Repr { __Nonexhaustive } +#[cfg(feature = "proto-ipv4")] impl From for Repr { fn from(repr: Ipv4Repr) -> Repr { Repr::Ipv4(repr) @@ -363,6 +384,7 @@ impl Repr { pub fn version(&self) -> Version { match self { &Repr::Unspecified { .. } => Version::Unspecified, + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(_) => Version::Ipv4, #[cfg(feature = "proto-ipv6")] &Repr::Ipv6(_) => Version::Ipv6, @@ -374,6 +396,7 @@ impl Repr { pub fn src_addr(&self) -> Address { match self { &Repr::Unspecified { src_addr, .. } => src_addr, + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(repr) => Address::Ipv4(repr.src_addr), #[cfg(feature = "proto-ipv6")] &Repr::Ipv6(repr) => Address::Ipv6(repr.src_addr), @@ -385,6 +408,7 @@ impl Repr { pub fn dst_addr(&self) -> Address { match self { &Repr::Unspecified { dst_addr, .. } => dst_addr, + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(repr) => Address::Ipv4(repr.dst_addr), #[cfg(feature = "proto-ipv6")] &Repr::Ipv6(repr) => Address::Ipv6(repr.dst_addr), @@ -396,6 +420,7 @@ impl Repr { pub fn protocol(&self) -> Protocol { match self { &Repr::Unspecified { protocol, .. } => protocol, + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(repr) => repr.protocol, #[cfg(feature = "proto-ipv6")] &Repr::Ipv6(repr) => repr.next_header, @@ -407,6 +432,7 @@ impl Repr { pub fn payload_len(&self) -> usize { match self { &Repr::Unspecified { payload_len, .. } => payload_len, + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(repr) => repr.payload_len, #[cfg(feature = "proto-ipv6")] &Repr::Ipv6(repr) => repr.payload_len, @@ -419,6 +445,7 @@ impl Repr { match self { &mut Repr::Unspecified { ref mut payload_len, .. } => *payload_len = length, + #[cfg(feature = "proto-ipv4")] &mut Repr::Ipv4(Ipv4Repr { ref mut payload_len, .. }) => *payload_len = length, #[cfg(feature = "proto-ipv6")] @@ -432,6 +459,7 @@ impl Repr { pub fn hop_limit(&self) -> u8 { match self { &Repr::Unspecified { hop_limit, .. } => hop_limit, + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(Ipv4Repr { hop_limit, .. }) => hop_limit, #[cfg(feature = "proto-ipv6")] &Repr::Ipv6(Ipv6Repr { hop_limit, ..}) => hop_limit, @@ -466,6 +494,7 @@ impl Repr { } match self { + #[cfg(feature = "proto-ipv4")] &Repr::Unspecified { src_addr: Address::Ipv4(src_addr), dst_addr: Address::Ipv4(dst_addr), @@ -494,6 +523,7 @@ impl Repr { })) } + #[cfg(feature = "proto-ipv4")] &Repr::Unspecified { src_addr: Address::Unspecified, dst_addr: Address::Ipv4(dst_addr), @@ -537,6 +567,7 @@ impl Repr { } } + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(mut repr) => resolve_unspecified!(Repr::Ipv4, Address::Ipv4, repr, fallback_src_addrs), @@ -559,6 +590,7 @@ impl Repr { match self { &Repr::Unspecified { .. } => panic!("unspecified IP representation"), + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(repr) => repr.buffer_len(), #[cfg(feature = "proto-ipv6")] @@ -577,6 +609,7 @@ impl Repr { match self { &Repr::Unspecified { .. } => panic!("unspecified IP representation"), + #[cfg(feature = "proto-ipv4")] &Repr::Ipv4(repr) => repr.emit(&mut Ipv4Packet::new(buffer), &checksum_caps), #[cfg(feature = "proto-ipv6")] @@ -654,6 +687,7 @@ pub mod checksum { pub fn pseudo_header(src_addr: &Address, dst_addr: &Address, protocol: 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] = protocol.into(); @@ -697,12 +731,15 @@ use super::pretty_print::{PrettyPrint, PrettyIndent}; pub fn pretty_print_ip_payload>(f: &mut fmt::Formatter, indent: &mut PrettyIndent, ip_repr: T, payload: &[u8]) -> fmt::Result { - use wire::{Icmpv4Packet, TcpPacket, TcpRepr, UdpPacket, UdpRepr}; + #[cfg(feature = "proto-ipv4")] + use wire::Icmpv4Packet; + use wire::{TcpPacket, TcpRepr, UdpPacket, UdpRepr}; use wire::ip::checksum::format_checksum; let checksum_caps = ChecksumCapabilities::ignored(); let repr = ip_repr.into(); match repr.protocol() { + #[cfg(feature = "proto-ipv4")] Protocol::Icmp => { indent.increase(f)?; Icmpv4Packet::<&[u8]>::pretty_print(&payload.as_ref(), f, indent) @@ -748,10 +785,43 @@ pub fn pretty_print_ip_payload>(f: &mut fmt::Formatter, indent: &m } #[cfg(test)] -mod 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 wire::{Ipv4Address, IpProtocol, IpAddress, Ipv4Repr, IpCidr}; + use wire::{IpAddress, IpProtocol,IpCidr}; + #[cfg(feature = "proto-ipv4")] + use wire::{Ipv4Address, Ipv4Repr}; + #[test] + #[cfg(feature = "proto-ipv4")] fn ip_repr_lower() { let ip_addr_a = Ipv4Address::new(1, 2, 3, 4); let ip_addr_b = Ipv4Address::new(5, 6, 7, 8); diff --git a/src/wire/mod.rs b/src/wire/mod.rs index 1d3cd17d6..0d5cdcf66 100644 --- a/src/wire/mod.rs +++ b/src/wire/mod.rs @@ -46,6 +46,8 @@ //! /*! ```rust +# #[cfg(feature = "proto-ipv4")] +# { use smoltcp::phy::ChecksumCapabilities; use smoltcp::wire::*; let repr = Ipv4Repr { @@ -67,6 +69,7 @@ let mut buffer = vec![0; repr.buffer_len() + repr.payload_len]; .expect("malformed packet"); assert_eq!(repr, parsed); } +# } ``` */ @@ -78,11 +81,14 @@ mod field { pub mod pretty_print; mod ethernet; +#[cfg(feature = "proto-ipv4")] mod arp; -mod ip; +pub(crate) mod ip; +#[cfg(feature = "proto-ipv4")] mod ipv4; #[cfg(feature = "proto-ipv6")] mod ipv6; +#[cfg(feature = "proto-ipv4")] mod icmpv4; mod udp; mod tcp; @@ -93,6 +99,7 @@ pub use self::ethernet::{EtherType as EthernetProtocol, Address as EthernetAddress, Frame as EthernetFrame}; +#[cfg(feature = "proto-ipv4")] pub use self::arp::{Hardware as ArpHardware, Operation as ArpOperation, Packet as ArpPacket, @@ -105,6 +112,7 @@ pub use self::ip::{Version as IpVersion, Repr as IpRepr, Cidr as IpCidr}; +#[cfg(feature = "proto-ipv4")] pub use self::ipv4::{Address as Ipv4Address, Packet as Ipv4Packet, Repr as Ipv4Repr, @@ -116,6 +124,7 @@ pub use self::ipv6::{Address as Ipv6Address, Repr as Ipv6Repr, Cidr as Ipv6Cidr}; +#[cfg(feature = "proto-ipv4")] pub use self::icmpv4::{Message as Icmpv4Message, DstUnreachable as Icmpv4DstUnreachable, Redirect as Icmpv4Redirect, diff --git a/src/wire/tcp.rs b/src/wire/tcp.rs index 15f928419..881662e38 100644 --- a/src/wire/tcp.rs +++ b/src/wire/tcp.rs @@ -854,12 +854,16 @@ impl> PrettyPrint for Packet { #[cfg(test)] mod test { + #[cfg(feature = "proto-ipv4")] use wire::Ipv4Address; use super::*; + #[cfg(feature = "proto-ipv4")] const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]); + #[cfg(feature = "proto-ipv4")] const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]); + #[cfg(feature = "proto-ipv4")] static PACKET_BYTES: [u8; 28] = [0xbf, 0x00, 0x00, 0x50, 0x01, 0x23, 0x45, 0x67, @@ -869,13 +873,16 @@ mod test { 0x03, 0x03, 0x0c, 0x01, 0xaa, 0x00, 0x00, 0xff]; + #[cfg(feature = "proto-ipv4")] static OPTION_BYTES: [u8; 4] = [0x03, 0x03, 0x0c, 0x01]; + #[cfg(feature = "proto-ipv4")] static PAYLOAD_BYTES: [u8; 4] = [0xaa, 0x00, 0x00, 0xff]; #[test] + #[cfg(feature = "proto-ipv4")] fn test_deconstruct() { let packet = Packet::new(&PACKET_BYTES[..]); assert_eq!(packet.src_port(), 48896); @@ -898,6 +905,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_construct() { let mut bytes = vec![0xa5; PACKET_BYTES.len()]; let mut packet = Packet::new(&mut bytes); @@ -923,6 +931,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_truncated() { let packet = Packet::new(&PACKET_BYTES[..23]); assert_eq!(packet.check_len(), Err(Error::Truncated)); @@ -936,6 +945,7 @@ mod test { assert_eq!(packet.check_len(), Err(Error::Malformed)); } + #[cfg(feature = "proto-ipv4")] static SYN_PACKET_BYTES: [u8; 24] = [0xbf, 0x00, 0x00, 0x50, 0x01, 0x23, 0x45, 0x67, @@ -944,6 +954,7 @@ mod test { 0x7a, 0x8d, 0x00, 0x00, 0xaa, 0x00, 0x00, 0xff]; + #[cfg(feature = "proto-ipv4")] fn packet_repr() -> Repr<'static> { Repr { src_port: 48896, @@ -958,6 +969,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_parse() { let packet = Packet::new(&SYN_PACKET_BYTES[..]); let repr = Repr::parse(&packet, &SRC_ADDR.into(), &DST_ADDR.into(), &ChecksumCapabilities::default()).unwrap(); @@ -965,6 +977,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_emit() { let repr = packet_repr(); let mut bytes = vec![0xa5; repr.buffer_len()]; diff --git a/src/wire/udp.rs b/src/wire/udp.rs index ddd990f05..7cfdbdc15 100644 --- a/src/wire/udp.rs +++ b/src/wire/udp.rs @@ -210,6 +210,7 @@ impl<'a> Repr<'a> { // Valid checksum is expected... if checksum_caps.udpv4.rx() && !packet.verify_checksum(src_addr, dst_addr) { match (src_addr, dst_addr) { + #[cfg(feature = "proto-ipv4")] (&IpAddress::Ipv4(_), &IpAddress::Ipv4(_)) if packet.checksum() != 0 => { // ... except on UDP-over-IPv4, where it can be omitted. @@ -282,21 +283,27 @@ impl> PrettyPrint for Packet { #[cfg(test)] mod test { + #[cfg(feature = "proto-ipv4")] use wire::Ipv4Address; use super::*; + #[cfg(feature = "proto-ipv4")] const SRC_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 1]); + #[cfg(feature = "proto-ipv4")] const DST_ADDR: Ipv4Address = Ipv4Address([192, 168, 1, 2]); + #[cfg(feature = "proto-ipv4")] static PACKET_BYTES: [u8; 12] = [0xbf, 0x00, 0x00, 0x35, 0x00, 0x0c, 0x12, 0x4d, 0xaa, 0x00, 0x00, 0xff]; + #[cfg(feature = "proto-ipv4")] static PAYLOAD_BYTES: [u8; 4] = [0xaa, 0x00, 0x00, 0xff]; #[test] + #[cfg(feature = "proto-ipv4")] fn test_deconstruct() { let packet = Packet::new(&PACKET_BYTES[..]); assert_eq!(packet.src_port(), 48896); @@ -308,6 +315,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_construct() { let mut bytes = vec![0xa5; 12]; let mut packet = Packet::new(&mut bytes); @@ -329,6 +337,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_zero_checksum() { let mut bytes = vec![0; 8]; let mut packet = Packet::new(&mut bytes); @@ -339,6 +348,7 @@ mod test { assert_eq!(packet.checksum(), 0xffff); } + #[cfg(feature = "proto-ipv4")] fn packet_repr() -> Repr<'static> { Repr { src_port: 48896, @@ -348,6 +358,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_parse() { let packet = Packet::new(&PACKET_BYTES[..]); let repr = Repr::parse(&packet, &SRC_ADDR.into(), &DST_ADDR.into(), &ChecksumCapabilities::default()).unwrap(); @@ -355,6 +366,7 @@ mod test { } #[test] + #[cfg(feature = "proto-ipv4")] fn test_emit() { let repr = packet_repr(); let mut bytes = vec![0xa5; repr.buffer_len()];