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: 10d538c02fa3
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: 6a8989381f7e
Choose a head ref
  • 2 commits
  • 5 files changed
  • 1 contributor

Commits on Dec 10, 2016

  1. Copy the full SHA
    ef87849 View commit details
  2. Copy the full SHA
    6a89893 View commit details
Showing with 81 additions and 42 deletions.
  1. +11 −17 examples/smoltcpdump.rs
  2. +0 −10 src/interface/mod.rs
  3. +2 −2 src/lib.rs
  4. +44 −0 src/phy/mod.rs
  5. +24 −13 src/{interface → phy}/raw_socket.rs
28 changes: 11 additions & 17 deletions examples/smoltcpdump.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
extern crate smoltcp;

use std::{env, io};
use std::env;
use smoltcp::phy::{Device, RawSocket};
use smoltcp::wire::{EthernetFrame, EthernetProtocolType, ArpPacket};
use smoltcp::interface::RawSocket;

fn get<T>(result: Result<T, ()>) -> io::Result<T> {
result.map_err(|()| io::Error::new(io::ErrorKind::InvalidData,
"buffer too small"))
.into()
}

fn print_frame(socket: &mut RawSocket) -> io::Result<()> {
let buffer = try!(socket.capture());

let frame = try!(get(EthernetFrame::new(&buffer[..])));
fn print_frame(buffer: &[u8]) -> Result<(), ()> {
let frame = try!(EthernetFrame::new(&buffer[..]));
println!("{}", frame);

match frame.ethertype() {
EthernetProtocolType::Arp => {
let packet = try!(get(ArpPacket::new(frame.payload())));
let packet = try!(ArpPacket::new(frame.payload()));
println!("| {}", packet);
},
_ => ()
@@ -31,9 +23,11 @@ fn main() {
let ifname = env::args().nth(1).unwrap();
let mut socket = RawSocket::new(ifname.as_ref()).unwrap();
loop {
match print_frame(&mut socket) {
Ok(()) => (),
Err(e) => println!("Cannot print frame: {}", e)
}
socket.recv(|buffer| {
match print_frame(buffer) {
Ok(()) => (),
Err(()) => println!("buffer too small")
}
})
}
}
10 changes: 0 additions & 10 deletions src/interface/mod.rs

This file was deleted.

4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(range_contains)]
#![feature(range_contains, associated_consts)]
#![no_std]

#[cfg(test)]
@@ -7,5 +7,5 @@ extern crate std;

extern crate byteorder;

pub mod phy;
pub mod wire;
pub mod interface;
44 changes: 44 additions & 0 deletions src/phy/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Access to networking hardware.
//!
//! The `phy` module provides an interface for sending and receiving frames
//! through a physical (or perhaps virtualized) network device, [Device](trait.Device.html),
//! as well as some useful implementations of that trait.
//!
//! Currently the only implementation, [RawSocket](struct.RawSocket.html), is based on
//! Unix raw sockets, and only works on Linux.
#[cfg(all(unix, feature = "std"))]
mod raw_socket;

/// An interface for sending and receiving raw network frames.
///
/// It is expected that a `Device` implementation would allocate memory for both sending
/// and receiving packets from memory pools; hence, the stack borrows the buffer for a packet
/// that it is about to receive, as well for a packet that it is about to send, from the device.
pub trait Device {
/// Maximum transmission unit.
///
/// The network device is unable to send or receive frames larger than the MTU.
/// In practice, MTU will fall between 64 and 9216 octets.
const MTU: usize;

/// Receives a frame.
///
/// It is expected that a `recv` implementation, once a packet is written to memory
/// through DMA, would gain ownership of the underlying buffer, provide it for parsing,
/// and then return it to the network device.
fn recv<F: FnOnce(&[u8])>(&mut self, handler: F);

/// Transmits a frame.
///
/// It is expected that a `send` implementation would gain ownership of a buffer with
/// the requested size, provide it for emission, and then schedule it to be read from
/// memory by the network device.
///
/// # Panics
/// This function may panic if `size` is larger than `MTU`.
fn send<F: FnOnce(&mut [u8])>(&mut self, size: usize, handler: F);
}

#[cfg(all(unix, feature = "std"))]
pub use self::raw_socket::RawSocket;
37 changes: 24 additions & 13 deletions src/interface/raw_socket.rs → src/phy/raw_socket.rs
Original file line number Diff line number Diff line change
@@ -78,24 +78,35 @@ impl RawSocket {
})
}
}
}

/// Captures a packet into the internal buffer, which is sized appropriately
/// for the interface MTU.
pub fn capture(&mut self) -> io::Result<&[u8]> {
unsafe {
impl Drop for RawSocket {
fn drop(&mut self) {
unsafe { libc::close(self.sockfd); }
}
}

impl super::Device for RawSocket {
const MTU: usize = 1536;

fn recv<F: FnOnce(&[u8])>(&mut self, handler: F) {
let len = unsafe {
let len = libc::recv(self.sockfd, self.buffer.as_mut_ptr() as *mut libc::c_void,
self.buffer.len(), 0);
if len == -1 {
return Err(io::Error::last_os_error())
}
if len == -1 { Err(io::Error::last_os_error()).unwrap() }
len
};

Ok(&self.buffer[..len as usize])
}
handler(&self.buffer[..len as usize])
}
}

impl Drop for RawSocket {
fn drop(&mut self) {
unsafe { libc::close(self.sockfd); }
fn send<F: FnOnce(&mut [u8])>(&mut self, size: usize, handler: F) {
handler(&mut self.buffer[..size]);

unsafe {
let len = libc::send(self.sockfd, self.buffer.as_ptr() as *const libc::c_void,
size, 0);
if len == -1 { Err(io::Error::last_os_error()).unwrap() }
}
}
}