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: 8a3dee094328
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: f6f7dc8cb653
Choose a head ref
  • 3 commits
  • 11 files changed
  • 1 contributor

Commits on Dec 13, 2016

  1. Copy the full SHA
    04b546a View commit details

Commits on Dec 14, 2016

  1. Copy the full SHA
    f23e3c4 View commit details
  2. Copy the full SHA
    f6f7dc8 View commit details
Showing with 472 additions and 130 deletions.
  1. +3 −3 examples/smoltcpserver.rs
  2. +14 −15 src/iface/arp_cache.rs
  3. +8 −8 src/iface/ethernet.rs
  4. +0 −49 src/iface/mod.rs
  5. +2 −1 src/wire/arp.rs
  6. +6 −4 src/wire/ethernet.rs
  7. +22 −20 src/wire/icmpv4.rs
  8. +91 −9 src/wire/ip.rs
  9. +17 −15 src/wire/ipv4.rs
  10. +10 −6 src/wire/mod.rs
  11. +299 −0 src/wire/udp.rs
6 changes: 3 additions & 3 deletions examples/smoltcpserver.rs
Original file line number Diff line number Diff line change
@@ -3,14 +3,14 @@ extern crate smoltcp;

use std::env;
use smoltcp::phy::{Tracer, TapInterface};
use smoltcp::wire::{EthernetFrame, EthernetAddress};
use smoltcp::iface::{ProtocolAddress, SliceArpCache, EthernetInterface};
use smoltcp::wire::{EthernetFrame, EthernetAddress, InternetAddress};
use smoltcp::iface::{SliceArpCache, EthernetInterface};

fn main() {
let ifname = env::args().nth(1).unwrap();

let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
let protocol_addrs = [ProtocolAddress::ipv4([192, 168, 69, 1])];
let protocol_addrs = [InternetAddress::ipv4([192, 168, 69, 1])];

let device = TapInterface::new(ifname.as_ref()).unwrap();
let device = Tracer::<_, EthernetFrame<&[u8]>>::new(device);
29 changes: 14 additions & 15 deletions src/iface/arp_cache.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use wire::EthernetAddress;
use super::ProtocolAddress;
use wire::{EthernetAddress, InternetAddress};

/// An Address Resolution Protocol cache.
///
/// This cache maps protocol addresses to hardware addresses.
pub trait Cache {
/// Update the cache to map given protocol address to given hardware address.
fn fill(&mut self, protocol_addr: ProtocolAddress, hardware_addr: EthernetAddress);
fn fill(&mut self, protocol_addr: InternetAddress, hardware_addr: EthernetAddress);

/// Look up the hardware address corresponding for the given protocol address.
fn lookup(&mut self, protocol_addr: ProtocolAddress) -> Option<EthernetAddress>;
fn lookup(&mut self, protocol_addr: InternetAddress) -> Option<EthernetAddress>;
}

/// An Address Resolution Protocol cache backed by a slice.
@@ -26,7 +25,7 @@ pub trait Cache {
/// let mut arp_cache = SliceArpCache::new(&mut arp_cache_storage);
/// ```
pub struct SliceCache<'a> {
storage: &'a mut [(ProtocolAddress, EthernetAddress, usize)],
storage: &'a mut [(InternetAddress, EthernetAddress, usize)],
counter: usize
}

@@ -35,7 +34,7 @@ impl<'a> SliceCache<'a> {
///
/// # Panics
/// This function panics if `storage.len() == 0`.
pub fn new(storage: &'a mut [(ProtocolAddress, EthernetAddress, usize)]) -> SliceCache<'a> {
pub fn new(storage: &'a mut [(InternetAddress, EthernetAddress, usize)]) -> SliceCache<'a> {
if storage.len() == 0 {
panic!("ARP slice cache created with empty storage")
}
@@ -50,9 +49,9 @@ impl<'a> SliceCache<'a> {
}

/// Find an entry for the given protocol address, if any.
fn find(&self, protocol_addr: ProtocolAddress) -> Option<usize> {
// The order of comparison is important: any valid ProtocolAddress should
// sort before ProtocolAddress::Invalid.
fn find(&self, protocol_addr: InternetAddress) -> Option<usize> {
// The order of comparison is important: any valid InternetAddress should
// sort before InternetAddress::Invalid.
self.storage.binary_search_by_key(&protocol_addr, |&(key, _, _)| key).ok()
}

@@ -68,14 +67,14 @@ impl<'a> SliceCache<'a> {
}

impl<'a> Cache for SliceCache<'a> {
fn fill(&mut self, protocol_addr: ProtocolAddress, hardware_addr: EthernetAddress) {
fn fill(&mut self, protocol_addr: InternetAddress, hardware_addr: EthernetAddress) {
if let None = self.find(protocol_addr) {
self.storage[self.lru()] = (protocol_addr, hardware_addr, self.counter);
self.sort()
}
}

fn lookup(&mut self, protocol_addr: ProtocolAddress) -> Option<EthernetAddress> {
fn lookup(&mut self, protocol_addr: InternetAddress) -> Option<EthernetAddress> {
if let Some(index) = self.find(protocol_addr) {
let (_protocol_addr, hardware_addr, ref mut counter) = self.storage[index];
self.counter += 1;
@@ -96,10 +95,10 @@ mod test {
const HADDR_C: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 3]);
const HADDR_D: EthernetAddress = EthernetAddress([0, 0, 0, 0, 0, 4]);

const PADDR_A: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 0]);
const PADDR_B: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 1]);
const PADDR_C: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 2]);
const PADDR_D: ProtocolAddress = ProtocolAddress::ipv4([0, 0, 0, 3]);
const PADDR_A: InternetAddress = InternetAddress::ipv4([0, 0, 0, 0]);
const PADDR_B: InternetAddress = InternetAddress::ipv4([0, 0, 0, 1]);
const PADDR_C: InternetAddress = InternetAddress::ipv4([0, 0, 0, 2]);
const PADDR_D: InternetAddress = InternetAddress::ipv4([0, 0, 0, 3]);

#[test]
fn test_slice_cache() {
16 changes: 8 additions & 8 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -2,18 +2,18 @@ use Error;
use phy::Device;
use wire::{EthernetAddress, EthernetProtocolType, EthernetFrame};
use wire::{ArpPacket, ArpRepr, ArpOperation};
use wire::InternetProtocolType;
use wire::{InternetAddress, InternetProtocolType};
use wire::{Ipv4Packet, Ipv4Repr};
use wire::{Icmpv4Packet, Icmpv4Repr};
use super::{ProtocolAddress, ArpCache};
use super::{ArpCache};

/// An Ethernet network interface.
#[derive(Debug)]
pub struct Interface<'a, DeviceT: Device, ArpCacheT: ArpCache> {
device: DeviceT,
arp_cache: ArpCacheT,
hardware_addr: EthernetAddress,
protocol_addrs: &'a [ProtocolAddress]
protocol_addrs: &'a [InternetAddress]
}

impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT> {
@@ -48,15 +48,15 @@ impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT>
}

/// Get the protocol addresses of the interface.
pub fn protocol_addrs(&self) -> &'a [ProtocolAddress] {
pub fn protocol_addrs(&self) -> &'a [InternetAddress] {
self.protocol_addrs
}

/// Set the protocol addresses of the interface.
///
/// # Panics
/// This function panics if any of the addresses is not unicast.
pub fn set_protocol_addrs(&mut self, addrs: &'a [ProtocolAddress]) {
pub fn set_protocol_addrs(&mut self, addrs: &'a [InternetAddress]) {
for addr in addrs {
if !addr.is_unicast() {
panic!("protocol address {} is not unicast", addr)
@@ -67,7 +67,7 @@ impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT>
}

/// Checks whether the interface has the given protocol address assigned.
pub fn has_protocol_addr<T: Into<ProtocolAddress>>(&self, addr: T) -> bool {
pub fn has_protocol_addr<T: Into<InternetAddress>>(&self, addr: T) -> bool {
let addr = addr.into();
self.protocol_addrs.iter().any(|&probe| probe == addr)
}
@@ -169,8 +169,8 @@ impl<'a, DeviceT: Device, ArpCacheT: ArpCache> Interface<'a, DeviceT, ArpCacheT>
if let Response::Nop = response { return Ok(()) }

let tx_size = self.device.mtu();
let tx_buffer = try!(self.device.transmit(tx_size));
let mut frame = try!(EthernetFrame::new(tx_buffer));
let mut tx_buffer = try!(self.device.transmit(tx_size));
let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
frame.set_src_addr(self.hardware_addr);

match response {
49 changes: 0 additions & 49 deletions src/iface/mod.rs
Original file line number Diff line number Diff line change
@@ -2,58 +2,9 @@
//!
//! The `iface` module deals with the *network interfaces*. It filters incoming frames,
//! provides lookup and caching of hardware addresses, and handles management packets.
use core::fmt;
use wire;

mod arp_cache;
mod ethernet;

pub use self::arp_cache::Cache as ArpCache;
pub use self::arp_cache::SliceCache as SliceArpCache;
pub use self::ethernet::Interface as EthernetInterface;

/// An internetworking protocol address.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum ProtocolAddress {
/// An invalid address.
/// May be used as a placeholder for storage where the address is not assigned yet.
Invalid,
/// An IPv4 address.
Ipv4(wire::Ipv4Address)
}

impl ProtocolAddress {
/// Create a protocol address wrapping an IPv4 address with the given octets.
pub const fn ipv4(octets: [u8; 4]) -> ProtocolAddress {
ProtocolAddress::Ipv4(wire::Ipv4Address(octets))
}

/// Query whether the address is a valid unicast address.
pub fn is_unicast(&self) -> bool {
match self {
&ProtocolAddress::Invalid => false,
&ProtocolAddress::Ipv4(addr) => addr.is_unicast()
}
}
}

impl Default for ProtocolAddress {
fn default() -> ProtocolAddress {
ProtocolAddress::Invalid
}
}

impl From<wire::Ipv4Address> for ProtocolAddress {
fn from(addr: wire::Ipv4Address) -> Self {
ProtocolAddress::Ipv4(addr)
}
}

impl fmt::Display for ProtocolAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ProtocolAddress::Invalid => write!(f, "(invalid)"),
&ProtocolAddress::Ipv4(addr) => write!(f, "{}", addr)
}
}
}
3 changes: 2 additions & 1 deletion src/wire/arp.rs
Original file line number Diff line number Diff line change
@@ -291,7 +291,8 @@ impl<T: AsRef<[u8]>> fmt::Display for Packet<T> {
match Repr::parse(self) {
Ok(repr) => write!(f, "{}", repr),
_ => {
try!(write!(f, "ARP htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}",
try!(write!(f, "ARP (unrecognized)"));
try!(write!(f, " htype={:?} ptype={:?} hlen={:?} plen={:?} op={:?}",
self.hardware_type(), self.protocol_type(),
self.hardware_len(), self.protocol_len(),
self.operation()));
10 changes: 6 additions & 4 deletions src/wire/ethernet.rs
Original file line number Diff line number Diff line change
@@ -72,10 +72,10 @@ pub struct Frame<T: AsRef<[u8]>> {
mod field {
use wire::field::*;

pub const DESTINATION: Field = 0..6;
pub const SOURCE: Field = 6..12;
pub const ETHERTYPE: Field = 12..14;
pub const PAYLOAD: FieldFrom = 14..;
pub const DESTINATION: Field = 0..6;
pub const SOURCE: Field = 6..12;
pub const ETHERTYPE: Field = 12..14;
pub const PAYLOAD: Rest = 14..;
}

impl<T: AsRef<[u8]>> Frame<T> {
@@ -148,7 +148,9 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Frame<T> {
let data = self.buffer.as_mut();
NetworkEndian::write_u16(&mut data[field::ETHERTYPE], value.into())
}
}

impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Frame<&'a mut T> {
/// Return a mutable pointer to the payload.
#[inline(always)]
pub fn payload_mut(&mut self) -> &mut [u8] {
42 changes: 22 additions & 20 deletions src/wire/icmpv4.rs
Original file line number Diff line number Diff line change
@@ -129,8 +129,6 @@ pub struct Packet<T: AsRef<[u8]>> {
}

mod field {
#![allow(non_snake_case)]

use wire::field::*;

pub const TYPE: usize = 0;
@@ -217,7 +215,7 @@ impl<T: AsRef<[u8]>> Packet<T> {
/// Validate the header checksum.
pub fn verify_checksum(&self) -> bool {
let data = self.buffer.as_ref();
checksum(data) == !0
checksum::data(data) == !0
}
}

@@ -272,25 +270,27 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
NetworkEndian::write_u16(&mut data[field::ECHO_SEQNO], value)
}

/// Return a mutable pointer to the type-specific data.
#[inline(always)]
pub fn data_mut(&mut self) -> &mut [u8] {
let range = self.header_len()..;
let mut data = self.buffer.as_mut();
&mut data[range]
}

/// Compute and fill in the header checksum.
pub fn fill_checksum(&mut self) {
self.set_checksum(0);
let checksum = {
let data = self.buffer.as_ref();
!checksum(data)
!checksum::data(data)
};
self.set_checksum(checksum)
}
}

impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
/// Return a mutable pointer to the type-specific data.
#[inline(always)]
pub fn data_mut(&mut self) -> &mut [u8] {
let range = self.header_len()..;
let mut data = self.buffer.as_mut();
&mut data[range]
}
}

/// A high-level representation of an Internet Control Message Protocol version 4 packet header.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Repr<'a> {
@@ -310,8 +310,7 @@ pub enum Repr<'a> {

impl<'a> Repr<'a> {
/// Parse an Internet Control Message Protocol version 4 packet and return
/// a high-level representation, or return `Err(())` if the packet is not recognized
/// or is malformed.
/// a high-level representation.
pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&'a T>) -> Result<Repr<'a>, Error> {
match (packet.msg_type(), packet.msg_code()) {
(Type::EchoRequest, 0) => {
@@ -343,8 +342,9 @@ impl<'a> Repr<'a> {
}
}

/// Emit a high-level representation into an Internet Protocol version 4 packet.
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
/// Emit a high-level representation into an Internet Control Message Protocol version 4
/// packet.
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, packet: &mut Packet<&mut T>) {
packet.set_msg_code(0);
match self {
&Repr::EchoRequest { ident, seq_no, data } => {
@@ -372,8 +372,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
match Repr::parse(self) {
Ok(repr) => write!(f, "{}", repr),
_ => {
write!(f, "ICMPv4 type={} code={}",
self.msg_type(), self.msg_code())
try!(write!(f, "ICMPv4 (unrecognized)"));
try!(write!(f, " type={} code={} cksum={:#04x}",
self.msg_type(), self.msg_code(), self.checksum()));
Ok(())
}
}
}
@@ -397,8 +399,8 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
indent: &mut PrettyIndent) -> fmt::Result {
match Packet::new(buffer) {
Err(err) => write!(f, "{}({})\n", indent, err),
Ok(frame) => write!(f, "{}{}\n", indent, frame)
Err(err) => write!(f, "{}({})\n", indent, err),
Ok(packet) => write!(f, "{}{}\n", indent, packet)
}
}
}
Loading