mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-10-02 15:15:05 +00:00
Factor out packet parsing from Socket::process.
Not only is it incredibly wasteful, but this information is in any case already necessary within the EthernetInterface::process_* methods.
This commit is contained in:
parent
3974dc780f
commit
43a547fb0c
@ -199,11 +199,14 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||||||
ð_frame.src_addr());
|
ð_frame.src_addr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ip_repr = IpRepr::Ipv4(ipv4_repr);
|
||||||
|
let ip_payload = ipv4_packet.payload();
|
||||||
|
|
||||||
// Pass every IP packet to all raw sockets we have registered.
|
// Pass every IP packet to all raw sockets we have registered.
|
||||||
let mut handled_by_raw_socket = false;
|
let mut handled_by_raw_socket = false;
|
||||||
for raw_socket in sockets.iter_mut().filter_map(
|
for raw_socket in sockets.iter_mut().filter_map(
|
||||||
<Socket as AsSocket<RawSocket>>::try_as_socket) {
|
<Socket as AsSocket<RawSocket>>::try_as_socket) {
|
||||||
match raw_socket.process(&ipv4_repr.into(), ipv4_packet.payload()) {
|
match raw_socket.process(&ip_repr, ip_payload) {
|
||||||
// The packet is valid and handled by socket.
|
// The packet is valid and handled by socket.
|
||||||
Ok(()) => handled_by_raw_socket = true,
|
Ok(()) => handled_by_raw_socket = true,
|
||||||
// The packet isn't addressed to the socket, or cannot be accepted by it.
|
// The packet isn't addressed to the socket, or cannot be accepted by it.
|
||||||
@ -220,18 +223,18 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||||||
|
|
||||||
match ipv4_repr.protocol {
|
match ipv4_repr.protocol {
|
||||||
IpProtocol::Icmp =>
|
IpProtocol::Icmp =>
|
||||||
Self::process_icmpv4(ipv4_repr, ipv4_packet.payload()),
|
Self::process_icmpv4(ipv4_repr, ip_payload),
|
||||||
IpProtocol::Udp =>
|
IpProtocol::Udp =>
|
||||||
Self::process_udpv4(sockets, ipv4_repr, ipv4_packet.payload()),
|
Self::process_udpv4(sockets, ip_repr, ip_payload),
|
||||||
IpProtocol::Tcp =>
|
IpProtocol::Tcp =>
|
||||||
Self::process_tcp(sockets, timestamp, ipv4_repr.into(), ipv4_packet.payload()),
|
Self::process_tcp(sockets, timestamp, ip_repr, ip_payload),
|
||||||
_ if handled_by_raw_socket =>
|
_ if handled_by_raw_socket =>
|
||||||
Ok(Response::Nop),
|
Ok(Response::Nop),
|
||||||
_ => {
|
_ => {
|
||||||
let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
|
let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
|
||||||
reason: Icmpv4DstUnreachable::ProtoUnreachable,
|
reason: Icmpv4DstUnreachable::ProtoUnreachable,
|
||||||
header: ipv4_repr,
|
header: ipv4_repr,
|
||||||
data: &ipv4_packet.payload()[0..8]
|
data: &ip_payload[0..8]
|
||||||
};
|
};
|
||||||
let ipv4_reply_repr = Ipv4Repr {
|
let ipv4_reply_repr = Ipv4Repr {
|
||||||
src_addr: ipv4_repr.dst_addr,
|
src_addr: ipv4_repr.dst_addr,
|
||||||
@ -251,9 +254,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||||||
|
|
||||||
match icmp_repr {
|
match icmp_repr {
|
||||||
// Respond to echo requests.
|
// Respond to echo requests.
|
||||||
Icmpv4Repr::EchoRequest {
|
Icmpv4Repr::EchoRequest { ident, seq_no, data } => {
|
||||||
ident, seq_no, data
|
|
||||||
} => {
|
|
||||||
let icmp_reply_repr = Icmpv4Repr::EchoReply {
|
let icmp_reply_repr = Icmpv4Repr::EchoReply {
|
||||||
ident: ident,
|
ident: ident,
|
||||||
seq_no: seq_no,
|
seq_no: seq_no,
|
||||||
@ -277,13 +278,15 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn process_udpv4<'frame>(sockets: &mut SocketSet,
|
fn process_udpv4<'frame>(sockets: &mut SocketSet,
|
||||||
ipv4_repr: Ipv4Repr, ip_payload: &'frame [u8]) ->
|
ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
|
||||||
Result<Response<'frame>> {
|
Result<Response<'frame>> {
|
||||||
let ip_repr = IpRepr::Ipv4(ipv4_repr);
|
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
|
||||||
|
let udp_packet = UdpPacket::new_checked(ip_payload)?;
|
||||||
|
let udp_repr = UdpRepr::parse(&udp_packet, &src_addr, &dst_addr)?;
|
||||||
|
|
||||||
for udp_socket in sockets.iter_mut().filter_map(
|
for udp_socket in sockets.iter_mut().filter_map(
|
||||||
<Socket as AsSocket<UdpSocket>>::try_as_socket) {
|
<Socket as AsSocket<UdpSocket>>::try_as_socket) {
|
||||||
match udp_socket.process(&ip_repr, ip_payload) {
|
match udp_socket.process(&ip_repr, &udp_repr) {
|
||||||
// The packet is valid and handled by socket.
|
// The packet is valid and handled by socket.
|
||||||
Ok(()) => return Ok(Response::Nop),
|
Ok(()) => return Ok(Response::Nop),
|
||||||
// The packet isn't addressed to the socket.
|
// The packet isn't addressed to the socket.
|
||||||
@ -294,26 +297,37 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The packet wasn't handled by a socket, send an ICMP port unreachable packet.
|
// The packet wasn't handled by a socket, send an ICMP port unreachable packet.
|
||||||
let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
|
match ip_repr {
|
||||||
reason: Icmpv4DstUnreachable::PortUnreachable,
|
IpRepr::Ipv4(ipv4_repr) => {
|
||||||
header: ipv4_repr,
|
let icmpv4_reply_repr = Icmpv4Repr::DstUnreachable {
|
||||||
data: &ip_payload[0..8]
|
reason: Icmpv4DstUnreachable::PortUnreachable,
|
||||||
};
|
header: ipv4_repr,
|
||||||
let ipv4_reply_repr = Ipv4Repr {
|
data: &ip_payload[0..8]
|
||||||
src_addr: ipv4_repr.dst_addr,
|
};
|
||||||
dst_addr: ipv4_repr.src_addr,
|
let ipv4_reply_repr = Ipv4Repr {
|
||||||
protocol: IpProtocol::Icmp,
|
src_addr: ipv4_repr.dst_addr,
|
||||||
payload_len: icmp_reply_repr.buffer_len()
|
dst_addr: ipv4_repr.src_addr,
|
||||||
};
|
protocol: IpProtocol::Icmp,
|
||||||
Ok(Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr))
|
payload_len: icmpv4_reply_repr.buffer_len()
|
||||||
|
};
|
||||||
|
Ok(Response::Icmpv4(ipv4_reply_repr, icmpv4_reply_repr))
|
||||||
|
},
|
||||||
|
IpRepr::Unspecified { .. } |
|
||||||
|
IpRepr::__Nonexhaustive =>
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_tcp<'frame>(sockets: &mut SocketSet, timestamp: u64,
|
fn process_tcp<'frame>(sockets: &mut SocketSet, timestamp: u64,
|
||||||
ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
|
ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
|
||||||
Result<Response<'frame>> {
|
Result<Response<'frame>> {
|
||||||
|
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
|
||||||
|
let tcp_packet = TcpPacket::new_checked(ip_payload)?;
|
||||||
|
let tcp_repr = TcpRepr::parse(&tcp_packet, &src_addr, &dst_addr)?;
|
||||||
|
|
||||||
for tcp_socket in sockets.iter_mut().filter_map(
|
for tcp_socket in sockets.iter_mut().filter_map(
|
||||||
<Socket as AsSocket<TcpSocket>>::try_as_socket) {
|
<Socket as AsSocket<TcpSocket>>::try_as_socket) {
|
||||||
match tcp_socket.process(timestamp, &ip_repr, ip_payload) {
|
match tcp_socket.process(timestamp, &ip_repr, &tcp_repr) {
|
||||||
// The packet is valid and handled by socket.
|
// The packet is valid and handled by socket.
|
||||||
Ok(reply) => return Ok(reply.map_or(Response::Nop, Response::Tcp)),
|
Ok(reply) => return Ok(reply.map_or(Response::Nop, Response::Tcp)),
|
||||||
// The packet isn't addressed to the socket.
|
// The packet isn't addressed to the socket.
|
||||||
@ -324,13 +338,11 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The packet wasn't handled by a socket, send a TCP RST packet.
|
|
||||||
let tcp_packet = TcpPacket::new_checked(ip_payload)?;
|
|
||||||
let tcp_repr = TcpRepr::parse(&tcp_packet, &ip_repr.src_addr(), &ip_repr.dst_addr())?;
|
|
||||||
if tcp_repr.control == TcpControl::Rst {
|
if tcp_repr.control == TcpControl::Rst {
|
||||||
// Never reply to a TCP RST packet with another TCP RST packet.
|
// Never reply to a TCP RST packet with another TCP RST packet.
|
||||||
Ok(Response::Nop)
|
Ok(Response::Nop)
|
||||||
} else {
|
} else {
|
||||||
|
// The packet wasn't handled by a socket, send a TCP RST packet.
|
||||||
Ok(Response::Tcp(TcpSocket::rst_reply(&ip_repr, &tcp_repr)))
|
Ok(Response::Tcp(TcpSocket::rst_reply(&ip_repr, &tcp_repr)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,7 @@ use managed::Managed;
|
|||||||
|
|
||||||
use {Error, Result};
|
use {Error, Result};
|
||||||
use phy::DeviceLimits;
|
use phy::DeviceLimits;
|
||||||
use wire::{IpProtocol, IpAddress, IpEndpoint};
|
use wire::{IpProtocol, IpAddress, IpEndpoint, TcpSeqNumber, TcpRepr, TcpControl};
|
||||||
use wire::{TcpSeqNumber, TcpPacket, TcpRepr, TcpControl};
|
|
||||||
use socket::{Socket, IpRepr};
|
use socket::{Socket, IpRepr};
|
||||||
|
|
||||||
/// A TCP stream ring buffer.
|
/// A TCP stream ring buffer.
|
||||||
@ -743,15 +742,10 @@ impl<'a> TcpSocket<'a> {
|
|||||||
(ip_reply_repr, reply_repr)
|
(ip_reply_repr, reply_repr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process(&mut self, timestamp: u64, ip_repr: &IpRepr, payload: &[u8]) ->
|
pub(crate) fn process(&mut self, timestamp: u64, ip_repr: &IpRepr, repr: &TcpRepr) ->
|
||||||
Result<Option<(IpRepr, TcpRepr<'static>)>> {
|
Result<Option<(IpRepr, TcpRepr<'static>)>> {
|
||||||
debug_assert!(ip_repr.protocol() == IpProtocol::Tcp);
|
|
||||||
|
|
||||||
if self.state == State::Closed { return Err(Error::Rejected) }
|
if self.state == State::Closed { return Err(Error::Rejected) }
|
||||||
|
|
||||||
let packet = TcpPacket::new_checked(&payload[..ip_repr.payload_len()])?;
|
|
||||||
let mut 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
|
// 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
|
// be destined to this socket, but another one may well listen on the same
|
||||||
// local endpoint.
|
// local endpoint.
|
||||||
@ -784,7 +778,7 @@ impl<'a> TcpSocket<'a> {
|
|||||||
match (self.state, repr) {
|
match (self.state, repr) {
|
||||||
// An RST received in response to initial SYN is acceptable if it acknowledges
|
// An RST received in response to initial SYN is acceptable if it acknowledges
|
||||||
// the initial SYN.
|
// the initial SYN.
|
||||||
(State::SynSent, TcpRepr {
|
(State::SynSent, &TcpRepr {
|
||||||
control: TcpControl::Rst, ack_number: None, ..
|
control: TcpControl::Rst, ack_number: None, ..
|
||||||
}) => {
|
}) => {
|
||||||
net_debug!("[{}]{}:{}: unacceptable RST (expecting RST|ACK) \
|
net_debug!("[{}]{}:{}: unacceptable RST (expecting RST|ACK) \
|
||||||
@ -792,7 +786,7 @@ impl<'a> TcpSocket<'a> {
|
|||||||
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
||||||
return Err(Error::Dropped)
|
return Err(Error::Dropped)
|
||||||
}
|
}
|
||||||
(State::SynSent, TcpRepr {
|
(State::SynSent, &TcpRepr {
|
||||||
control: TcpControl::Rst, ack_number: Some(ack_number), ..
|
control: TcpControl::Rst, ack_number: Some(ack_number), ..
|
||||||
}) => {
|
}) => {
|
||||||
if ack_number != self.local_seq_no + 1 {
|
if ack_number != self.local_seq_no + 1 {
|
||||||
@ -802,19 +796,19 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Any other RST need only have a valid sequence number.
|
// Any other RST need only have a valid sequence number.
|
||||||
(_, TcpRepr { control: TcpControl::Rst, .. }) => (),
|
(_, &TcpRepr { control: TcpControl::Rst, .. }) => (),
|
||||||
// The initial SYN cannot contain an acknowledgement.
|
// The initial SYN cannot contain an acknowledgement.
|
||||||
(State::Listen, TcpRepr { ack_number: None, .. }) => (),
|
(State::Listen, &TcpRepr { ack_number: None, .. }) => (),
|
||||||
// This case is handled above.
|
// This case is handled above.
|
||||||
(State::Listen, TcpRepr { ack_number: Some(_), .. }) => unreachable!(),
|
(State::Listen, &TcpRepr { ack_number: Some(_), .. }) => unreachable!(),
|
||||||
// Every packet after the initial SYN must be an acknowledgement.
|
// Every packet after the initial SYN must be an acknowledgement.
|
||||||
(_, TcpRepr { ack_number: None, .. }) => {
|
(_, &TcpRepr { ack_number: None, .. }) => {
|
||||||
net_debug!("[{}]{}:{}: expecting an ACK",
|
net_debug!("[{}]{}:{}: expecting an ACK",
|
||||||
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
||||||
return Err(Error::Dropped)
|
return Err(Error::Dropped)
|
||||||
}
|
}
|
||||||
// Every acknowledgement must be for transmitted but unacknowledged data.
|
// Every acknowledgement must be for transmitted but unacknowledged data.
|
||||||
(_, TcpRepr { ack_number: Some(ack_number), .. }) => {
|
(_, &TcpRepr { ack_number: Some(ack_number), .. }) => {
|
||||||
let unacknowledged = self.tx_buffer.len() + control_len;
|
let unacknowledged = self.tx_buffer.len() + control_len;
|
||||||
if ack_number < self.local_seq_no {
|
if ack_number < self.local_seq_no {
|
||||||
net_debug!("[{}]{}:{}: duplicate ACK ({} not in {}...{})",
|
net_debug!("[{}]{}:{}: duplicate ACK ({} not in {}...{})",
|
||||||
@ -838,7 +832,7 @@ impl<'a> TcpSocket<'a> {
|
|||||||
(State::Listen, _) => (),
|
(State::Listen, _) => (),
|
||||||
(State::SynSent, _) => (),
|
(State::SynSent, _) => (),
|
||||||
// In all other states, segments must occupy a valid portion of the receive window.
|
// In all other states, segments must occupy a valid portion of the receive window.
|
||||||
(_, TcpRepr { seq_number, .. }) => {
|
(_, &TcpRepr { seq_number, .. }) => {
|
||||||
let mut send_challenge_ack = false;
|
let mut send_challenge_ack = false;
|
||||||
|
|
||||||
let window_start = self.remote_last_ack;
|
let window_start = self.remote_last_ack;
|
||||||
@ -901,19 +895,22 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if repr.control == TcpControl::Psh {
|
// We don't care about the PSH flag.
|
||||||
// We don't care about the PSH flag.
|
let control =
|
||||||
repr.control = TcpControl::None;
|
if repr.control == TcpControl::Psh {
|
||||||
}
|
TcpControl::None
|
||||||
|
} else {
|
||||||
|
repr.control
|
||||||
|
};
|
||||||
|
|
||||||
// Validate and update the state.
|
// Validate and update the state.
|
||||||
match (self.state, repr) {
|
match (self.state, control) {
|
||||||
// RSTs are not accepted in the LISTEN state.
|
// RSTs are not accepted in the LISTEN state.
|
||||||
(State::Listen, TcpRepr { control: TcpControl::Rst, .. }) =>
|
(State::Listen, TcpControl::Rst) =>
|
||||||
return Err(Error::Dropped),
|
return Err(Error::Dropped),
|
||||||
|
|
||||||
// RSTs in SYN-RECEIVED flip the socket back to the LISTEN state.
|
// RSTs in SYN-RECEIVED flip the socket back to the LISTEN state.
|
||||||
(State::SynReceived, TcpRepr { control: TcpControl::Rst, .. }) => {
|
(State::SynReceived, TcpControl::Rst) => {
|
||||||
net_trace!("[{}]{}:{}: received RST",
|
net_trace!("[{}]{}:{}: received RST",
|
||||||
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
||||||
self.local_endpoint.addr = self.listen_address;
|
self.local_endpoint.addr = self.listen_address;
|
||||||
@ -923,7 +920,7 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RSTs in any other state close the socket.
|
// RSTs in any other state close the socket.
|
||||||
(_, TcpRepr { control: TcpControl::Rst, .. }) => {
|
(_, TcpControl::Rst) => {
|
||||||
net_trace!("[{}]{}:{}: received RST",
|
net_trace!("[{}]{}:{}: received RST",
|
||||||
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
||||||
self.set_state(State::Closed);
|
self.set_state(State::Closed);
|
||||||
@ -933,19 +930,16 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SYN packets in the LISTEN state change it to SYN-RECEIVED.
|
// SYN packets in the LISTEN state change it to SYN-RECEIVED.
|
||||||
(State::Listen, TcpRepr {
|
(State::Listen, TcpControl::Syn) => {
|
||||||
src_port, dst_port, control: TcpControl::Syn, seq_number, ack_number: None,
|
|
||||||
max_seg_size, ..
|
|
||||||
}) => {
|
|
||||||
net_trace!("[{}]{}: received SYN",
|
net_trace!("[{}]{}: received SYN",
|
||||||
self.debug_id, self.local_endpoint);
|
self.debug_id, self.local_endpoint);
|
||||||
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), dst_port);
|
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), repr.dst_port);
|
||||||
self.remote_endpoint = IpEndpoint::new(ip_repr.src_addr(), src_port);
|
self.remote_endpoint = IpEndpoint::new(ip_repr.src_addr(), repr.src_port);
|
||||||
// FIXME: use something more secure here
|
// FIXME: use something more secure here
|
||||||
self.local_seq_no = TcpSeqNumber(-seq_number.0);
|
self.local_seq_no = TcpSeqNumber(-repr.seq_number.0);
|
||||||
self.remote_next_seq = self.local_seq_no;
|
self.remote_next_seq = self.local_seq_no;
|
||||||
self.remote_seq_no = seq_number + 1;
|
self.remote_seq_no = repr.seq_number + 1;
|
||||||
if let Some(max_seg_size) = max_seg_size {
|
if let Some(max_seg_size) = repr.max_seg_size {
|
||||||
self.remote_mss = max_seg_size as usize
|
self.remote_mss = max_seg_size as usize
|
||||||
}
|
}
|
||||||
self.set_state(State::SynReceived);
|
self.set_state(State::SynReceived);
|
||||||
@ -953,7 +947,7 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ACK packets in the SYN-RECEIVED state change it to ESTABLISHED.
|
// ACK packets in the SYN-RECEIVED state change it to ESTABLISHED.
|
||||||
(State::SynReceived, TcpRepr { control: TcpControl::None, .. }) => {
|
(State::SynReceived, TcpControl::None) => {
|
||||||
self.set_state(State::Established);
|
self.set_state(State::Established);
|
||||||
self.timer.reset();
|
self.timer.reset();
|
||||||
}
|
}
|
||||||
@ -961,24 +955,21 @@ impl<'a> TcpSocket<'a> {
|
|||||||
// FIN packets in the SYN-RECEIVED state change it to CLOSE-WAIT.
|
// FIN packets in the SYN-RECEIVED state change it to CLOSE-WAIT.
|
||||||
// It's not obvious from RFC 793 that this is permitted, but
|
// It's not obvious from RFC 793 that this is permitted, but
|
||||||
// 7th and 8th steps in the "SEGMENT ARRIVES" event describe this behavior.
|
// 7th and 8th steps in the "SEGMENT ARRIVES" event describe this behavior.
|
||||||
(State::SynReceived, TcpRepr { control: TcpControl::Fin, .. }) => {
|
(State::SynReceived, TcpControl::Fin) => {
|
||||||
self.remote_seq_no += 1;
|
self.remote_seq_no += 1;
|
||||||
self.set_state(State::CloseWait);
|
self.set_state(State::CloseWait);
|
||||||
self.timer.reset();
|
self.timer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// SYN|ACK packets in the SYN-SENT state change it to ESTABLISHED.
|
// SYN|ACK packets in the SYN-SENT state change it to ESTABLISHED.
|
||||||
(State::SynSent, TcpRepr {
|
(State::SynSent, TcpControl::Syn) => {
|
||||||
control: TcpControl::Syn, seq_number, ack_number: Some(_),
|
|
||||||
max_seg_size, ..
|
|
||||||
}) => {
|
|
||||||
net_trace!("[{}]{}:{}: received SYN|ACK",
|
net_trace!("[{}]{}:{}: received SYN|ACK",
|
||||||
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
self.debug_id, self.local_endpoint, self.remote_endpoint);
|
||||||
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), repr.dst_port);
|
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), repr.dst_port);
|
||||||
self.remote_next_seq = self.local_seq_no + 1;
|
self.remote_next_seq = self.local_seq_no + 1;
|
||||||
self.remote_seq_no = seq_number + 1;
|
self.remote_seq_no = repr.seq_number + 1;
|
||||||
self.remote_last_ack = seq_number;
|
self.remote_last_ack = repr.seq_number;
|
||||||
if let Some(max_seg_size) = max_seg_size {
|
if let Some(max_seg_size) = repr.max_seg_size {
|
||||||
self.remote_mss = max_seg_size as usize;
|
self.remote_mss = max_seg_size as usize;
|
||||||
}
|
}
|
||||||
self.set_state(State::Established);
|
self.set_state(State::Established);
|
||||||
@ -986,12 +977,12 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ACK packets in ESTABLISHED state reset the retransmit timer.
|
// ACK packets in ESTABLISHED state reset the retransmit timer.
|
||||||
(State::Established, TcpRepr { control: TcpControl::None, .. }) => {
|
(State::Established, TcpControl::None) => {
|
||||||
self.timer.reset()
|
self.timer.reset()
|
||||||
},
|
},
|
||||||
|
|
||||||
// FIN packets in ESTABLISHED state indicate the remote side has closed.
|
// FIN packets in ESTABLISHED state indicate the remote side has closed.
|
||||||
(State::Established, TcpRepr { control: TcpControl::Fin, .. }) => {
|
(State::Established, TcpControl::Fin) => {
|
||||||
self.remote_seq_no += 1;
|
self.remote_seq_no += 1;
|
||||||
self.set_state(State::CloseWait);
|
self.set_state(State::CloseWait);
|
||||||
self.timer.reset();
|
self.timer.reset();
|
||||||
@ -999,7 +990,7 @@ impl<'a> TcpSocket<'a> {
|
|||||||
|
|
||||||
// ACK packets in FIN-WAIT-1 state change it to FIN-WAIT-2, if we've already
|
// ACK packets in FIN-WAIT-1 state change it to FIN-WAIT-2, if we've already
|
||||||
// sent everything in the transmit buffer. If not, they reset the retransmit timer.
|
// sent everything in the transmit buffer. If not, they reset the retransmit timer.
|
||||||
(State::FinWait1, TcpRepr { control: TcpControl::None, .. }) => {
|
(State::FinWait1, TcpControl::None) => {
|
||||||
if ack_of_fin {
|
if ack_of_fin {
|
||||||
self.set_state(State::FinWait2);
|
self.set_state(State::FinWait2);
|
||||||
} else {
|
} else {
|
||||||
@ -1009,7 +1000,7 @@ impl<'a> TcpSocket<'a> {
|
|||||||
|
|
||||||
// FIN packets in FIN-WAIT-1 state change it to CLOSING, or to TIME-WAIT
|
// FIN packets in FIN-WAIT-1 state change it to CLOSING, or to TIME-WAIT
|
||||||
// if they also acknowledge our FIN.
|
// if they also acknowledge our FIN.
|
||||||
(State::FinWait1, TcpRepr { control: TcpControl::Fin, .. }) => {
|
(State::FinWait1, TcpControl::Fin) => {
|
||||||
self.remote_seq_no += 1;
|
self.remote_seq_no += 1;
|
||||||
if ack_of_fin {
|
if ack_of_fin {
|
||||||
self.set_state(State::TimeWait);
|
self.set_state(State::TimeWait);
|
||||||
@ -1021,14 +1012,14 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIN packets in FIN-WAIT-2 state change it to TIME-WAIT.
|
// FIN packets in FIN-WAIT-2 state change it to TIME-WAIT.
|
||||||
(State::FinWait2, TcpRepr { control: TcpControl::Fin, .. }) => {
|
(State::FinWait2, TcpControl::Fin) => {
|
||||||
self.remote_seq_no += 1;
|
self.remote_seq_no += 1;
|
||||||
self.set_state(State::TimeWait);
|
self.set_state(State::TimeWait);
|
||||||
self.timer.set_for_close(timestamp);
|
self.timer.set_for_close(timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACK packets in CLOSING state change it to TIME-WAIT.
|
// ACK packets in CLOSING state change it to TIME-WAIT.
|
||||||
(State::Closing, TcpRepr { control: TcpControl::None, .. }) => {
|
(State::Closing, TcpControl::None) => {
|
||||||
if ack_of_fin {
|
if ack_of_fin {
|
||||||
self.set_state(State::TimeWait);
|
self.set_state(State::TimeWait);
|
||||||
self.timer.set_for_close(timestamp);
|
self.timer.set_for_close(timestamp);
|
||||||
@ -1038,12 +1029,12 @@ impl<'a> TcpSocket<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ACK packets in CLOSE-WAIT state reset the retransmit timer.
|
// ACK packets in CLOSE-WAIT state reset the retransmit timer.
|
||||||
(State::CloseWait, TcpRepr { control: TcpControl::None, .. }) => {
|
(State::CloseWait, TcpControl::None) => {
|
||||||
self.timer.reset();
|
self.timer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACK packets in LAST-ACK state change it to CLOSED.
|
// ACK packets in LAST-ACK state change it to CLOSED.
|
||||||
(State::LastAck, TcpRepr { control: TcpControl::None, .. }) => {
|
(State::LastAck, TcpControl::None) => {
|
||||||
// Clear the remote endpoint, or we'll send an RST there.
|
// Clear the remote endpoint, or we'll send an RST there.
|
||||||
self.set_state(State::Closed);
|
self.set_state(State::Closed);
|
||||||
self.remote_endpoint = IpEndpoint::default();
|
self.remote_endpoint = IpEndpoint::default();
|
||||||
@ -1357,16 +1348,13 @@ mod test {
|
|||||||
fn send(socket: &mut TcpSocket, timestamp: u64, repr: &TcpRepr) ->
|
fn send(socket: &mut TcpSocket, timestamp: u64, repr: &TcpRepr) ->
|
||||||
Result<Option<TcpRepr<'static>>> {
|
Result<Option<TcpRepr<'static>>> {
|
||||||
trace!("send: {}", repr);
|
trace!("send: {}", repr);
|
||||||
let mut buffer = vec![0; repr.buffer_len()];
|
|
||||||
let mut packet = TcpPacket::new(&mut buffer);
|
|
||||||
repr.emit(&mut packet, &REMOTE_IP, &LOCAL_IP);
|
|
||||||
let ip_repr = IpRepr::Unspecified {
|
let ip_repr = IpRepr::Unspecified {
|
||||||
src_addr: REMOTE_IP,
|
src_addr: REMOTE_IP,
|
||||||
dst_addr: LOCAL_IP,
|
dst_addr: LOCAL_IP,
|
||||||
protocol: IpProtocol::Tcp,
|
protocol: IpProtocol::Tcp,
|
||||||
payload_len: repr.buffer_len()
|
payload_len: repr.buffer_len()
|
||||||
};
|
};
|
||||||
match socket.process(timestamp, &ip_repr, &packet.into_inner()[..]) {
|
match socket.process(timestamp, &ip_repr, repr) {
|
||||||
Ok(Some((_ip_repr, repr))) => {
|
Ok(Some((_ip_repr, repr))) => {
|
||||||
trace!("recv: {}", repr);
|
trace!("recv: {}", repr);
|
||||||
Ok(Some(repr))
|
Ok(Some(repr))
|
||||||
|
@ -2,8 +2,7 @@ use core::cmp::min;
|
|||||||
use managed::Managed;
|
use managed::Managed;
|
||||||
|
|
||||||
use {Error, Result};
|
use {Error, Result};
|
||||||
use wire::{IpProtocol, IpEndpoint};
|
use wire::{IpProtocol, IpEndpoint, UdpRepr};
|
||||||
use wire::{UdpPacket, UdpRepr};
|
|
||||||
use socket::{Socket, IpRepr};
|
use socket::{Socket, IpRepr};
|
||||||
use storage::{Resettable, RingBuffer};
|
use storage::{Resettable, RingBuffer};
|
||||||
|
|
||||||
@ -180,12 +179,7 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
|
|||||||
Ok((length, endpoint))
|
Ok((length, endpoint))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process(&mut self, ip_repr: &IpRepr, payload: &[u8]) -> Result<()> {
|
pub(crate) fn process(&mut self, ip_repr: &IpRepr, repr: &UdpRepr) -> Result<()> {
|
||||||
debug_assert!(ip_repr.protocol() == IpProtocol::Udp);
|
|
||||||
|
|
||||||
let packet = UdpPacket::new_checked(&payload[..ip_repr.payload_len()])?;
|
|
||||||
let repr = UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr())?;
|
|
||||||
|
|
||||||
// Reject packets with a wrong destination.
|
// Reject packets with a wrong destination.
|
||||||
if self.endpoint.port != repr.dst_port { return Err(Error::Rejected) }
|
if self.endpoint.port != repr.dst_port { return Err(Error::Rejected) }
|
||||||
if !self.endpoint.addr.is_unspecified() &&
|
if !self.endpoint.addr.is_unspecified() &&
|
||||||
@ -343,17 +337,14 @@ mod test {
|
|||||||
let mut socket = socket(buffer(1), buffer(0));
|
let mut socket = socket(buffer(1), buffer(0));
|
||||||
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
|
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
|
||||||
|
|
||||||
let mut buffer = vec![0; REMOTE_UDP_REPR.buffer_len()];
|
|
||||||
REMOTE_UDP_REPR.emit(&mut UdpPacket::new(&mut buffer), &LOCAL_IP, &REMOTE_IP);
|
|
||||||
|
|
||||||
assert!(!socket.can_recv());
|
assert!(!socket.can_recv());
|
||||||
assert_eq!(socket.recv(), Err(Error::Exhausted));
|
assert_eq!(socket.recv(), Err(Error::Exhausted));
|
||||||
|
|
||||||
assert_eq!(socket.process(&REMOTE_IP_REPR, &buffer),
|
assert_eq!(socket.process(&REMOTE_IP_REPR, &REMOTE_UDP_REPR),
|
||||||
Ok(()));
|
Ok(()));
|
||||||
assert!(socket.can_recv());
|
assert!(socket.can_recv());
|
||||||
|
|
||||||
assert_eq!(socket.process(&REMOTE_IP_REPR, &buffer),
|
assert_eq!(socket.process(&REMOTE_IP_REPR, &REMOTE_UDP_REPR),
|
||||||
Err(Error::Exhausted));
|
Err(Error::Exhausted));
|
||||||
assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END)));
|
assert_eq!(socket.recv(), Ok((&b"abcdef"[..], REMOTE_END)));
|
||||||
assert!(!socket.can_recv());
|
assert!(!socket.can_recv());
|
||||||
@ -364,9 +355,8 @@ mod test {
|
|||||||
let mut socket = socket(buffer(1), buffer(0));
|
let mut socket = socket(buffer(1), buffer(0));
|
||||||
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
|
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
|
||||||
|
|
||||||
let mut buffer = vec![0; REMOTE_UDP_REPR.buffer_len()];
|
assert_eq!(socket.process(&REMOTE_IP_REPR, &REMOTE_UDP_REPR),
|
||||||
REMOTE_UDP_REPR.emit(&mut UdpPacket::new(&mut buffer), &LOCAL_IP, &REMOTE_IP);
|
Ok(()));
|
||||||
assert_eq!(socket.process(&REMOTE_IP_REPR, &buffer), Ok(()));
|
|
||||||
|
|
||||||
let mut slice = [0; 4];
|
let mut slice = [0; 4];
|
||||||
assert_eq!(socket.recv_slice(&mut slice[..]), Ok((4, REMOTE_END)));
|
assert_eq!(socket.recv_slice(&mut slice[..]), Ok((4, REMOTE_END)));
|
||||||
@ -379,9 +369,7 @@ mod test {
|
|||||||
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
|
assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
|
||||||
|
|
||||||
let udp_repr = UdpRepr { payload: &[0; 100][..], ..REMOTE_UDP_REPR };
|
let udp_repr = UdpRepr { payload: &[0; 100][..], ..REMOTE_UDP_REPR };
|
||||||
let mut buffer = vec![0; udp_repr.buffer_len()];
|
assert_eq!(socket.process(&REMOTE_IP_REPR, &udp_repr),
|
||||||
udp_repr.emit(&mut UdpPacket::new(&mut buffer), &LOCAL_IP, &REMOTE_IP);
|
|
||||||
assert_eq!(socket.process(&REMOTE_IP_REPR, &buffer),
|
|
||||||
Err(Error::Truncated));
|
Err(Error::Truncated));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user