Implement a trait for sending and receiving frames.
parent
683652a9a6
commit
fb3faa9d28
|
@ -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")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(range_contains)]
|
||||
#![feature(range_contains, associated_consts)]
|
||||
#![no_std]
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue