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: 974bad1adf54
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: 56ee8e5df8eb
Choose a head ref
  • 3 commits
  • 2 files changed
  • 1 contributor

Commits on Aug 21, 2017

  1. Copy the full SHA
    77ffe7c View commit details
  2. Copy the full SHA
    3864b49 View commit details
  3. Copy the full SHA
    56ee8e5 View commit details
Showing with 53 additions and 28 deletions.
  1. +11 −18 src/iface/ethernet.rs
  2. +42 −10 src/socket/tcp.rs
29 changes: 11 additions & 18 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -145,19 +145,23 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let arp_repr = ArpRepr::parse(&arp_packet)?;

match arp_repr {
// Respond to ARP requests aimed at us, and fill the ARP cache
// from all ARP requests, including gratuitous.
// Respond to ARP requests aimed at us, and fill the ARP cache from all ARP
// requests and replies, to minimize the chance that we have to perform
// an explicit ARP request.
ArpRepr::EthernetIpv4 {
operation: ArpOperation::Request,
source_hardware_addr, source_protocol_addr,
target_protocol_addr, ..
operation, source_hardware_addr, source_protocol_addr, target_protocol_addr, ..
} => {
if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
self.arp_cache.fill(&source_protocol_addr.into(),
&source_hardware_addr);
} else {
// Discard packets with non-unicast source addresses.
net_debug!("non-unicast source in {}", arp_repr);
return Err(Error::Malformed)
}

if self.has_protocol_addr(target_protocol_addr) {
if operation == ArpOperation::Reply &&
self.has_protocol_addr(target_protocol_addr) {
Ok(Response::Arp(ArpRepr::EthernetIpv4 {
operation: ArpOperation::Reply,
source_hardware_addr: self.hardware_addr,
@@ -170,18 +174,6 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
}
}

// Fill the ARP cache from gratuitous ARP replies.
ArpRepr::EthernetIpv4 {
operation: ArpOperation::Reply,
source_hardware_addr, source_protocol_addr, ..
} => {
if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
self.arp_cache.fill(&source_protocol_addr.into(),
&source_hardware_addr);
}
Ok(Response::Nop)
}

_ => Err(Error::Unrecognized)
}
}
@@ -195,6 +187,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {

if !ipv4_repr.src_addr.is_unicast() {
// Discard packets with non-unicast source addresses.
net_debug!("non-unicast source in {}", ipv4_repr);
return Err(Error::Malformed)
}

52 changes: 42 additions & 10 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
@@ -637,6 +637,35 @@ impl<'a> TcpSocket<'a> {
Ok(buffer.len())
}

/// Peek at a sequence of received octets without removing them from
/// the receive buffer, and return a pointer to it.
///
/// This function otherwise behaves identically to [recv](#method.recv).
pub fn peek(&mut self, size: usize) -> Result<&[u8]> {
// See recv() above.
if !self.may_recv() { return Err(Error::Illegal) }

let buffer = self.rx_buffer.peek(0, size);
if buffer.len() > 0 {
#[cfg(any(test, feature = "verbose"))]
net_trace!("[{}]{}:{}: rx buffer: peeking at {} octets",
self.debug_id, self.local_endpoint, self.remote_endpoint,
buffer.len());
}
Ok(buffer)
}

/// Peek at a sequence of received octets without removing them from
/// the receive buffer, and fill a slice from it.
///
/// This function otherwise behaves identically to [recv_slice](#method.recv_slice).
pub fn peek_slice(&mut self, data: &mut [u8]) -> Result<usize> {
let buffer = self.peek(data.len())?;
let data = &mut data[..buffer.len()];
data.copy_from_slice(buffer);
Ok(buffer.len())
}

fn set_state(&mut self, state: State) {
if self.state != state {
if self.remote_endpoint.addr.is_unspecified() {
@@ -661,6 +690,11 @@ impl<'a> TcpSocket<'a> {
let packet = TcpPacket::new_checked(&payload[..ip_repr.payload_len()])?;
let repr = TcpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr())?;

// If we're still listening for SYNs and the packet has an ACK, it cannot
// be destined to this socket, but another one may well listen on the same
// local endpoint.
if self.state == State::Listen && repr.ack_number.is_some() { return Err(Error::Rejected) }

// Reject packets with a wrong destination.
if self.local_endpoint.port != repr.dst_port { return Err(Error::Rejected) }
if !self.local_endpoint.addr.is_unspecified() &&
@@ -686,17 +720,11 @@ impl<'a> TcpSocket<'a> {

// Reject unacceptable acknowledgements.
match (self.state, repr) {
// The initial SYN (or whatever) cannot contain an acknowledgement.
// It may be destined to another socket though.
(State::Listen, TcpRepr { ack_number: Some(_), .. }) => {
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, .. }) => {
(State::SynSent, TcpRepr {
control: TcpControl::Rst, ack_number: None, ..
}) => {
net_debug!("[{}]{}:{}: unacceptable RST (expecting RST|ACK) \
in response to initial SYN",
self.debug_id, self.local_endpoint, self.remote_endpoint);
@@ -713,6 +741,10 @@ impl<'a> TcpSocket<'a> {
}
// Any other RST need only have a valid sequence number.
(_, TcpRepr { control: TcpControl::Rst, .. }) => (),
// The initial SYN cannot contain an acknowledgement.
(State::Listen, TcpRepr { ack_number: None, .. }) => (),
// This case is handled above.
(State::Listen, TcpRepr { ack_number: Some(_), .. }) => unreachable!(),
// Every packet after the initial SYN must be an acknowledgement.
(_, TcpRepr { ack_number: None, .. }) => {
net_debug!("[{}]{}:{}: expecting an ACK",
@@ -1493,7 +1525,7 @@ mod test {
seq_number: REMOTE_SEQ,
ack_number: Some(LOCAL_SEQ),
..SEND_TEMPL
}, Err(Error::Dropped));
}, Err(Error::Rejected));
assert_eq!(s.state, State::Listen);
}