瀏覽代碼

Implement TCP Window Scaling, Phase 1 (Issue #106)

Closes: #232
Approved by: whitequark
jhwgh1968 6 年之前
父節點
當前提交
42d25bfe26
共有 2 個文件被更改,包括 87 次插入5 次删除
  1. 54 4
      src/socket/tcp.rs
  2. 33 1
      src/wire/tcp.rs

+ 54 - 4
src/socket/tcp.rs

@@ -229,6 +229,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 receive window scaling factor for remotes which support RFC 1323, None if unsupported.
+    remote_win_scale: Option<u8>,
     /// The maximum number of data octets that the remote side may receive.
     remote_mss:      usize,
     /// The timestamp of the last packet received.
@@ -271,6 +273,7 @@ impl<'a> TcpSocket<'a> {
             remote_last_ack: None,
             remote_last_win: 0,
             remote_win_len:  0,
+            remote_win_scale: None,
             remote_mss:      DEFAULT_MSS,
             remote_last_ts:  None,
             local_rx_last_ack: None,
@@ -397,6 +400,7 @@ impl<'a> TcpSocket<'a> {
         self.remote_last_ack = None;
         self.remote_last_win = 0;
         self.remote_win_len  = 0;
+        self.remote_win_scale = None;
         self.remote_mss      = DEFAULT_MSS;
         self.remote_last_ts  = None;
     }
@@ -768,6 +772,7 @@ impl<'a> TcpSocket<'a> {
             seq_number:   TcpSeqNumber(0),
             ack_number:   None,
             window_len:   0,
+            window_scale: None,
             max_seg_size: None,
             payload:      &[]
         };
@@ -1024,6 +1029,7 @@ impl<'a> TcpSocket<'a> {
                 if let Some(max_seg_size) = repr.max_seg_size {
                     self.remote_mss = max_seg_size as usize
                 }
+                self.remote_win_scale = repr.window_scale;
                 self.set_state(State::SynReceived);
                 self.timer.set_for_idle(timestamp, self.keep_alive);
             }
@@ -1134,7 +1140,10 @@ impl<'a> TcpSocket<'a> {
 
         // Update remote state.
         self.remote_last_ts = Some(timestamp);
-        self.remote_win_len = repr.window_len as usize;
+
+        // RFC 1323: The window field (SEG.WND) in the header of every incoming segment, with the
+        // exception of SYN segments, is left-shifted by Snd.Wind.Scale bits before updating SND.WND.
+        self.remote_win_len = (repr.window_len as usize) << (self.remote_win_scale.unwrap_or(0) as usize);
 
         if ack_len > 0 {
             // Dequeue acknowledged octets.
@@ -1376,6 +1385,7 @@ impl<'a> TcpSocket<'a> {
             seq_number:   self.remote_last_seq,
             ack_number:   Some(self.remote_seq_no + self.rx_buffer.len()),
             window_len:   self.rx_buffer.window() as u16,
+            window_scale: None,
             max_seg_size: None,
             payload:      &[]
         };
@@ -1396,6 +1406,9 @@ impl<'a> TcpSocket<'a> {
                 repr.control = TcpControl::Syn;
                 if self.state == State::SynSent {
                     repr.ack_number = None;
+                    repr.window_scale = Some(0);
+                } else {
+                    repr.window_scale = self.remote_win_scale.map(|_| 0);
                 }
             }
 
@@ -1471,7 +1484,7 @@ impl<'a> TcpSocket<'a> {
             // Fill the MSS option. See RFC 6691 for an explanation of this calculation.
             let mut max_segment_size = caps.max_transmission_unit;
             max_segment_size -= ip_repr.buffer_len();
-            max_segment_size -= repr.header_len();
+            max_segment_size -= repr.mss_header_len();
             repr.max_seg_size = Some(max_segment_size as u16);
         }
 
@@ -1589,7 +1602,8 @@ 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, max_seg_size: None,
+        window_len: 256, window_scale: None,
+        max_seg_size: None,
         payload: &[]
     };
     const _RECV_IP_TEMPL: IpRepr = IpRepr::Unspecified {
@@ -1601,7 +1615,8 @@ mod test {
         src_port: LOCAL_PORT, dst_port: REMOTE_PORT,
         control: TcpControl::None,
         seq_number: TcpSeqNumber(0), ack_number: Some(TcpSeqNumber(0)),
-        window_len: 64, max_seg_size: None,
+        window_len: 64, window_scale: None,
+        max_seg_size: None,
         payload: &[]
     };
 
@@ -2020,6 +2035,35 @@ mod test {
         assert_eq!(s.remote_endpoint, IpEndpoint::default());
     }
 
+    #[test]
+    fn test_syn_received_no_window_scaling() {
+        let mut s = socket_listen();
+        send!(s, TcpRepr {
+            control: TcpControl::Syn,
+            seq_number: REMOTE_SEQ,
+            ack_number: None,
+            ..SEND_TEMPL
+        });
+        assert_eq!(s.state(), State::SynReceived);
+        assert_eq!(s.local_endpoint(), LOCAL_END);
+        assert_eq!(s.remote_endpoint(), REMOTE_END);
+        recv!(s, [TcpRepr {
+            control: TcpControl::Syn,
+            seq_number: LOCAL_SEQ,
+            ack_number: Some(REMOTE_SEQ + 1),
+            max_seg_size: Some(BASE_MSS),
+            window_scale: None,
+            ..RECV_TEMPL
+        }]);
+        send!(s, TcpRepr {
+            seq_number: REMOTE_SEQ + 1,
+            ack_number: Some(LOCAL_SEQ + 1),
+            window_scale: None,
+            ..SEND_TEMPL
+        });
+        assert_eq!(s.remote_win_scale, None);
+    }
+
     #[test]
     fn test_syn_received_close() {
         let mut s = socket_syn_received();
@@ -2055,6 +2099,7 @@ mod test {
             seq_number: LOCAL_SEQ,
             ack_number: None,
             max_seg_size: Some(BASE_MSS),
+            window_scale: Some(0),
             ..RECV_TEMPL
         }]);
         send!(s, TcpRepr {
@@ -2062,6 +2107,7 @@ mod test {
             seq_number: REMOTE_SEQ,
             ack_number: Some(LOCAL_SEQ + 1),
             max_seg_size: Some(BASE_MSS - 80),
+            window_scale: Some(0),
             ..SEND_TEMPL
         });
         assert_eq!(s.local_endpoint, LOCAL_END);
@@ -2110,6 +2156,7 @@ mod test {
             seq_number: LOCAL_SEQ,
             ack_number: None,
             max_seg_size: Some(BASE_MSS),
+            window_scale: Some(0),
             ..RECV_TEMPL
         }]);
         send!(s, TcpRepr {
@@ -2117,6 +2164,7 @@ mod test {
             seq_number: REMOTE_SEQ,
             ack_number: Some(LOCAL_SEQ + 1),
             max_seg_size: Some(BASE_MSS - 80),
+            window_scale: Some(0),
             ..SEND_TEMPL
         });
         recv!(s, [TcpRepr {
@@ -3762,6 +3810,7 @@ mod test {
             seq_number: LOCAL_SEQ,
             ack_number: None,
             max_seg_size: Some(BASE_MSS),
+            window_scale: Some(0),
             ..RECV_TEMPL
         }));
         assert_eq!(s.state, State::SynSent);
@@ -3770,6 +3819,7 @@ mod test {
             control:    TcpControl::Rst,
             seq_number: LOCAL_SEQ + 1,
             ack_number: Some(TcpSeqNumber(0)),
+            window_scale: None,
             ..RECV_TEMPL
         }));
         assert_eq!(s.state, State::Closed);

+ 33 - 1
src/wire/tcp.rs

@@ -645,6 +645,7 @@ pub struct Repr<'a> {
     pub seq_number:   SeqNumber,
     pub ack_number:   Option<SeqNumber>,
     pub window_len:   u16,
+    pub window_scale: Option<u8>,
     pub max_seg_size: Option<u16>,
     pub payload:      &'a [u8]
 }
@@ -682,6 +683,7 @@ impl<'a> Repr<'a> {
         // cut the byte at the urgent pointer from the stream.
 
         let mut max_seg_size = None;
+        let mut window_scale = None;
         let mut options = packet.options();
         while options.len() > 0 {
             let (next_options, option) = TcpOption::parse(options)?;
@@ -690,7 +692,19 @@ impl<'a> Repr<'a> {
                 TcpOption::NoOperation => (),
                 TcpOption::MaxSegmentSize(value) =>
                     max_seg_size = Some(value),
-                _ => ()
+                TcpOption::WindowScale(value) => {
+                    // RFC 1323: Thus, the shift count must be limited to 14 (which allows windows
+                    // of 2**30 = 1 Gbyte). If a Window Scale option is received with a shift.cnt
+                    // value exceeding 14, the TCP should log the error but use 14 instead of the
+                    // specified value.
+                    window_scale = if value > 14 {
+                        net_debug!("{}:{}:{}:{}: parsed window scaling factor >14, setting to 14", src_addr, packet.src_port(), dst_addr, packet.dst_port());
+                        Some(14)
+                    } else {
+                        Some(value)
+                    };
+                }
+                _ => (),
             }
             options = next_options;
         }
@@ -702,20 +716,34 @@ impl<'a> Repr<'a> {
             seq_number:   packet.seq_number(),
             ack_number:   ack_number,
             window_len:   packet.window_len(),
+            window_scale: window_scale,
             max_seg_size: max_seg_size,
             payload:      packet.payload()
         })
     }
 
     /// Return the length of a header that will be emitted from this high-level representation.
+    ///
+    /// This should be used for buffer space calculations.
     pub fn header_len(&self) -> usize {
         let mut length = field::URGENT.end;
         if self.max_seg_size.is_some() {
             length += 4
         }
+        if self.window_scale.is_some() {
+            length += 3
+        }
         length
     }
 
+    /// Return the length of the header for the TCP protocol.
+    ///
+    /// Per RFC 6691, this should be used for MSS calculations. It may be smaller than the buffer
+    /// space required to accomodate this packet's data.
+    pub fn mss_header_len(&self) -> usize {
+        field::URGENT.end
+    }
+
     /// Return the length of a packet that will be emitted from this high-level representation.
     pub fn buffer_len(&self) -> usize {
         self.header_len() + self.payload.len()
@@ -742,6 +770,9 @@ impl<'a> Repr<'a> {
         packet.set_ack(self.ack_number.is_some());
         {
             let mut options = packet.options_mut();
+            if let Some(value) = self.window_scale {
+                let tmp = options; options = TcpOption::WindowScale(value).emit(tmp);
+            }
             if let Some(value) = self.max_seg_size {
                 let tmp = options; options = TcpOption::MaxSegmentSize(value).emit(tmp);
             }
@@ -967,6 +998,7 @@ mod test {
             seq_number:   SeqNumber(0x01234567),
             ack_number:   None,
             window_len:   0x0123,
+            window_scale: None,
             control:      Control::Syn,
             max_seg_size: None,
             payload:      &PAYLOAD_BYTES