Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6bc6cc7af7ab
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: bc0e3c352d79
Choose a head ref
  • 4 commits
  • 8 files changed
  • 1 contributor

Commits on Jul 31, 2017

  1. Fix warnings.

    whitequark committed Jul 31, 2017
    Copy the full SHA
    7533542 View commit details

Commits on Aug 1, 2017

  1. Remove IpEndpoint::accepts.

    Unclear purpose, one use, we don't need it.
    whitequark committed Aug 1, 2017
    Copy the full SHA
    5e448db View commit details
  2. Only return Err(Rejected) from TcpSocket::process on endpoint mismatch.

    Otherwise, a future SocketSet that tries to route packets by using
    IP/port numbers instead of brute force would result in different
    semantics.
    whitequark committed Aug 1, 2017
    Copy the full SHA
    6b2d711 View commit details
  3. Copy the full SHA
    bc0e3c3 View commit details
Showing with 51 additions and 45 deletions.
  1. +3 −1 README.md
  2. +1 −1 examples/server.rs
  3. +1 −1 src/lib.rs
  4. +9 −0 src/macros.rs
  5. +6 −7 src/socket/raw.rs
  6. +16 −14 src/socket/tcp.rs
  7. +15 −13 src/socket/udp.rs
  8. +0 −8 src/wire/ip.rs
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -110,7 +110,9 @@ on `collections::vec::Vec`. This only works on nightly rustc.
### Feature `log`

The `log` feature enables logging of events within the networking stack through
the [log crate][log]. The events are emitted with the TRACE log level.
the [log crate][log]. Normal events (e.g. buffer level or TCP state changes) are emitted with
the TRACE log level. Exceptional events (e.g. malformed packets) are emitted with
the DEBUG log level.

[log]: https://crates.io/crates/log

2 changes: 1 addition & 1 deletion examples/server.rs
Original file line number Diff line number Diff line change
@@ -93,7 +93,7 @@ fn main() {

if socket.can_send() {
debug!("tcp:6969 send greeting");
write!(socket, "hello\n");
write!(socket, "hello\n").unwrap();
debug!("tcp:6969 close");
socket.close();
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -81,7 +81,7 @@ extern crate alloc;
#[cfg(feature = "collections")]
extern crate collections;
#[cfg(any(test, feature = "log"))]
#[macro_use(trace, log, log_enabled)]
#[macro_use(log, log_enabled, trace, debug)]
extern crate log;

use core::fmt;
9 changes: 9 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -17,6 +17,15 @@ macro_rules! net_trace_enabled {
})
}

macro_rules! net_debug {
($($arg:expr),*) => {
#[cfg(feature = "log")]
debug!($($arg),*);
#[cfg(not(feature = "log"))]
$( let _ = $arg );*; // suppress unused variable warnings
}
}

macro_rules! enum_with_unknown {
(
$( #[$enum_attr:meta] )*
13 changes: 6 additions & 7 deletions src/socket/raw.rs
Original file line number Diff line number Diff line change
@@ -186,8 +186,7 @@ impl<'a, 'b> RawSocket<'a, 'b> {
pub(crate) fn dispatch<F, R>(&mut self, _timestamp: u64, _limits: &DeviceLimits,
emit: &mut F) -> Result<R>
where F: FnMut(&IpRepr, &IpPayload) -> Result<R> {
fn prepare(version: IpVersion, protocol: IpProtocol,
buffer: &mut [u8]) -> Result<(IpRepr, RawRepr)> {
fn prepare(protocol: IpProtocol, buffer: &mut [u8]) -> Result<(IpRepr, RawRepr)> {
match IpVersion::of_packet(buffer.as_ref())? {
IpVersion::Ipv4 => {
let mut packet = Ipv4Packet::new_checked(buffer.as_mut())?;
@@ -205,7 +204,7 @@ impl<'a, 'b> RawSocket<'a, 'b> {
}

let mut packet_buf = self.tx_buffer.dequeue()?;
match prepare(self.ip_version, self.ip_protocol, packet_buf.as_mut()) {
match prepare(self.ip_protocol, packet_buf.as_mut()) {
Ok((ip_repr, raw_repr)) => {
net_trace!("[{}]:{}:{}: sending {} octets",
self.debug_id, self.ip_version, self.ip_protocol,
@@ -240,7 +239,7 @@ impl<'a> IpPayload for RawRepr<'a> {

#[cfg(test)]
mod test {
use wire::{IpAddress, Ipv4Address, IpRepr, Ipv4Repr};
use wire::{Ipv4Address, IpRepr, Ipv4Repr};
use super::*;

fn buffer(packets: usize) -> SocketBuffer<'static, 'static> {
@@ -292,7 +291,7 @@ mod test {
let mut socket = socket(buffer(0), buffer(1));

assert!(socket.can_send());
assert_eq!(socket.dispatch(0, &limits, &mut |ip_repr, ip_payload| {
assert_eq!(socket.dispatch(0, &limits, &mut |_ip_repr, _ip_payload| {
unreachable!()
}), Err(Error::Exhausted) as Result<()>);

@@ -333,15 +332,15 @@ mod test {
Ipv4Packet::new(&mut wrong_version).set_version(5);

assert_eq!(socket.send_slice(&wrong_version[..]), Ok(()));
assert_eq!(socket.dispatch(0, &limits, &mut |ip_repr, ip_payload| {
assert_eq!(socket.dispatch(0, &limits, &mut |_ip_repr, _ip_payload| {
unreachable!()
}), Err(Error::Rejected) as Result<()>);

let mut wrong_protocol = PACKET_BYTES.clone();
Ipv4Packet::new(&mut wrong_protocol).set_protocol(IpProtocol::Tcp);

assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(()));
assert_eq!(socket.dispatch(0, &limits, &mut |ip_repr, ip_payload| {
assert_eq!(socket.dispatch(0, &limits, &mut |_ip_repr, _ip_payload| {
unreachable!()
}), Err(Error::Rejected) as Result<()>);
}
30 changes: 16 additions & 14 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
@@ -689,13 +689,15 @@ impl<'a> TcpSocket<'a> {
// The initial SYN (or whatever) cannot contain an acknowledgement.
// It may be destined to another socket though.
(State::Listen, TcpRepr { ack_number: Some(_), .. }) => {
return Err(Error::Rejected)
net_debug!("[{}]{}:{}: unacceptable ACK in LISTEN state",
self.debug_id, self.local_endpoint, self.remote_endpoint);
return Err(Error::Dropped)
}
(State::Listen, TcpRepr { ack_number: None, .. }) => (),
// An RST received in response to initial SYN is acceptable if it acknowledges
// the initial SYN.
(State::SynSent, TcpRepr { control: TcpControl::Rst, ack_number: None, .. }) => {
net_trace!("[{}]{}:{}: unacceptable RST (expecting RST|ACK) \
net_debug!("[{}]{}:{}: unacceptable RST (expecting RST|ACK) \
in response to initial SYN",
self.debug_id, self.local_endpoint, self.remote_endpoint);
return Err(Error::Malformed)
@@ -704,7 +706,7 @@ impl<'a> TcpSocket<'a> {
control: TcpControl::Rst, ack_number: Some(ack_number), ..
}) => {
if ack_number != self.local_seq_no + 1 {
net_trace!("[{}]{}:{}: unacceptable RST|ACK in response to initial SYN",
net_debug!("[{}]{}:{}: unacceptable RST|ACK in response to initial SYN",
self.debug_id, self.local_endpoint, self.remote_endpoint);
return Err(Error::Malformed)
}
@@ -713,23 +715,23 @@ impl<'a> TcpSocket<'a> {
(_, TcpRepr { control: TcpControl::Rst, .. }) => (),
// Every packet after the initial SYN must be an acknowledgement.
(_, TcpRepr { ack_number: None, .. }) => {
net_trace!("[{}]{}:{}: expecting an ACK",
net_debug!("[{}]{}:{}: expecting an ACK",
self.debug_id, self.local_endpoint, self.remote_endpoint);
return Err(Error::Malformed)
}
// Every acknowledgement must be for transmitted but unacknowledged data.
(_, TcpRepr { ack_number: Some(ack_number), .. }) => {
let unacknowledged = self.tx_buffer.len() + control_len;
if ack_number < self.local_seq_no {
net_trace!("[{}]{}:{}: duplicate ACK ({} not in {}...{})",
net_debug!("[{}]{}:{}: duplicate ACK ({} not in {}...{})",
self.debug_id, self.local_endpoint, self.remote_endpoint,
ack_number, self.local_seq_no, self.local_seq_no + unacknowledged);
// FIXME: instead of waiting for the retransmit timer to kick in,
// reset it here.
return Err(Error::Dropped)
}
if ack_number > self.local_seq_no + unacknowledged {
net_trace!("[{}]{}:{}: unacceptable ACK ({} not in {}...{})",
net_debug!("[{}]{}:{}: unacceptable ACK ({} not in {}...{})",
self.debug_id, self.local_endpoint, self.remote_endpoint,
ack_number, self.local_seq_no, self.local_seq_no + unacknowledged);
return Err(Error::Dropped)
@@ -747,7 +749,7 @@ impl<'a> TcpSocket<'a> {
let next_remote_seq = self.remote_seq_no + self.rx_buffer.len();
let mut send_ack_again = false;
if seq_number > next_remote_seq {
net_trace!("[{}]{}:{}: unacceptable SEQ ({} not in {}..), \
net_debug!("[{}]{}:{}: unacceptable SEQ ({} not in {}..), \
will send duplicate ACK",
self.debug_id, self.local_endpoint, self.remote_endpoint,
seq_number, next_remote_seq);
@@ -759,7 +761,7 @@ impl<'a> TcpSocket<'a> {
// retransmission.
send_ack_again = true;
} else if seq_number != next_remote_seq {
net_trace!("[{}]{}:{}: duplicate SEQ ({} in ..{}), \
net_debug!("[{}]{}:{}: duplicate SEQ ({} in ..{}), \
will re-send ACK",
self.debug_id, self.local_endpoint, self.remote_endpoint,
seq_number, next_remote_seq);
@@ -806,9 +808,9 @@ impl<'a> TcpSocket<'a> {

// Validate and update the state.
match (self.state, repr) {
// RSTs are ignored in the LISTEN state.
// RSTs are not accepted in the LISTEN state.
(State::Listen, TcpRepr { control: TcpControl::Rst, .. }) =>
return Err(Error::Rejected),
return Err(Error::Dropped),

// RSTs in SYN-RECEIVED flip the socket back to the LISTEN state.
(State::SynReceived, TcpRepr { control: TcpControl::Rst, .. }) => {
@@ -949,7 +951,7 @@ impl<'a> TcpSocket<'a> {
}

_ => {
net_trace!("[{}]{}:{}: unexpected packet {}",
net_debug!("[{}]{}:{}: unexpected packet {}",
self.debug_id, self.local_endpoint, self.remote_endpoint, repr);
return Err(Error::Malformed)
}
@@ -1132,7 +1134,7 @@ impl<'a> TcpSocket<'a> {

if should_send {
if let Some(actual_delay) = self.retransmit.commit(timestamp) {
net_trace!("[{}]{}:{}: retransmitting at t+{}ms ",
net_debug!("[{}]{}:{}: retransmitting at t+{}ms ",
self.debug_id, self.local_endpoint, self.remote_endpoint,
actual_delay);
}
@@ -1491,7 +1493,7 @@ mod test {
seq_number: REMOTE_SEQ,
ack_number: Some(LOCAL_SEQ),
..SEND_TEMPL
}, Err(Error::Rejected));
}, Err(Error::Dropped));
assert_eq!(s.state, State::Listen);
}

@@ -1503,7 +1505,7 @@ mod test {
seq_number: REMOTE_SEQ,
ack_number: None,
..SEND_TEMPL
}, Err(Error::Rejected));
}, Err(Error::Dropped));
}

#[test]
28 changes: 15 additions & 13 deletions src/socket/udp.rs
Original file line number Diff line number Diff line change
@@ -188,12 +188,14 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
let packet = UdpPacket::new_checked(&payload[..ip_repr.payload_len()])?;
let repr = UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr())?;

let endpoint = IpEndpoint { addr: ip_repr.src_addr(), port: repr.src_port };
if !self.endpoint.accepts(&endpoint) { return Err(Error::Rejected) }
// Reject packets with a wrong destination.
if self.endpoint.port != repr.dst_port { return Err(Error::Rejected) }
if !self.endpoint.addr.is_unspecified() &&
self.endpoint.addr != ip_repr.dst_addr() { return Err(Error::Rejected) }

let packet_buf = self.rx_buffer.try_enqueue(|buf| buf.resize(repr.payload.len()))?;
packet_buf.as_mut().copy_from_slice(repr.payload);
packet_buf.endpoint = endpoint;
packet_buf.endpoint = IpEndpoint { addr: ip_repr.src_addr(), port: repr.src_port };
net_trace!("[{}]{}:{}: receiving {} octets",
self.debug_id, self.endpoint,
packet_buf.endpoint, packet_buf.size);
@@ -236,9 +238,7 @@ impl<'a> IpPayload for UdpRepr<'a> {

#[cfg(test)]
mod test {
use std::vec::Vec;
use wire::{IpAddress, Ipv4Address, IpRepr, Ipv4Repr, UdpRepr};
use socket::AsSocket;
use super::*;

fn buffer(packets: usize) -> SocketBuffer<'static, 'static> {
@@ -294,7 +294,7 @@ mod test {
fn test_send_unaddressable() {
let mut socket = socket(buffer(0), buffer(1));
assert_eq!(socket.send_slice(b"abcdef", REMOTE_END), Err(Error::Unaddressable));
socket.bind(LOCAL_PORT);
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
assert_eq!(socket.send_slice(b"abcdef",
IpEndpoint { addr: IpAddress::Unspecified, ..REMOTE_END }),
Err(Error::Unaddressable));
@@ -307,7 +307,8 @@ mod test {
#[test]
fn test_send_truncated() {
let mut socket = socket(buffer(0), buffer(1));
socket.bind(LOCAL_END);
assert_eq!(socket.bind(LOCAL_END), Ok(()));

assert_eq!(socket.send_slice(&[0; 32][..], REMOTE_END), Err(Error::Truncated));
}

@@ -316,10 +317,10 @@ mod test {
let limits = DeviceLimits::default();

let mut socket = socket(buffer(0), buffer(1));
socket.bind(LOCAL_END);
assert_eq!(socket.bind(LOCAL_END), Ok(()));

assert!(socket.can_send());
assert_eq!(socket.dispatch(0, &limits, &mut |ip_repr, ip_payload| {
assert_eq!(socket.dispatch(0, &limits, &mut |_ip_repr, _ip_payload| {
unreachable!()
}), Err(Error::Exhausted) as Result<()>);

@@ -367,13 +368,14 @@ mod test {
#[test]
fn test_recv_process() {
let mut socket = socket(buffer(1), buffer(0));
socket.bind(LOCAL_PORT);
assert!(!socket.can_recv());
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));

let mut buffer = vec![0; REMOTE_UDP_REPR.buffer_len()];
REMOTE_UDP_REPR.emit(&mut UdpPacket::new(&mut buffer), &LOCAL_IP, &REMOTE_IP);

assert!(!socket.can_recv());
assert_eq!(socket.recv(), Err(Error::Exhausted));

assert_eq!(socket.process(0, &REMOTE_IP_REPR, &buffer),
Ok(()));
assert!(socket.can_recv());
@@ -387,7 +389,7 @@ mod test {
#[test]
fn test_recv_truncated_slice() {
let mut socket = socket(buffer(1), buffer(0));
socket.bind(LOCAL_PORT);
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));

let mut buffer = vec![0; REMOTE_UDP_REPR.buffer_len()];
REMOTE_UDP_REPR.emit(&mut UdpPacket::new(&mut buffer), &LOCAL_IP, &REMOTE_IP);
@@ -401,7 +403,7 @@ mod test {
#[test]
fn test_recv_truncated_packet() {
let mut socket = socket(buffer(1), buffer(0));
socket.bind(LOCAL_PORT);
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));

let udp_repr = UdpRepr { payload: &[0; 100][..], ..REMOTE_UDP_REPR };
let mut buffer = vec![0; udp_repr.buffer_len()];
8 changes: 0 additions & 8 deletions src/wire/ip.rs
Original file line number Diff line number Diff line change
@@ -139,14 +139,6 @@ impl Endpoint {
pub fn is_specified(&self) -> bool {
!self.addr.is_unspecified() && self.port != 0
}

/// Query whether `self` should accept packets from `other`.
///
/// Returns `true` if `other` is a specified endpoint and `self` either
/// has an unspecified address, or the addresses are equal.
pub fn accepts(&self, other: &Endpoint) -> bool {
other.is_specified() && (self.addr == other.addr || self.addr.is_unspecified())
}
}

impl fmt::Display for Endpoint {