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: f6f7dc8cb653
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: 3377b911d84b
Choose a head ref
  • 2 commits
  • 12 files changed
  • 1 contributor

Commits on Dec 14, 2016

  1. Implement UDP sockets.

    whitequark committed Dec 14, 2016
    Copy the full SHA
    659f6ed View commit details

Commits on Dec 15, 2016

  1. Copy the full SHA
    3377b91 View commit details
Showing with 518 additions and 66 deletions.
  1. +6 −2 README.md
  2. +14 −9 examples/smoltcpserver.rs
  3. +38 −17 src/iface/arp_cache.rs
  4. +132 −37 src/iface/ethernet.rs
  5. +1 −0 src/iface/mod.rs
  6. +7 −0 src/lib.rs
  7. +1 −0 src/phy/mod.rs
  8. +74 −0 src/socket/mod.rs
  9. +214 −0 src/socket/udp.rs
  10. +28 −0 src/wire/ip.rs
  11. +2 −1 src/wire/ipv4.rs
  12. +1 −0 src/wire/mod.rs
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ The only supported medium is Ethernet.

* Regular Ethernet II frames are supported.
* ARP packets (including gratuitous requests and replies) are supported.
* 802.3 and 802.1Q is **not** supported.
* 802.3 and 802.1Q are **not** supported.
* Jumbo frames are **not** supported.
* Frame check sequence calculation is **not** supported.

@@ -30,13 +30,17 @@ The only supported internetworking protocol is IPv4.
* IPv4 header checksum is supported.
* IPv4 fragmentation is **not** supported.
* IPv4 options are **not** supported.
* ICMPv4 header checksum is supported.
* ICMPv4 echo requests and replies are supported.
* ICMPv4 destination unreachable message is **not** supported.
* ICMPv4 parameter problem message is **not** supported.

### UDP layer

UDP is **not** supported yet.
The UDP protocol is supported over IPv4.

* UDP header checksum is supported.
* UDP sockets are supported.

### TCP layer

23 changes: 14 additions & 9 deletions examples/smoltcpserver.rs
Original file line number Diff line number Diff line change
@@ -3,25 +3,30 @@ extern crate smoltcp;

use std::env;
use smoltcp::phy::{Tracer, TapInterface};
use smoltcp::wire::{EthernetFrame, EthernetAddress, InternetAddress};
use smoltcp::wire::{EthernetFrame, EthernetAddress, InternetAddress, InternetEndpoint};
use smoltcp::iface::{SliceArpCache, EthernetInterface};
use smoltcp::socket::{Socket, UdpSocket, UdpUnitaryBuffer};

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

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

let device = TapInterface::new(ifname.as_ref()).unwrap();
let device = Tracer::<_, EthernetFrame<&[u8]>>::new(device);
let arp_cache = SliceArpCache::new(vec![Default::default(); 8]);

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

let mut arp_cache_data = [Default::default(); 8];
let arp_cache = SliceArpCache::new(&mut arp_cache_data);
let mut iface = EthernetInterface::new(device, arp_cache);
let listen_address = InternetAddress::ipv4([0, 0, 0, 0]);
let endpoint = InternetEndpoint::new(listen_address, 6969);

iface.set_hardware_addr(hardware_addr);
iface.set_protocol_addrs(&protocol_addrs);
let udp_rx_buffer = UdpUnitaryBuffer::new(vec![0; 2048]);
let udp_tx_buffer = UdpUnitaryBuffer::new(vec![0; 2048]);
let mut udp_socket = UdpSocket::new(endpoint, udp_rx_buffer, udp_tx_buffer);
let mut sockets: [&mut Socket; 1] = [&mut udp_socket];

let mut iface = EthernetInterface::new(device, arp_cache,
hardware_addr, &mut protocol_addrs[..], &mut sockets[..]);
loop {
match iface.poll() {
Ok(()) => (),
55 changes: 38 additions & 17 deletions src/iface/arp_cache.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use core::borrow::BorrowMut;

use wire::{EthernetAddress, InternetAddress};

/// An Address Resolution Protocol cache.
///
/// This cache maps protocol addresses to hardware addresses.
/// This interface 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: InternetAddress, hardware_addr: EthernetAddress);
@@ -17,29 +19,40 @@ pub trait Cache {
/// eviction strategy.
///
/// # Examples
/// This cache can be created as:
///
/// On systems with heap, this cache can be created with:
/// ```rust
/// use smoltcp::iface::SliceArpCache;
/// let mut arp_cache = SliceArpCache::new(vec![Default::default(); 8]);
/// ```
///
/// On systems without heap, use:
/// ```rust
/// use smoltcp::iface::SliceArpCache;
/// let mut arp_cache_storage = [Default::default(); 8];
/// let mut arp_cache = SliceArpCache::new(&mut arp_cache_storage);
/// let mut arp_cache_storage = [Default::default(); 8]
/// let mut arp_cache = SliceArpCache::new(&mut arp_cache_storage[..]);
/// ```
pub struct SliceCache<'a> {
storage: &'a mut [(InternetAddress, EthernetAddress, usize)],
pub struct SliceCache<
StorageT: BorrowMut<[(InternetAddress, EthernetAddress, usize)]>
> {
storage: StorageT,
counter: usize
}

impl<'a> SliceCache<'a> {
impl<
StorageT: BorrowMut<[(InternetAddress, EthernetAddress, usize)]>
> SliceCache<StorageT> {
/// Create a cache. The backing storage is cleared upon creation.
///
/// # Panics
/// This function panics if `storage.len() == 0`.
pub fn new(storage: &'a mut [(InternetAddress, EthernetAddress, usize)]) -> SliceCache<'a> {
if storage.len() == 0 {
pub fn new(mut storage: StorageT) -> SliceCache<StorageT> {
if storage.borrow().len() == 0 {
panic!("ARP slice cache created with empty storage")
}

for elem in storage.iter_mut() {
for elem in storage.borrow_mut().iter_mut() {
*elem = Default::default()
}
SliceCache {
@@ -52,31 +65,39 @@ impl<'a> SliceCache<'a> {
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()
let storage = self.storage.borrow();
storage.binary_search_by_key(&protocol_addr, |&(key, _, _)| key).ok()
}

/// Sort entries in an order suitable for `find`.
fn sort(&mut self) {
self.storage.sort_by_key(|&(key, _, _)| key)
let mut storage = self.storage.borrow_mut();
storage.sort_by_key(|&(key, _, _)| key)
}

/// Find the least recently used entry.
fn lru(&self) -> usize {
self.storage.iter().enumerate().min_by_key(|&(_, &(_, _, counter))| counter).unwrap().0
let storage = self.storage.borrow();
storage.iter().enumerate().min_by_key(|&(_, &(_, _, counter))| counter).unwrap().0
}
}

impl<'a> Cache for SliceCache<'a> {
impl<
StorageT: BorrowMut<[(InternetAddress, EthernetAddress, usize)]>
> Cache for SliceCache<StorageT> {
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);
let lru_index = self.lru();
self.storage.borrow_mut()[lru_index] =
(protocol_addr, hardware_addr, self.counter);
self.sort()
}
}

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];
let (_protocol_addr, hardware_addr, ref mut counter) =
self.storage.borrow_mut()[index];
self.counter += 1;
*counter = self.counter;
Some(hardware_addr)
@@ -103,7 +124,7 @@ mod test {
#[test]
fn test_slice_cache() {
let mut cache_storage = [Default::default(); 3];
let mut cache = SliceCache::new(&mut cache_storage);
let mut cache = SliceCache::new(&mut cache_storage[..]);

cache.fill(PADDR_A, HADDR_A);
assert_eq!(cache.lookup(PADDR_A), Some(HADDR_A));
Loading