diff --git a/src/iface/ethernet.rs b/src/iface/ethernet.rs index 27e92a64..fc2fb0b8 100644 --- a/src/iface/ethernet.rs +++ b/src/iface/ethernet.rs @@ -20,12 +20,12 @@ use wire::{TcpPacket, TcpRepr, TcpControl}; use socket::{Socket, SocketSet, AnySocket}; #[cfg(feature = "socket-raw")] use socket::RawSocket; +#[cfg(feature = "socket-icmp")] +use socket::IcmpSocket; #[cfg(feature = "socket-udp")] use socket::UdpSocket; #[cfg(feature = "socket-tcp")] use socket::TcpSocket; -#[cfg(feature = "socket-icmp")] -use socket::IcmpSocket; use super::ArpCache; /// An Ethernet network interface. @@ -223,6 +223,16 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> device_result = inner.dispatch(tx_token, timestamp, Packet::Raw(response)); device_result }, &caps.checksum), + #[cfg(feature = "socket-icmp")] + Socket::Icmp(ref mut socket) => + socket.dispatch(&caps, |response| { + let tx_token = device.transmit().ok_or(Error::Exhausted)?; + match response { + (IpRepr::Ipv4(repr), icmp_repr) => + inner.dispatch(tx_token, timestamp, Packet::Icmpv4((repr, icmp_repr))), + _ => Err(Error::Unaddressable), + } + }), #[cfg(feature = "socket-udp")] Socket::Udp(ref mut socket) => socket.dispatch(|response| { @@ -237,16 +247,6 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT> device_result = inner.dispatch(tx_token, timestamp, Packet::Tcp(response)); device_result }), - #[cfg(feature = "socket-icmp")] - Socket::Icmp(ref mut socket) => - socket.dispatch(&caps, |response| { - let tx_token = device.transmit().ok_or(Error::Exhausted)?; - match response { - (IpRepr::Ipv4(repr), icmp_repr) => - inner.dispatch(tx_token, timestamp, Packet::Icmpv4((repr, icmp_repr))), - _ => Err(Error::Unaddressable), - } - }), Socket::__Nonexhaustive(_) => unreachable!() }; match (device_result, socket_result) { diff --git a/src/lib.rs b/src/lib.rs index 89fe6e0b..1b6dab6c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ //! //! # The socket layer //! The socket layer APIs are provided in the module [socket](socket/index.html); currently, -//! TCP, UDP, ICMP, and Raw sockets are provided. The socket API provides the usual primitives, +//! raw, ICMP, TCP, and UDP sockets are provided. The socket API provides the usual primitives, //! but necessarily differs in many from the [Berkeley socket API][berk], as the latter was //! not designed to be used without heap allocation. //! [berk]: https://en.wikipedia.org/wiki/Berkeley_sockets diff --git a/src/socket/icmp.rs b/src/socket/icmp.rs index 50c9eb09..59cbe13e 100644 --- a/src/socket/icmp.rs +++ b/src/socket/icmp.rs @@ -167,43 +167,49 @@ impl<'a, 'b> IcmpSocket<'a, 'b> { /// diagnose connection problems. /// /// ``` - /// # use smoltcp::socket::{IcmpPacketBuffer, IcmpSocketBuffer}; + /// # use smoltcp::socket::{Socket, IcmpSocket, IcmpPacketBuffer, IcmpSocketBuffer}; /// # let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]); /// # let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]); /// use smoltcp::wire::IpEndpoint; - /// use smoltcp::socket::{Socket, IcmpSocket, IcmpEndpoint}; - /// let mut icmp_socket = match IcmpSocket::new(rx_buffer, tx_buffer) { - /// Socket::Icmp(socket) => socket, - /// _ => unreachable!() - /// }; + /// use smoltcp::socket::IcmpEndpoint; + /// + /// let mut icmp_socket = // ... + /// # match IcmpSocket::new(rx_buffer, tx_buffer) { + /// # Socket::Icmp(socket) => socket, + /// # _ => unreachable!() + /// # }; + /// /// // Bind to ICMP error responses for UDP packets sent from port 53. /// let endpoint = IpEndpoint::from(53); /// icmp_socket.bind(IcmpEndpoint::Udp(endpoint)).unwrap(); /// ``` /// - /// ## Bind to a specific ICMP identifier: + /// ## Bind to a specific IP identifier: /// /// To [send] and [recv] ICMP packets that are not associated with a specific UDP - /// port, the socket may be bound to a specific ICMP identifier using + /// port, the socket may be bound to a specific IP identifier using /// [IcmpEndpoint::Ident]. This is useful for sending and receiving Echo Request/Reply /// messages. /// /// ``` - /// # use smoltcp::socket::{IcmpPacketBuffer, IcmpSocketBuffer}; + /// # use smoltcp::socket::{Socket, IcmpSocket, IcmpPacketBuffer, IcmpSocketBuffer}; /// # let rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]); /// # let tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketBuffer::new(vec![0; 20])]); - /// use smoltcp::socket::{Socket, IcmpSocket, IcmpEndpoint}; - /// let mut icmp_socket = match IcmpSocket::new(rx_buffer, tx_buffer) { - /// Socket::Icmp(socket) => socket, - /// _ => unreachable!() - /// }; - /// // Bind to ICMP messages with the identifier 0x1234 + /// use smoltcp::socket::IcmpEndpoint; + /// + /// let mut icmp_socket = // ... + /// # match IcmpSocket::new(rx_buffer, tx_buffer) { + /// # Socket::Icmp(socket) => socket, + /// # _ => unreachable!() + /// # }; + /// + /// // Bind to ICMP messages with the IP identifier 0x1234 /// icmp_socket.bind(IcmpEndpoint::Ident(0x1234)).unwrap(); /// ``` /// /// [is_specified]: enum.IcmpEndpoint.html#method.is_specified - /// [IcmpEndpoint::Ident]: enum.IcmpEndpoint#variant.Ident - /// [IcmpEndpoint::Udp]: enum.IcmpEndpoint#variant.Udp + /// [IcmpEndpoint::Ident]: enum.IcmpEndpoint.html#variant.Ident + /// [IcmpEndpoint::Udp]: enum.IcmpEndpoint.html#variant.Udp /// [send]: #method.send /// [recv]: #method.recv pub fn bind>(&mut self, endpoint: T) -> Result<()> { @@ -241,7 +247,7 @@ impl<'a, 'b> IcmpSocket<'a, 'b> { /// /// This function returns `Err(Error::Exhausted)` if the transmit buffer is full, /// `Err(Error::Truncated)` if the requested size is larger than the packet buffer - /// size, and `Err(Error::Unaddressable)` if the or remote address, is unspecified. + /// size, and `Err(Error::Unaddressable)` if the remote address is unspecified. pub fn send(&mut self, size: usize, endpoint: IpAddress) -> Result<&mut [u8]> { if endpoint.is_unspecified() { return Err(Error::Unaddressable) @@ -289,34 +295,24 @@ impl<'a, 'b> IcmpSocket<'a, 'b> { /// the given sockets received buffer. pub(crate) fn accepts(&self, ip_repr: &IpRepr, icmp_repr: &Icmpv4Repr, cksum: &ChecksumCapabilities) -> bool { - match self.endpoint { + match (&self.endpoint, icmp_repr) { // If we are bound to ICMP errors associated to a UDP port, only // accept Destination Unreachable messages with the data containing // a UDP packet send from the local port we are bound to. - Endpoint::Udp(endpoint) => - if !endpoint.addr.is_unspecified() && endpoint.addr != ip_repr.dst_addr() { - false - } else { - match icmp_repr { - &Icmpv4Repr::DstUnreachable { data, .. } => { - let packet = UdpPacket::new(data); - match UdpRepr::parse(&packet, &ip_repr.src_addr(), - &ip_repr.dst_addr(), cksum) { - Ok(repr) => endpoint.port == repr.src_port, - Err(_) => false, - } - } - _ => false, - } + (&Endpoint::Udp(endpoint), &Icmpv4Repr::DstUnreachable { data, .. }) + if endpoint.addr.is_unspecified() || endpoint.addr == ip_repr.dst_addr() => { + let packet = UdpPacket::new(data); + match UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr(), cksum) { + Ok(repr) => endpoint.port == repr.src_port, + Err(_) => false, } + } // If we are bound to a specific ICMP identifier value, only accept an // Echo Request/Reply with the identifier field matching the endpoint // port. - Endpoint::Ident(id) => match icmp_repr { - &Icmpv4Repr::EchoRequest { ident, .. } | &Icmpv4Repr::EchoReply { ident, .. } => - ident == id, - _ => false, - } + (&Endpoint::Ident(bound_ident), &Icmpv4Repr::EchoRequest { ident, .. }) | + (&Endpoint::Ident(bound_ident), &Icmpv4Repr::EchoReply { ident, .. }) => + ident == bound_ident, _ => false, } } @@ -330,9 +326,9 @@ impl<'a, 'b> IcmpSocket<'a, 'b> { Ok(()) } - pub(crate) fn dispatch(&mut self, caps: &DeviceCapabilities, - emit: F) -> Result<()> - where F: FnOnce((IpRepr, Icmpv4Repr)) -> Result<()> { + pub(crate) fn dispatch(&mut self, caps: &DeviceCapabilities, emit: F) -> Result<()> + where F: FnOnce((IpRepr, Icmpv4Repr)) -> Result<()> + { let handle = self.handle; let ttl = self.ttl.unwrap_or(64); let checksum = &caps.checksum;