Bläddra i källkod

Fail-free ingress

Ryan Summers 3 år sedan
förälder
incheckning
6091350f57

+ 2 - 1
src/iface/interface.rs

@@ -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")]

+ 4 - 4
src/socket/dhcpv4.rs

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

+ 4 - 17
src/socket/icmp.rs

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

+ 3 - 1
src/socket/raw.rs

@@ -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(())
                 }
             }
         })?;

+ 2 - 2
src/socket/tcp.rs

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

+ 1 - 1
src/socket/udp.rs

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

+ 1 - 1
src/socket/waker.rs

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

+ 6 - 3
src/storage/packet_buffer.rs

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

+ 10 - 6
src/storage/ring_buffer.rs

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