Fail-free ingress

This commit is contained in:
Ryan Summers 2021-05-31 17:30:45 +02:00
parent 8d4e255090
commit 95829934db
9 changed files with 33 additions and 36 deletions

View File

@ -667,6 +667,7 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
let response = $response;
neighbor_addr = Some(response.ip_repr().dst_addr());
device_result = inner.dispatch_ip(tx_token, timestamp, response);
device_result
})
}
@ -694,7 +695,7 @@ impl<'a, DeviceT> Interface<'a, DeviceT>
#[cfg(feature = "proto-ipv6")]
(IpRepr::Ipv6(ipv6_repr), IcmpRepr::Ipv6(icmpv6_repr)) =>
respond!(IpPacket::Icmpv6((ipv6_repr, icmpv6_repr))),
_ => panic!("Invalid ICMP represnetation"),
_ => Err(Error::Unaddressable),
}
}),
#[cfg(feature = "socket-udp")]

View File

@ -298,7 +298,7 @@ impl Dhcpv4Socket {
}
pub(crate) fn dispatch<F>(&mut self, now: Instant, ethernet_addr: EthernetAddress, ip_mtu: usize, emit: F) -> Result<()>
where F: FnOnce((Ipv4Repr, UdpRepr, DhcpRepr)) {
where F: FnOnce((Ipv4Repr, UdpRepr, DhcpRepr)) -> Result<()> {
// Worst case biggest IPv4 header length.
// 0x0f * 4 = 60 bytes.
@ -350,7 +350,7 @@ impl Dhcpv4Socket {
// send packet
net_debug!("DHCP send DISCOVER to {}: {:?}", ipv4_repr.dst_addr, dhcp_repr);
ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len();
emit((ipv4_repr, udp_repr, dhcp_repr));
emit((ipv4_repr, udp_repr, dhcp_repr))?;
// Update state AFTER the packet has been successfully sent.
state.retry_at = now + DISCOVER_TIMEOUT;
@ -376,7 +376,7 @@ impl Dhcpv4Socket {
net_debug!("DHCP send request to {}: {:?}", ipv4_repr.dst_addr, dhcp_repr);
ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len();
emit((ipv4_repr, udp_repr, dhcp_repr));
emit((ipv4_repr, udp_repr, dhcp_repr))?;
// Exponential backoff: Double every 2 retries.
state.retry_at = now + (REQUEST_TIMEOUT << (state.retry as u32 / 2));
@ -405,7 +405,7 @@ impl Dhcpv4Socket {
net_debug!("DHCP send renew to {}: {:?}", ipv4_repr.dst_addr, dhcp_repr);
ipv4_repr.payload_len = udp_repr.header_len() + dhcp_repr.buffer_len();
emit((ipv4_repr, udp_repr, dhcp_repr));
emit((ipv4_repr, udp_repr, dhcp_repr))?;
// In both RENEWING and REBINDING states, if the client receives no
// response to its DHCPREQUEST message, the client SHOULD wait one-half

View File

@ -402,7 +402,7 @@ impl<'a> IcmpSocket<'a> {
}
pub(crate) fn dispatch<F>(&mut self, emit: F) -> Result<()>
where F: FnOnce((IpRepr, IcmpRepr))
where F: FnOnce((IpRepr, IcmpRepr)) -> Result<()>
{
let handle = self.meta.handle;
let hop_limit = self.hop_limit.unwrap_or(64);
@ -413,13 +413,7 @@ impl<'a> IcmpSocket<'a> {
#[cfg(feature = "proto-ipv4")]
IpAddress::Ipv4(ipv4_addr) => {
let packet = Icmpv4Packet::new_unchecked(&*packet_buf);
let repr = match Icmpv4Repr::parse(&packet, &ChecksumCapabilities::ignored()) {
Ok(repr) => repr,
Err(err) => {
net_debug!("ICMPv4 represnetation invalid: {}", err);
return
},
};
let repr = Icmpv4Repr::parse(&packet, &ChecksumCapabilities::ignored())?;
let ip_repr = IpRepr::Ipv4(Ipv4Repr {
src_addr: Ipv4Address::default(),
dst_addr: ipv4_addr,
@ -433,14 +427,7 @@ impl<'a> IcmpSocket<'a> {
IpAddress::Ipv6(ipv6_addr) => {
let packet = Icmpv6Packet::new_unchecked(&*packet_buf);
let src_addr = Ipv6Address::default();
let repr = match Icmpv6Repr::parse(&src_addr.into(), &ipv6_addr.into(), &packet,
&ChecksumCapabilities::ignored()) {
Ok(repr) => repr,
Err(err) => {
net_debug!("ICMPv6 represnetation invalid: {}", err);
return
},
};
let repr = Icmpv6Repr::parse(&src_addr.into(), &ipv6_addr.into(), &packet, &ChecksumCapabilities::ignored())?;
let ip_repr = IpRepr::Ipv6(Ipv6Repr {
src_addr: src_addr,
dst_addr: ipv6_addr,
@ -450,7 +437,7 @@ impl<'a> IcmpSocket<'a> {
});
emit((ip_repr, IcmpRepr::Ipv6(repr)))
},
_ => net_debug!("ICMP destination unaddressable"),
_ => Err(Error::Unaddressable)
}
})?;

View File

@ -228,7 +228,7 @@ impl<'a> RawSocket<'a> {
pub(crate) fn dispatch<F>(&mut self, checksum_caps: &ChecksumCapabilities, emit: F) ->
Result<()>
where F: FnOnce((IpRepr, &[u8])) {
where F: FnOnce((IpRepr, &[u8])) -> Result<()> {
fn prepare<'a>(protocol: IpProtocol, buffer: &'a mut [u8],
_checksum_caps: &ChecksumCapabilities) -> Result<(IpRepr, &'a [u8])> {
match IpVersion::of_packet(buffer)? {
@ -275,6 +275,8 @@ impl<'a> RawSocket<'a> {
net_debug!("{}:{}:{}: dropping outgoing packet ({})",
handle, ip_version, ip_protocol,
error);
// Return Ok(()) so the packet is dequeued.
Ok(())
}
}
})?;

View File

@ -1669,7 +1669,7 @@ impl<'a> TcpSocket<'a> {
pub(crate) fn dispatch<F>(&mut self, timestamp: Instant, ip_mtu: usize,
emit: F) -> Result<()>
where F: FnOnce((IpRepr, TcpRepr)) {
where F: FnOnce((IpRepr, TcpRepr)) -> Result<()> {
if !self.remote_endpoint.is_specified() { return Err(Error::Exhausted) }
if self.remote_last_ts.is_none() {
@ -1867,7 +1867,7 @@ impl<'a> TcpSocket<'a> {
// to not waste time waiting for the retransmit timer on packets that we know
// for sure will not be successfully transmitted.
ip_repr.set_payload_len(repr.buffer_len());
emit((ip_repr, repr));
emit((ip_repr, repr))?;
// We've sent something, whether useful data or a keep-alive packet, so rewind
// the keep-alive timer.

View File

@ -296,7 +296,7 @@ impl<'a> UdpSocket<'a> {
}
pub(crate) fn dispatch<F>(&mut self, emit: F) -> Result<()>
where F: FnOnce((IpRepr, UdpRepr, &[u8])) {
where F: FnOnce((IpRepr, UdpRepr, &[u8])) -> Result<()> {
let handle = self.handle();
let endpoint = self.endpoint;
let hop_limit = self.hop_limit.unwrap_or(64);

View File

@ -30,4 +30,4 @@ impl WakerRegistration {
pub fn wake(&mut self) {
self.waker.take().map(|w| w.wake());
}
}
}

View File

@ -125,7 +125,7 @@ impl<'a, H> PacketBuffer<'a, H> {
/// Call `f` with a single packet from the buffer, and dequeue the packet if `f`
/// returns successfully, or return `Err(Error::Exhausted)` if the buffer is empty.
pub fn dequeue_with<'c, R, F>(&'c mut self, f: F) -> Result<R>
where F: FnOnce(&mut H, &'c mut [u8]) -> R {
where F: FnOnce(&mut H, &'c mut [u8]) -> Result<R> {
self.dequeue_padding();
let Self { ref mut metadata_ring, ref mut payload_ring } = *self;
@ -136,9 +136,12 @@ impl<'a, H> PacketBuffer<'a, H> {
payload_ring.dequeue_many_with(|payload_buf| {
debug_assert!(payload_buf.len() >= size);
(size, Ok(f(header.as_mut().unwrap(), &mut payload_buf[..size])))
match f(header.as_mut().unwrap(), &mut payload_buf[..size]) {
Ok(val) => (size, Ok(val)),
Err(err) => (0, Err(err)),
}
}).1
})?
})
}
/// Dequeue a single packet from the buffer, and return a reference to its payload

View File

@ -136,14 +136,18 @@ impl<'a, T: 'a> RingBuffer<'a, T> {
/// Call `f` with a single buffer element, and dequeue the element if `f`
/// returns successfully, or return `Err(Error::Exhausted)` if the buffer is empty.
pub fn dequeue_one_with<'b, R, F>(&'b mut self, f: F) -> Result<R>
where F: FnOnce(&'b mut T) -> R {
where F: FnOnce(&'b mut T) -> Result<R> {
if self.is_empty() { return Err(Error::Exhausted) }
let next_at = self.get_idx_unchecked(1);
let result = f(&mut self.storage[self.read_at]);
self.length -= 1;
self.read_at = next_at;
Ok(result)
match f(&mut self.storage[self.read_at]) {
Ok(result) => {
self.length -= 1;
self.read_at = next_at;
Ok(result)
}
Err(error) => Err(error)
}
}
/// Dequeue an element from the buffer, and return a reference to it,
@ -151,7 +155,7 @@ impl<'a, T: 'a> RingBuffer<'a, T> {
///
/// This function is a shortcut for `ring_buf.dequeue_one_with(Ok)`.
pub fn dequeue_one(&mut self) -> Result<&mut T> {
self.dequeue_one_with(|buf| buf)
self.dequeue_one_with(Ok)
}
}