Add support for TCP MSS option in TCP representation.
This commit is contained in:
parent
4c3f454902
commit
077513fda6
|
@ -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()));
|
let tcp_packet = try!(TcpPacket::new(ipv4_packet.payload()));
|
||||||
if !tcp_packet.rst() {
|
if !tcp_packet.rst() {
|
||||||
let tcp_reply_repr = TcpRepr {
|
let tcp_reply_repr = TcpRepr {
|
||||||
src_port: tcp_packet.dst_port(),
|
src_port: tcp_packet.dst_port(),
|
||||||
dst_port: tcp_packet.src_port(),
|
dst_port: tcp_packet.src_port(),
|
||||||
control: TcpControl::Rst,
|
control: TcpControl::Rst,
|
||||||
seq_number: tcp_packet.ack_number(),
|
seq_number: tcp_packet.ack_number(),
|
||||||
ack_number: Some(tcp_packet.seq_number() +
|
ack_number: Some(tcp_packet.seq_number() +
|
||||||
tcp_packet.segment_len()),
|
tcp_packet.segment_len()),
|
||||||
window_len: 0,
|
window_len: 0,
|
||||||
payload: &[]
|
max_seg_size: None,
|
||||||
|
payload: &[]
|
||||||
};
|
};
|
||||||
let ipv4_reply_repr = Ipv4Repr {
|
let ipv4_reply_repr = Ipv4Repr {
|
||||||
src_addr: dst_addr,
|
src_addr: dst_addr,
|
||||||
|
|
|
@ -821,13 +821,14 @@ impl<'a> TcpSocket<'a> {
|
||||||
if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) }
|
if self.remote_endpoint.is_unspecified() { return Err(Error::Exhausted) }
|
||||||
|
|
||||||
let mut repr = TcpRepr {
|
let mut repr = TcpRepr {
|
||||||
src_port: self.local_endpoint.port,
|
src_port: self.local_endpoint.port,
|
||||||
dst_port: self.remote_endpoint.port,
|
dst_port: self.remote_endpoint.port,
|
||||||
control: TcpControl::None,
|
control: TcpControl::None,
|
||||||
seq_number: self.local_seq_no,
|
seq_number: self.local_seq_no,
|
||||||
ack_number: None,
|
ack_number: None,
|
||||||
window_len: self.rx_buffer.window() as u16,
|
window_len: self.rx_buffer.window() as u16,
|
||||||
payload: &[]
|
max_seg_size: None,
|
||||||
|
payload: &[]
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.state == State::Closed {
|
if self.state == State::Closed {
|
||||||
|
@ -1053,13 +1054,15 @@ mod test {
|
||||||
src_port: REMOTE_PORT, dst_port: LOCAL_PORT,
|
src_port: REMOTE_PORT, dst_port: LOCAL_PORT,
|
||||||
control: TcpControl::None,
|
control: TcpControl::None,
|
||||||
seq_number: TcpSeqNumber(0), ack_number: Some(TcpSeqNumber(0)),
|
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 {
|
const RECV_TEMPL: TcpRepr<'static> = TcpRepr {
|
||||||
src_port: LOCAL_PORT, dst_port: REMOTE_PORT,
|
src_port: LOCAL_PORT, dst_port: REMOTE_PORT,
|
||||||
control: TcpControl::None,
|
control: TcpControl::None,
|
||||||
seq_number: TcpSeqNumber(0), ack_number: Some(TcpSeqNumber(0)),
|
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> {
|
fn send(socket: &mut TcpSocket, timestamp: u64, repr: &TcpRepr) -> Result<(), Error> {
|
||||||
|
|
103
src/wire/tcp.rs
103
src/wire/tcp.rs
|
@ -576,13 +576,14 @@ pub enum Control {
|
||||||
/// A high-level representation of a Transmission Control Protocol packet.
|
/// A high-level representation of a Transmission Control Protocol packet.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct Repr<'a> {
|
pub struct Repr<'a> {
|
||||||
pub src_port: u16,
|
pub src_port: u16,
|
||||||
pub dst_port: u16,
|
pub dst_port: u16,
|
||||||
pub control: Control,
|
pub control: Control,
|
||||||
pub seq_number: SeqNumber,
|
pub seq_number: SeqNumber,
|
||||||
pub ack_number: Option<SeqNumber>,
|
pub ack_number: Option<SeqNumber>,
|
||||||
pub window_len: u16,
|
pub window_len: u16,
|
||||||
pub payload: &'a [u8]
|
pub max_seg_size: Option<u16>,
|
||||||
|
pub payload: &'a [u8]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Repr<'a> {
|
impl<'a> Repr<'a> {
|
||||||
|
@ -615,20 +616,44 @@ impl<'a> Repr<'a> {
|
||||||
// however, most deployed systems (e.g. Linux) are *not* standards-compliant, and would
|
// however, most deployed systems (e.g. Linux) are *not* standards-compliant, and would
|
||||||
// cut the byte at the urgent pointer from the stream.
|
// cut the byte at the urgent pointer from the stream.
|
||||||
|
|
||||||
|
let mut max_seg_size = None;
|
||||||
|
let mut options = packet.options();
|
||||||
|
while options.len() > 0 {
|
||||||
|
let (next_options, option) = TcpOption::parse(options)?;
|
||||||
|
match option {
|
||||||
|
TcpOption::EndOfList => break,
|
||||||
|
TcpOption::NoOperation => (),
|
||||||
|
TcpOption::MaxSegmentSize(value) =>
|
||||||
|
max_seg_size = Some(value),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
options = next_options;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Repr {
|
Ok(Repr {
|
||||||
src_port: packet.src_port(),
|
src_port: packet.src_port(),
|
||||||
dst_port: packet.dst_port(),
|
dst_port: packet.dst_port(),
|
||||||
control: control,
|
control: control,
|
||||||
seq_number: packet.seq_number(),
|
seq_number: packet.seq_number(),
|
||||||
ack_number: ack_number,
|
ack_number: ack_number,
|
||||||
window_len: packet.window_len(),
|
window_len: packet.window_len(),
|
||||||
payload: packet.payload()
|
max_seg_size: max_seg_size,
|
||||||
|
payload: packet.payload()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the length of a header that will be emitted from this high-level representation.
|
||||||
|
pub fn header_len(&self) -> usize {
|
||||||
|
let mut length = field::URGENT.end;
|
||||||
|
if self.max_seg_size.is_some() {
|
||||||
|
length += 4
|
||||||
|
}
|
||||||
|
length
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the length of a packet that will be emitted from this high-level representation.
|
/// Return the length of a packet that will be emitted from this high-level representation.
|
||||||
pub fn buffer_len(&self) -> usize {
|
pub fn buffer_len(&self) -> usize {
|
||||||
field::URGENT.end + self.payload.len()
|
self.header_len() + self.payload.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a high-level representation into a Transmission Control Protocol packet.
|
/// Emit a high-level representation into a Transmission Control Protocol packet.
|
||||||
|
@ -641,7 +666,7 @@ impl<'a> Repr<'a> {
|
||||||
packet.set_seq_number(self.seq_number);
|
packet.set_seq_number(self.seq_number);
|
||||||
packet.set_ack_number(self.ack_number.unwrap_or(SeqNumber(0)));
|
packet.set_ack_number(self.ack_number.unwrap_or(SeqNumber(0)));
|
||||||
packet.set_window_len(self.window_len);
|
packet.set_window_len(self.window_len);
|
||||||
packet.set_header_len(field::URGENT.end as u8);
|
packet.set_header_len(self.header_len() as u8);
|
||||||
packet.clear_flags();
|
packet.clear_flags();
|
||||||
match self.control {
|
match self.control {
|
||||||
Control::None => (),
|
Control::None => (),
|
||||||
|
@ -650,6 +675,15 @@ impl<'a> Repr<'a> {
|
||||||
Control::Rst => packet.set_rst(true)
|
Control::Rst => packet.set_rst(true)
|
||||||
}
|
}
|
||||||
packet.set_ack(self.ack_number.is_some());
|
packet.set_ack(self.ack_number.is_some());
|
||||||
|
{
|
||||||
|
let mut options = packet.options_mut();
|
||||||
|
if let Some(value) = self.max_seg_size {
|
||||||
|
let tmp = options; options = TcpOption::MaxSegmentSize(value).emit(tmp);
|
||||||
|
}
|
||||||
|
if options.len() > 0 {
|
||||||
|
TcpOption::EndOfList.emit(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
packet.payload_mut().copy_from_slice(self.payload);
|
packet.payload_mut().copy_from_slice(self.payload);
|
||||||
packet.fill_checksum(src_addr, dst_addr)
|
packet.fill_checksum(src_addr, dst_addr)
|
||||||
}
|
}
|
||||||
|
@ -676,6 +710,25 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
|
||||||
try!(write!(f, " urg={}", self.urgent_at()))
|
try!(write!(f, " urg={}", self.urgent_at()))
|
||||||
}
|
}
|
||||||
try!(write!(f, " len={}", self.payload().len()));
|
try!(write!(f, " len={}", self.payload().len()));
|
||||||
|
let mut options = self.options();
|
||||||
|
while options.len() > 0 {
|
||||||
|
let (next_options, option) =
|
||||||
|
match TcpOption::parse(options) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(err) => return write!(f, " ({})", err)
|
||||||
|
};
|
||||||
|
match option {
|
||||||
|
TcpOption::EndOfList => break,
|
||||||
|
TcpOption::NoOperation => (),
|
||||||
|
TcpOption::MaxSegmentSize(value) =>
|
||||||
|
try!(write!(f, " mss={}", value)),
|
||||||
|
TcpOption::WindowScale(value) =>
|
||||||
|
try!(write!(f, " ws={}", value)),
|
||||||
|
TcpOption::Unknown { kind, .. } =>
|
||||||
|
try!(write!(f, " opt({})", kind)),
|
||||||
|
}
|
||||||
|
options = next_options;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -696,6 +749,9 @@ impl<'a> fmt::Display for Repr<'a> {
|
||||||
}
|
}
|
||||||
try!(write!(f, " win={}", self.window_len));
|
try!(write!(f, " win={}", self.window_len));
|
||||||
try!(write!(f, " len={}", self.payload.len()));
|
try!(write!(f, " len={}", self.payload.len()));
|
||||||
|
if let Some(max_seg_size) = self.max_seg_size {
|
||||||
|
try!(write!(f, " mss={}", max_seg_size));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -791,13 +847,14 @@ mod test {
|
||||||
|
|
||||||
fn packet_repr() -> Repr<'static> {
|
fn packet_repr() -> Repr<'static> {
|
||||||
Repr {
|
Repr {
|
||||||
src_port: 48896,
|
src_port: 48896,
|
||||||
dst_port: 80,
|
dst_port: 80,
|
||||||
seq_number: SeqNumber(0x01234567),
|
seq_number: SeqNumber(0x01234567),
|
||||||
ack_number: None,
|
ack_number: None,
|
||||||
window_len: 0x0123,
|
window_len: 0x0123,
|
||||||
control: Control::Syn,
|
control: Control::Syn,
|
||||||
payload: &PAYLOAD_BYTES
|
max_seg_size: None,
|
||||||
|
payload: &PAYLOAD_BYTES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue