Add the proto-ipv4 feature.

v0.7.x
Dan Robertson 2017-12-24 13:28:59 +00:00 committed by whitequark
parent 260e3d996f
commit 439e0a2cc1
18 changed files with 592 additions and 350 deletions

View File

@ -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 socket-udp' MODE='test'
env: FEATURES='std phy-tap_interface proto-ipv6 socket-udp' MODE='test'
- rust: nightly
env: FEATURES='std socket-raw' MODE='test'
env: FEATURES='std proto-ipv4 socket-raw' MODE='test'
- rust: nightly
env: FEATURES='std socket-udp' MODE='test'
env: FEATURES='std proto-ipv6 socket-udp' MODE='test'
- rust: nightly
env: FEATURES='std socket-tcp' MODE='test'
env: FEATURES='std proto-ipv6 socket-tcp' MODE='test'
- rust: nightly
env: FEATURES='std socket-icmp' MODE='test'
env: FEATURES='std proto-ipv4 socket-icmp socket-tcp' MODE='test'
- rust: nightly
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:

View File

@ -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

View File

@ -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

View File

@ -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<Ipv4Address>,
device_capabilities: DeviceCapabilities,
}
@ -61,6 +66,7 @@ pub struct InterfaceBuilder <'b, 'c, DeviceT: for<'d> Device<'d>> {
ethernet_addr: Option<EthernetAddress>,
neighbor_cache: Option<NeighborCache<'b>>,
ip_addrs: ManagedSlice<'c, IpCidr>,
#[cfg(feature = "proto-ipv4")]
ipv4_gateway: Option<Ipv4Address>,
}
@ -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<T>(mut self, ip_addrs: T) -> InterfaceBuilder<'b, 'c, DeviceT>
where T: Into<ManagedSlice<'c, IpCidr>>
where T: Into<ManagedSlice<'c, IpCidr>>
{
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<T>(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT>
where T: Into<Ipv4Address>
where T: Into<Ipv4Address>
{
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<IpAddress> {
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<Ipv4Address> {
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<GatewayAddrT>(&mut self, gateway: GatewayAddrT)
where GatewayAddrT: Into<Option<Ipv4Address>> {
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, &eth_frame),
#[cfg(feature = "proto-ipv4")]
EthernetProtocol::Ipv4 =>
self.process_ipv4(sockets, timestamp, &eth_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<Packet<'frame>>
@ -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<Packet<'frame>>
{
@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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<Ipv4Address> {
let mut octets = [0u8; 4];
for n in 0..4 {
@ -248,8 +250,10 @@ impl<'a> Parser<'a> {
}
fn accept_ip(&mut self) -> Result<IpAddress> {
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<IpEndpoint> {
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<IpEndpoint> {
fn accept_ipv6_endpoint(&mut self) -> Result<IpEndpoint> {
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<IpEndpoint> {
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<IpCidr> {
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(()));

View File

@ -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);

View File

@ -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!()
}
}
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
];
}
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
];
#[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));
}
}

View File

@ -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> {}

View File

@ -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")]

View File

@ -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<Option<TcpRepr<'static>>> {
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);
}
}

View File

@ -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));
}
}

View File

@ -217,10 +217,12 @@ impl<T: AsRef<[u8]>> PrettyPrint for Frame<T> {
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)

View File

@ -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<Version> {
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<Ipv4Address> 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<Ipv4Repr> 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<T: Into<Repr>>(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<T: Into<Repr>>(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);

View File

@ -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,

View File

@ -854,12 +854,16 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
#[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()];

View File

@ -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<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
#[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()];