Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: ef4af850e098
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 401d004e28dc
Choose a head ref
  • 3 commits
  • 6 files changed
  • 1 contributor

Commits on Nov 9, 2017

  1. Remove impl Ord/PartialOrd for Cidr.

    It's not obvious that CIDRs are ordered in any particular meaningful
    way.
    whitequark committed Nov 9, 2017
    Copy the full SHA
    1979072 View commit details
  2. Style. NFCI.

    whitequark committed Nov 9, 2017
    6
    Copy the full SHA
    ffcd3ab View commit details

Commits on Nov 10, 2017

  1. Update README.

    whitequark committed Nov 10, 2017
    Copy the full SHA
    401d004 View commit details
Showing with 64 additions and 62 deletions.
  1. +11 −5 README.md
  2. +12 −12 src/iface/ethernet.rs
  3. +1 −1 src/lib.rs
  4. +38 −42 src/socket/icmp.rs
  5. +1 −1 src/wire/ip.rs
  6. +1 −1 src/wire/ipv4.rs
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -36,23 +36,29 @@ The only supported internetworking protocol is IPv4.
* IPv4 fragmentation is **not** supported.
* IPv4 options are **not** supported and are silently ignored.
* IPv4 routes (other than the default one) are **not** supported.

### ICMP layer

The ICMPv4 protocol is supported, and ICMP sockets are available.

* ICMPv4 header checksum is supported.
* ICMPv4 echo requests and replies are supported.
* ICMPv4 echo replies are generated in response to echo requests.
* ICMP sockets can listen to ICMPv4 Port Unreachable messages, or any ICMPv4 messages with
a given IPv4 identifier field.
* ICMPv4 protocol unreachable messages are **not** passed to higher layers when received.
* ICMPv4 time exceeded messages are **not** supported.
* ICMPv4 parameter problem messages are **not** supported.
* ICMPv4 parameter problem messages are **not** generated.

### UDP layer

The UDP protocol is supported over IPv4.
The UDP protocol is supported over IPv4, and UDP sockets are available.

* Header checksum is always generated and validated.
* In response to a packet arriving at a port without a listening socket,
an ICMP destination unreachable message is generated.

### TCP layer

The TCP protocol is supported over IPv4. Server and client sockets are supported.
The TCP protocol is supported over IPv4, and server and client TCP sockets are available.

* Header checksum is generated and validated.
* Maximum segment size is negotiated.
24 changes: 12 additions & 12 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -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) {
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
80 changes: 38 additions & 42 deletions src/socket/icmp.rs
Original file line number Diff line number Diff line change
@@ -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<T: Into<Endpoint>>(&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<F>(&mut self, caps: &DeviceCapabilities,
emit: F) -> Result<()>
where F: FnOnce((IpRepr, Icmpv4Repr)) -> Result<()> {
pub(crate) fn dispatch<F>(&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;
2 changes: 1 addition & 1 deletion src/wire/ip.rs
Original file line number Diff line number Diff line change
@@ -136,7 +136,7 @@ impl fmt::Display for Address {

/// A specification of a CIDR block, containing an address and a variable-length
/// subnet masking prefix length.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cidr {
Ipv4(Ipv4Cidr),
#[doc(hidden)]
2 changes: 1 addition & 1 deletion src/wire/ipv4.rs
Original file line number Diff line number Diff line change
@@ -80,7 +80,7 @@ impl fmt::Display for Address {

/// A specification of an IPv4 CIDR block, containing an address and a variable-length
/// subnet masking prefix length.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Cidr {
address: Address,
prefix_len: u8,