2017-06-18 18:14:20 +08:00
|
|
|
use managed::Managed;
|
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
use {Error, Result};
|
2017-06-18 18:14:20 +08:00
|
|
|
use phy::DeviceLimits;
|
|
|
|
use wire::{IpVersion, IpProtocol, Ipv4Repr, Ipv4Packet};
|
|
|
|
use socket::{IpRepr, IpPayload, Socket};
|
|
|
|
use storage::{Resettable, RingBuffer};
|
|
|
|
|
|
|
|
/// A buffered raw IP packet.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PacketBuffer<'a> {
|
|
|
|
size: usize,
|
|
|
|
payload: Managed<'a, [u8]>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> PacketBuffer<'a> {
|
|
|
|
/// Create a buffered packet.
|
|
|
|
pub fn new<T>(payload: T) -> PacketBuffer<'a>
|
|
|
|
where T: Into<Managed<'a, [u8]>> {
|
|
|
|
PacketBuffer {
|
|
|
|
size: 0,
|
|
|
|
payload: payload.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_ref<'b>(&'b self) -> &'b [u8] {
|
|
|
|
&self.payload[..self.size]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_mut<'b>(&'b mut self) -> &'b mut [u8] {
|
|
|
|
&mut self.payload[..self.size]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Resettable for PacketBuffer<'a> {
|
|
|
|
fn reset(&mut self) {
|
|
|
|
self.size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A raw IP packet ring buffer.
|
|
|
|
pub type SocketBuffer<'a, 'b: 'a> = RingBuffer<'a, PacketBuffer<'b>>;
|
|
|
|
|
|
|
|
/// A raw IP socket.
|
|
|
|
///
|
|
|
|
/// A raw socket is bound to a specific IP protocol, and owns
|
|
|
|
/// transmit and receive packet buffers.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct RawSocket<'a, 'b: 'a> {
|
2017-07-28 06:55:30 +08:00
|
|
|
debug_id: usize,
|
2017-06-18 18:14:20 +08:00
|
|
|
ip_version: IpVersion,
|
|
|
|
ip_protocol: IpProtocol,
|
|
|
|
rx_buffer: SocketBuffer<'a, 'b>,
|
|
|
|
tx_buffer: SocketBuffer<'a, 'b>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'b> RawSocket<'a, 'b> {
|
|
|
|
/// Create a raw IP socket bound to the given IP version and datagram protocol,
|
|
|
|
/// with the given buffers.
|
|
|
|
pub fn new(ip_version: IpVersion, ip_protocol: IpProtocol,
|
|
|
|
rx_buffer: SocketBuffer<'a, 'b>,
|
|
|
|
tx_buffer: SocketBuffer<'a, 'b>) -> Socket<'a, 'b> {
|
|
|
|
Socket::Raw(RawSocket {
|
2017-07-28 06:55:30 +08:00
|
|
|
debug_id: 0,
|
2017-06-18 18:14:20 +08:00
|
|
|
ip_version,
|
|
|
|
ip_protocol,
|
|
|
|
rx_buffer,
|
|
|
|
tx_buffer,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the debug identifier.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-06-18 18:14:20 +08:00
|
|
|
pub fn debug_id(&self) -> usize {
|
|
|
|
self.debug_id
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the debug identifier.
|
|
|
|
///
|
|
|
|
/// The debug identifier is a number printed in socket trace messages.
|
|
|
|
/// It could as well be used by the user code.
|
|
|
|
pub fn set_debug_id(&mut self, id: usize) {
|
|
|
|
self.debug_id = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the IP version the socket is bound to.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-06-18 18:14:20 +08:00
|
|
|
pub fn ip_version(&self) -> IpVersion {
|
|
|
|
self.ip_version
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return the IP protocol the socket is bound to.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-06-18 18:14:20 +08:00
|
|
|
pub fn ip_protocol(&self) -> IpProtocol {
|
|
|
|
self.ip_protocol
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check whether the transmit buffer is full.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-06-18 18:14:20 +08:00
|
|
|
pub fn can_send(&self) -> bool {
|
|
|
|
!self.tx_buffer.full()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check whether the receive buffer is not empty.
|
2017-07-05 02:46:36 +08:00
|
|
|
#[inline]
|
2017-06-18 18:14:20 +08:00
|
|
|
pub fn can_recv(&self) -> bool {
|
|
|
|
!self.rx_buffer.empty()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Enqueue a packet to send, and return a pointer to its payload.
|
|
|
|
///
|
2017-07-27 21:51:02 +08:00
|
|
|
/// This function returns `Err(Error::Exhausted)` if the size is greater than
|
|
|
|
/// the transmit packet buffer size.
|
|
|
|
pub fn send(&mut self, size: usize) -> Result<&mut [u8]> {
|
2017-06-18 18:14:20 +08:00
|
|
|
let packet_buf = self.tx_buffer.enqueue()?;
|
|
|
|
packet_buf.size = size;
|
|
|
|
net_trace!("[{}]:{}:{}: buffer to send {} octets",
|
|
|
|
self.debug_id, self.ip_version, self.ip_protocol,
|
|
|
|
packet_buf.size);
|
|
|
|
Ok(&mut packet_buf.as_mut()[..size])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Enqueue a packet to send, and fill it from a slice.
|
|
|
|
///
|
|
|
|
/// See also [send](#method.send).
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn send_slice(&mut self, data: &[u8]) -> Result<usize> {
|
2017-06-18 18:14:20 +08:00
|
|
|
let buffer = self.send(data.len())?;
|
|
|
|
let data = &data[..buffer.len()];
|
|
|
|
buffer.copy_from_slice(data);
|
|
|
|
Ok(data.len())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Dequeue a packet, and return a pointer to the payload.
|
|
|
|
///
|
2017-07-27 21:51:02 +08:00
|
|
|
/// This function returns `Err(Error::Exhausted)` if the receive buffer is empty.
|
|
|
|
pub fn recv(&mut self) -> Result<&[u8]> {
|
2017-06-18 18:14:20 +08:00
|
|
|
let packet_buf = self.rx_buffer.dequeue()?;
|
|
|
|
net_trace!("[{}]:{}:{}: receive {} buffered octets",
|
|
|
|
self.debug_id, self.ip_version, self.ip_protocol,
|
|
|
|
packet_buf.size);
|
|
|
|
Ok(&packet_buf.as_ref()[..packet_buf.size])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Dequeue a packet, and copy the payload into the given slice.
|
|
|
|
///
|
|
|
|
/// See also [recv](#method.recv).
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn recv_slice(&mut self, data: &mut [u8]) -> Result<usize> {
|
2017-06-18 18:14:20 +08:00
|
|
|
let buffer = self.recv()?;
|
|
|
|
data[..buffer.len()].copy_from_slice(buffer);
|
|
|
|
Ok(buffer.len())
|
|
|
|
}
|
|
|
|
|
2017-07-01 04:54:58 +08:00
|
|
|
pub(crate) fn process(&mut self, _timestamp: u64, ip_repr: &IpRepr,
|
2017-07-27 21:51:02 +08:00
|
|
|
payload: &[u8]) -> Result<()> {
|
2017-06-18 18:14:20 +08:00
|
|
|
match self.ip_version {
|
|
|
|
IpVersion::Ipv4 => {
|
|
|
|
if ip_repr.protocol() != self.ip_protocol {
|
|
|
|
return Err(Error::Rejected);
|
|
|
|
}
|
|
|
|
let header_len = ip_repr.buffer_len();
|
2017-07-27 21:51:02 +08:00
|
|
|
let packet_buf = self.rx_buffer.enqueue()?;
|
2017-06-18 18:14:20 +08:00
|
|
|
packet_buf.size = header_len + payload.len();
|
|
|
|
ip_repr.emit(&mut packet_buf.as_mut()[..header_len]);
|
|
|
|
packet_buf.as_mut()[header_len..header_len + payload.len()]
|
|
|
|
.copy_from_slice(payload);
|
|
|
|
net_trace!("[{}]:{}:{}: receiving {} octets",
|
|
|
|
self.debug_id, self.ip_version, self.ip_protocol,
|
|
|
|
packet_buf.size);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
IpVersion::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// See [Socket::dispatch](enum.Socket.html#method.dispatch).
|
2017-07-01 04:54:58 +08:00
|
|
|
pub(crate) fn dispatch<F, R>(&mut self, _timestamp: u64, _limits: &DeviceLimits,
|
2017-07-27 21:51:02 +08:00
|
|
|
emit: &mut F) -> Result<R>
|
|
|
|
where F: FnMut(&IpRepr, &IpPayload) -> Result<R> {
|
|
|
|
let mut packet_buf = self.tx_buffer.dequeue()?;
|
2017-06-18 18:14:20 +08:00
|
|
|
net_trace!("[{}]:{}:{}: sending {} octets",
|
|
|
|
self.debug_id, self.ip_version, self.ip_protocol,
|
|
|
|
packet_buf.size);
|
|
|
|
|
|
|
|
match self.ip_version {
|
|
|
|
IpVersion::Ipv4 => {
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
let mut ipv4_packet = Ipv4Packet::new_checked(packet_buf.as_mut())?;
|
2017-06-18 18:14:20 +08:00
|
|
|
ipv4_packet.fill_checksum();
|
|
|
|
|
Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.
This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
* `fn check_len(&self) -> Result<(), Error>`, purely a validator;
* `fn new(T) -> Self`, purely a wrapper;
* `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.
This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).
Fixes #17.
2017-06-24 17:15:22 +08:00
|
|
|
let ipv4_packet = Ipv4Packet::new(&*ipv4_packet.into_inner());
|
2017-06-18 18:14:20 +08:00
|
|
|
let raw_repr = RawRepr(ipv4_packet.payload());
|
|
|
|
let ipv4_repr = Ipv4Repr::parse(&ipv4_packet)?;
|
|
|
|
emit(&IpRepr::Ipv4(ipv4_repr), &raw_repr)
|
|
|
|
}
|
|
|
|
IpVersion::__Nonexhaustive => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct RawRepr<'a>(&'a [u8]);
|
|
|
|
|
|
|
|
impl<'a> IpPayload for RawRepr<'a> {
|
|
|
|
fn buffer_len(&self) -> usize {
|
|
|
|
self.0.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit(&self, _repr: &IpRepr, payload: &mut [u8]) {
|
|
|
|
payload.copy_from_slice(self.0);
|
|
|
|
}
|
|
|
|
}
|