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: c9f915033f5e
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: 42261f346755
Choose a head ref
  • 4 commits
  • 7 files changed
  • 1 contributor

Commits on Jan 27, 2017

  1. Copy the full SHA
    a43dfd3 View commit details
  2. Send the TCP MSS option.

    whitequark committed Jan 27, 2017
    Copy the full SHA
    7af6ddf View commit details
  3. Copy the full SHA
    41ec6a5 View commit details
  4. Copy the full SHA
    42261f3 View commit details
Showing with 183 additions and 67 deletions.
  1. +5 −3 README.md
  2. +11 −9 src/iface/ethernet.rs
  3. +3 −2 src/socket/mod.rs
  4. +77 −29 src/socket/tcp.rs
  5. +2 −1 src/socket/udp.rs
  6. +5 −0 src/wire/ethernet.rs
  7. +80 −23 src/wire/tcp.rs
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@ The UDP protocol is supported over IPv4.

### TCP layer

The TCP protocol is supported over IPv4.
The TCP protocol is supported over IPv4. Only server sockets are supported.

* TCP header checksum is supported.
* Multiple packets will be transmitted without waiting for an acknowledgement.
@@ -57,9 +57,11 @@ The TCP protocol is supported over IPv4.
* TCP urgent pointer is **not** supported; any urgent octets will be received alongside
data octets.
* Reassembly of out-of-order segments is **not** supported.
* TCP options are **not** supported, in particular:
* Maximum segment size is hardcoded at the default value, 536.
* The status of TCP options is:
* Maximum segment size option is supported.
* Window scaling is **not** supported, and the maximum buffer size is 65536.
* Timestamping is **not** supported.
* Fast open is **not** supported.
* Keepalive is **not** supported.

Installation
20 changes: 11 additions & 9 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -230,14 +230,15 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let tcp_packet = try!(TcpPacket::new(ipv4_packet.payload()));
if !tcp_packet.rst() {
let tcp_reply_repr = TcpRepr {
src_port: tcp_packet.dst_port(),
dst_port: tcp_packet.src_port(),
control: TcpControl::Rst,
seq_number: tcp_packet.ack_number(),
ack_number: Some(tcp_packet.seq_number() +
tcp_packet.segment_len()),
window_len: 0,
payload: &[]
src_port: tcp_packet.dst_port(),
dst_port: tcp_packet.src_port(),
control: TcpControl::Rst,
seq_number: tcp_packet.ack_number(),
ack_number: Some(tcp_packet.seq_number() +
tcp_packet.segment_len()),
window_len: 0,
max_seg_size: None,
payload: &[]
};
let ipv4_reply_repr = Ipv4Repr {
src_addr: dst_addr,
@@ -352,10 +353,11 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let src_protocol_addrs = self.protocol_addrs.as_ref();
let arp_cache = &mut self.arp_cache;
let device = &mut self.device;
let mtu = device.mtu() - EthernetFrame::<&[u8]>::header_len();

let mut nothing_to_transmit = true;
for socket in sockets.iter_mut() {
let result = socket.dispatch(timestamp, &mut |repr, payload| {
let result = socket.dispatch(timestamp, mtu, &mut |repr, payload| {
let repr = try!(repr.lower(src_protocol_addrs));

let dst_hardware_addr =
5 changes: 3 additions & 2 deletions src/socket/mod.rs
Original file line number Diff line number Diff line change
@@ -92,9 +92,10 @@ impl<'a, 'b> Socket<'a, 'b> {
/// is returned.
///
/// This function is used internally by the networking stack.
pub fn dispatch<F, R>(&mut self, timestamp: u64, emit: &mut F) -> Result<R, Error>
pub fn dispatch<F, R>(&mut self, timestamp: u64, mtu: usize,
emit: &mut F) -> Result<R, Error>
where F: FnMut(&IpRepr, &IpPayload) -> Result<R, Error> {
dispatch_socket!(self, |socket [mut]| socket.dispatch(timestamp, emit))
dispatch_socket!(self, |socket [mut]| socket.dispatch(timestamp, mtu, emit))
}
}

106 changes: 77 additions & 29 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
@@ -245,6 +245,8 @@ pub struct TcpSocket<'a> {
/// The speculative remote window size.
/// I.e. the actual remote window size minus the count of in-flight octets.
remote_win_len: usize,
/// The maximum number of data octets that the remote side may receive.
remote_mss: usize,
retransmit: Retransmit,
rx_buffer: SocketBuffer<'a>,
tx_buffer: SocketBuffer<'a>,
@@ -271,6 +273,7 @@ impl<'a> TcpSocket<'a> {
remote_last_seq: TcpSeqNumber(0),
remote_last_ack: TcpSeqNumber(0),
remote_win_len: 0,
remote_mss: 536,
retransmit: Retransmit::new(),
tx_buffer: tx_buffer.into(),
rx_buffer: rx_buffer.into(),
@@ -688,7 +691,8 @@ impl<'a> TcpSocket<'a> {

// SYN packets in the LISTEN state change it to SYN-RECEIVED.
(State::Listen, TcpRepr {
src_port, dst_port, control: TcpControl::Syn, seq_number, ack_number: None, ..
src_port, dst_port, control: TcpControl::Syn, seq_number, ack_number: None,
max_seg_size, ..
}) => {
net_trace!("[{}]{}: received SYN",
self.debug_id, self.local_endpoint);
@@ -698,6 +702,9 @@ impl<'a> TcpSocket<'a> {
self.local_seq_no = TcpSeqNumber(-seq_number.0);
self.remote_last_seq = self.local_seq_no + 1;
self.remote_seq_no = seq_number + 1;
if let Some(max_seg_size) = max_seg_size {
self.remote_mss = max_seg_size as usize
}
self.set_state(State::SynReceived);
self.retransmit.reset();
}
@@ -816,18 +823,20 @@ impl<'a> TcpSocket<'a> {
}

/// See [Socket::dispatch](enum.Socket.html#method.dispatch).
pub fn dispatch<F, R>(&mut self, timestamp: u64, emit: &mut F) -> Result<R, Error>
pub fn dispatch<F, R>(&mut self, timestamp: u64, mtu: usize,
emit: &mut F) -> Result<R, Error>
where F: FnMut(&IpRepr, &IpPayload) -> Result<R, Error> {
if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) }

let mut repr = TcpRepr {
src_port: self.local_endpoint.port,
dst_port: self.remote_endpoint.port,
control: TcpControl::None,
seq_number: self.local_seq_no,
ack_number: None,
window_len: self.rx_buffer.window() as u16,
payload: &[]
src_port: self.local_endpoint.port,
dst_port: self.remote_endpoint.port,
control: TcpControl::None,
seq_number: self.local_seq_no,
ack_number: None,
window_len: self.rx_buffer.window() as u16,
max_seg_size: None,
payload: &[]
};

if self.state == State::Closed {
@@ -874,19 +883,12 @@ impl<'a> TcpSocket<'a> {
}

// We transmit a SYN|ACK in the SYN-RECEIVED state.
State::SynReceived => {
repr.control = TcpControl::Syn;
net_trace!("[{}]{}:{}: sending SYN|ACK",
self.debug_id, self.local_endpoint, self.remote_endpoint);
should_send = true;
}

// We transmit a SYN in the SYN-SENT state.
State::SynSent => {
State::SynReceived | State::SynSent => {
repr.control = TcpControl::Syn;
repr.ack_number = None;
net_trace!("[{}]{}:{}: sending SYN",
self.debug_id, self.local_endpoint, self.remote_endpoint);
net_trace!("[{}]{}:{}: sending SYN{}",
self.debug_id, self.local_endpoint, self.remote_endpoint,
if repr.ack_number.is_some() { "|ACK" } else { "" });
should_send = true;
}

@@ -902,8 +904,8 @@ impl<'a> TcpSocket<'a> {
let mut size = self.tx_buffer.len();
// Clamp to remote window length.
if size > self.remote_win_len { size = self.remote_win_len }
// Clamp to MSS. Currently we only support the default MSS value.
if size > 536 { size = 536 }
// Clamp to MSS.
if size > self.remote_mss { size = self.remote_mss }
// Extract data from the buffer. This may return less than what we want,
// in case it's not possible to extract a contiguous slice.
let offset = self.remote_last_seq - self.local_seq_no;
@@ -964,11 +966,18 @@ impl<'a> TcpSocket<'a> {
self.remote_last_ack = ack_number;

let ip_repr = IpRepr::Unspecified {
src_addr: self.local_endpoint.addr,
dst_addr: self.remote_endpoint.addr,
protocol: IpProtocol::Tcp,
payload_len: repr.buffer_len()
src_addr: self.local_endpoint.addr,
dst_addr: self.remote_endpoint.addr,
protocol: IpProtocol::Tcp,
payload_len: repr.buffer_len()
};
let ip_repr = try!(ip_repr.lower(&[]));

if repr.control == TcpControl::Syn {
let mtu = mtu - repr.header_len() - ip_repr.buffer_len();
repr.max_seg_size = Some(mtu as u16);
}

emit(&ip_repr, &repr)
} else {
Err(Error::Exhausted)
@@ -1053,13 +1062,15 @@ mod test {
src_port: REMOTE_PORT, dst_port: LOCAL_PORT,
control: TcpControl::None,
seq_number: TcpSeqNumber(0), ack_number: Some(TcpSeqNumber(0)),
window_len: 256, payload: &[]
window_len: 256, max_seg_size: None,
payload: &[]
};
const RECV_TEMPL: TcpRepr<'static> = TcpRepr {
src_port: LOCAL_PORT, dst_port: REMOTE_PORT,
control: TcpControl::None,
seq_number: TcpSeqNumber(0), ack_number: Some(TcpSeqNumber(0)),
window_len: 64, payload: &[]
window_len: 64, max_seg_size: None,
payload: &[]
};

fn send(socket: &mut TcpSocket, timestamp: u64, repr: &TcpRepr) -> Result<(), Error> {
@@ -1079,7 +1090,7 @@ mod test {
fn recv<F>(socket: &mut TcpSocket, timestamp: u64, mut f: F)
where F: FnMut(Result<TcpRepr, Error>) {
let mut buffer = vec![];
let result = socket.dispatch(timestamp, &mut |ip_repr, payload| {
let result = socket.dispatch(timestamp, 1520, &mut |ip_repr, payload| {
assert_eq!(ip_repr.protocol(), IpProtocol::Tcp);
assert_eq!(ip_repr.src_addr(), LOCAL_IP);
assert_eq!(ip_repr.dst_addr(), REMOTE_IP);
@@ -1292,6 +1303,7 @@ mod test {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: Some(REMOTE_SEQ + 1),
max_seg_size: Some(1480),
..RECV_TEMPL
}]);
send!(s, TcpRepr {
@@ -1868,6 +1880,7 @@ mod test {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: Some(REMOTE_SEQ + 1),
max_seg_size: Some(1480),
..RECV_TEMPL
}]);
send!(s, TcpRepr {
@@ -2099,12 +2112,14 @@ mod test {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: Some(REMOTE_SEQ + 1),
max_seg_size: Some(1480),
..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),
..RECV_TEMPL
}));
send!(s, TcpRepr {
@@ -2240,4 +2255,37 @@ mod test {
..RECV_TEMPL
}));
}

#[test]
fn test_maximum_segment_size() {
let mut s = socket_listen();
s.tx_buffer = SocketBuffer::new(vec![0; 32767]);
send!(s, TcpRepr {
control: TcpControl::Syn,
seq_number: REMOTE_SEQ,
ack_number: None,
max_seg_size: Some(1000),
..SEND_TEMPL
});
recv!(s, [TcpRepr {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: Some(REMOTE_SEQ + 1),
max_seg_size: Some(1480),
..RECV_TEMPL
}]);
send!(s, TcpRepr {
seq_number: REMOTE_SEQ + 1,
ack_number: Some(LOCAL_SEQ + 1),
window_len: 32767,
..SEND_TEMPL
});
s.send_slice(&[0; 1200][..]).unwrap();
recv!(s, [TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1),
payload: &[0; 1000][..],
..RECV_TEMPL
}])
}
}
3 changes: 2 additions & 1 deletion src/socket/udp.rs
Original file line number Diff line number Diff line change
@@ -232,7 +232,8 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
}

/// See [Socket::dispatch](enum.Socket.html#method.dispatch).
pub fn dispatch<F, R>(&mut self, _timestamp: u64, emit: &mut F) -> Result<R, Error>
pub fn dispatch<F, R>(&mut self, _timestamp: u64, _mtu: usize,
emit: &mut F) -> Result<R, Error>
where F: FnMut(&IpRepr, &IpPayload) -> Result<R, Error> {
let packet_buf = try!(self.tx_buffer.dequeue().map_err(|()| Error::Exhausted));
net_trace!("[{}]{}:{}: sending {} octets",
5 changes: 5 additions & 0 deletions src/wire/ethernet.rs
Original file line number Diff line number Diff line change
@@ -96,6 +96,11 @@ impl<T: AsRef<[u8]>> Frame<T> {
self.buffer
}

/// Return the length of a frame header.
pub fn header_len() -> usize {
field::PAYLOAD.start
}

/// Return the length of a buffer required to hold a packet with the payload
/// of a given length.
pub fn buffer_len(payload_len: usize) -> usize {
Loading