Implement a trait for sending and receiving frames.

v0.7.x
whitequark 2016-12-10 19:27:07 +00:00
parent 683652a9a6
commit fb3faa9d28
4 changed files with 73 additions and 34 deletions

View File

@ -1,24 +1,16 @@
extern crate smoltcp;
use std::{env, io};
use smoltcp::phy::RawSocket;
use std::env;
use smoltcp::phy::{Device, RawSocket};
use smoltcp::wire::{EthernetFrame, EthernetProtocolType, ArpPacket};
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")
}
})
}
}

View File

@ -1,4 +1,4 @@
#![feature(range_contains)]
#![feature(range_contains, associated_consts)]
#![no_std]
#[cfg(test)]

View File

@ -1,10 +1,44 @@
//! Access to networking hardware.
//!
//! The `phy` module provides a way to capture and inject packets.
//! It requires the standard library, and currently only works on Linux.
//! 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;

View File

@ -78,20 +78,6 @@ 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 {
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())
}
Ok(&self.buffer[..len as usize])
}
}
}
impl Drop for RawSocket {
@ -99,3 +85,28 @@ impl Drop for RawSocket {
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 { Err(io::Error::last_os_error()).unwrap() }
len
};
handler(&self.buffer[..len as usize])
}
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() }
}
}
}