Browse Source

Send the TCP MSS option.

whitequark 8 years ago
parent
commit
7af6ddfa0c
5 changed files with 34 additions and 21 deletions
  1. 2 1
      src/iface/ethernet.rs
  2. 3 2
      src/socket/mod.rs
  3. 22 17
      src/socket/tcp.rs
  4. 2 1
      src/socket/udp.rs
  5. 5 0
      src/wire/ethernet.rs

+ 2 - 1
src/iface/ethernet.rs

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

+ 3 - 2
src/socket/mod.rs

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

+ 22 - 17
src/socket/tcp.rs

@@ -816,7 +816,8 @@ 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) }
 
@@ -875,19 +876,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;
             }
 
@@ -965,11 +959,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)
@@ -1082,7 +1083,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);
@@ -1295,6 +1296,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 {
@@ -1871,6 +1873,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 {
@@ -2102,12 +2105,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 {

+ 2 - 1
src/socket/udp.rs

@@ -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 - 0
src/wire/ethernet.rs

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