Add support for multiple interfaces
- Smoltcp now talk to a IP device that does the routing - Add RouteTable - Add trait LinkDevice representing devices (eth0, loopback...) - Remove old device
This commit is contained in:
@@ -1,123 +0,0 @@
|
||||
use smoltcp;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::EthernetAddress;
|
||||
use crate::buffer_pool::{Buffer, BufferPool};
|
||||
|
||||
struct NetworkDeviceData {
|
||||
network_file: Rc<RefCell<File>>,
|
||||
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
|
||||
local_hwaddr: smoltcp::wire::EthernetAddress,
|
||||
buffer_pool: Rc<RefCell<BufferPool>>,
|
||||
}
|
||||
|
||||
pub struct NetworkDevice {
|
||||
data: Rc<RefCell<NetworkDeviceData>>,
|
||||
}
|
||||
|
||||
impl NetworkDevice {
|
||||
pub const MTU: usize = 1520;
|
||||
|
||||
pub fn new(
|
||||
network_file: Rc<RefCell<File>>,
|
||||
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
|
||||
local_hwaddr: smoltcp::wire::EthernetAddress,
|
||||
buffer_pool: Rc<RefCell<BufferPool>>,
|
||||
) -> NetworkDevice {
|
||||
NetworkDevice {
|
||||
data: Rc::new(RefCell::new(NetworkDeviceData {
|
||||
network_file,
|
||||
input_queue,
|
||||
local_hwaddr,
|
||||
buffer_pool,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RxToken {
|
||||
buffer: Buffer,
|
||||
}
|
||||
|
||||
impl smoltcp::phy::RxToken for RxToken {
|
||||
fn consume<R, F>(mut self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> R,
|
||||
{
|
||||
f(&mut self.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TxToken {
|
||||
data: Rc<RefCell<NetworkDeviceData>>,
|
||||
}
|
||||
|
||||
impl smoltcp::phy::TxToken for TxToken {
|
||||
fn consume<R, F>(self, len: usize, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> R,
|
||||
{
|
||||
let data = self.data.borrow_mut();
|
||||
let mut buffer = data.buffer_pool.borrow_mut().get_buffer();
|
||||
buffer.resize(len);
|
||||
let res = f(&mut buffer);
|
||||
|
||||
let mut loopback = false;
|
||||
if let Ok(mut frame) = smoltcp::wire::EthernetFrame::new_checked(&mut buffer) {
|
||||
if frame.dst_addr() == EthernetAddress::default() {
|
||||
frame.set_dst_addr(data.local_hwaddr);
|
||||
loopback = true;
|
||||
}
|
||||
}
|
||||
|
||||
if loopback {
|
||||
data.input_queue.borrow_mut().push_back(buffer.move_out());
|
||||
} else {
|
||||
// TODO: Handle error
|
||||
data.network_file
|
||||
.borrow_mut()
|
||||
.write(&buffer);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl smoltcp::phy::Device for NetworkDevice {
|
||||
type RxToken<'a> = RxToken;
|
||||
type TxToken<'a> = TxToken;
|
||||
|
||||
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
|
||||
let mut limits = smoltcp::phy::DeviceCapabilities::default();
|
||||
limits.max_transmission_unit = Self::MTU;
|
||||
limits.max_burst_size = Some(20);
|
||||
limits
|
||||
}
|
||||
|
||||
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||
let data = self.data.borrow_mut();
|
||||
let buffer = data.input_queue.borrow_mut().pop_front();
|
||||
|
||||
if let Some(buffer) = buffer {
|
||||
Some((
|
||||
RxToken { buffer },
|
||||
TxToken {
|
||||
data: Rc::clone(&self.data),
|
||||
},
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
|
||||
Some(TxToken {
|
||||
data: Rc::clone(&self.data),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{ErrorKind, Read, Write};
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::storage::PacketMetadata;
|
||||
use smoltcp::time::{Duration, Instant};
|
||||
use smoltcp::wire::{
|
||||
ArpOperation, ArpPacket, ArpRepr, EthernetAddress, EthernetFrame, EthernetProtocol,
|
||||
EthernetRepr, IpAddress, Ipv4Address, Ipv4Cidr,
|
||||
};
|
||||
|
||||
use super::LinkDevice;
|
||||
|
||||
struct Neighbor {
|
||||
hardware_address: EthernetAddress,
|
||||
expires_at: Instant,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
enum ArpState {
|
||||
#[default]
|
||||
Discovered,
|
||||
Discovering {
|
||||
target: Ipv4Address,
|
||||
tries: u32,
|
||||
silent_until: Instant,
|
||||
},
|
||||
}
|
||||
|
||||
type PacketBuffer = smoltcp::storage::PacketBuffer<'static, IpAddress>;
|
||||
|
||||
pub struct EthernetLink {
|
||||
name: Rc<str>,
|
||||
neighbor_cache: BTreeMap<IpAddress, Neighbor>,
|
||||
arp_state: ArpState,
|
||||
waiting_packets: PacketBuffer,
|
||||
input_buffer: Vec<u8>,
|
||||
output_buffer: Vec<u8>,
|
||||
network_file: File,
|
||||
hardware_address: EthernetAddress,
|
||||
ip_address: Ipv4Cidr,
|
||||
}
|
||||
|
||||
impl EthernetLink {
|
||||
// TODO: Review these constants
|
||||
const MAX_WAITING_PACKET_COUNT: usize = 10;
|
||||
const MTU: usize = 1500;
|
||||
const WAITING_PACKET_BUFFER_SIZE: usize = Self::MTU * Self::MAX_WAITING_PACKET_COUNT;
|
||||
|
||||
const NEIGHBOR_LIVE_TIME: Duration = Duration::from_secs(60);
|
||||
const ARP_SILENCE_TIME: Duration = Duration::from_secs(1);
|
||||
|
||||
pub fn new(
|
||||
name: &str,
|
||||
network_file: File,
|
||||
hardware_address: EthernetAddress,
|
||||
ip_address: Ipv4Cidr,
|
||||
) -> Self {
|
||||
let waiting_packets = PacketBuffer::new(
|
||||
vec![PacketMetadata::EMPTY; Self::MAX_WAITING_PACKET_COUNT],
|
||||
vec![0u8; Self::WAITING_PACKET_BUFFER_SIZE],
|
||||
);
|
||||
|
||||
Self {
|
||||
name: name.into(),
|
||||
network_file,
|
||||
waiting_packets,
|
||||
hardware_address,
|
||||
ip_address,
|
||||
input_buffer: vec![0u8; Self::MTU],
|
||||
output_buffer: Vec::with_capacity(Self::MTU),
|
||||
arp_state: Default::default(),
|
||||
neighbor_cache: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn send_to<F>(&mut self, dst: EthernetAddress, size: usize, f: F, proto: EthernetProtocol)
|
||||
where
|
||||
F: FnOnce(&mut [u8]),
|
||||
{
|
||||
let repr = EthernetRepr {
|
||||
src_addr: self.hardware_address,
|
||||
dst_addr: dst,
|
||||
ethertype: proto,
|
||||
};
|
||||
|
||||
self.output_buffer.clear();
|
||||
self.output_buffer.resize(repr.buffer_len() + size, 0);
|
||||
let mut frame = EthernetFrame::new_unchecked(&mut self.output_buffer);
|
||||
repr.emit(&mut frame);
|
||||
|
||||
f(frame.payload_mut());
|
||||
|
||||
if let Err(_) = self.network_file.write_all(&self.output_buffer) {
|
||||
error!(
|
||||
"Dropped outboud packet on {} (failed to write to network file)",
|
||||
self.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn process_arp(&mut self, packet: &[u8], now: Instant) {
|
||||
let Ok(repr) = ArpPacket::new_checked(packet).and_then(|packet| ArpRepr::parse(&packet)) else {
|
||||
debug!("Dropped incomming arp packet on {} (Malformed)", self.name);
|
||||
return;
|
||||
};
|
||||
|
||||
match repr {
|
||||
ArpRepr::EthernetIpv4 {
|
||||
operation,
|
||||
source_hardware_addr,
|
||||
source_protocol_addr,
|
||||
target_hardware_addr,
|
||||
target_protocol_addr,
|
||||
} => {
|
||||
if self.hardware_address != target_hardware_addr {
|
||||
// Only process packet that are for us
|
||||
return;
|
||||
}
|
||||
|
||||
if let ArpOperation::Unknown(_) = operation {
|
||||
return;
|
||||
}
|
||||
|
||||
if !source_hardware_addr.is_unicast() || !source_protocol_addr.is_unicast() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.ip_address.contains_addr(&target_protocol_addr) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.neighbor_cache.insert(
|
||||
IpAddress::Ipv4(source_protocol_addr),
|
||||
Neighbor {
|
||||
hardware_address: source_hardware_addr,
|
||||
expires_at: now + Self::NEIGHBOR_LIVE_TIME,
|
||||
},
|
||||
);
|
||||
|
||||
if let ArpOperation::Request = operation {
|
||||
let response = ArpRepr::EthernetIpv4 {
|
||||
operation: ArpOperation::Reply,
|
||||
source_hardware_addr: self.hardware_address,
|
||||
source_protocol_addr: self.ip_address.address(),
|
||||
target_hardware_addr: source_hardware_addr,
|
||||
target_protocol_addr: source_protocol_addr,
|
||||
};
|
||||
|
||||
self.send_to(
|
||||
source_hardware_addr,
|
||||
response.buffer_len(),
|
||||
|buf| response.emit(&mut ArpPacket::new_unchecked(buf)),
|
||||
EthernetProtocol::Arp,
|
||||
);
|
||||
}
|
||||
self.check_waiting_packets(source_protocol_addr, source_hardware_addr, now);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_waiting_packets(&mut self, ip: Ipv4Address, mac: EthernetAddress, now: Instant) {
|
||||
let mut waiting_packets =
|
||||
std::mem::replace(&mut self.waiting_packets, PacketBuffer::new(vec![], vec![]));
|
||||
loop {
|
||||
match waiting_packets.peek() {
|
||||
Ok((IpAddress::Ipv4(dst), _)) if dst == &ip => {}
|
||||
Ok((IpAddress::Ipv4(dst), _)) => {
|
||||
self.arp_state = ArpState::Discovering {
|
||||
target: *dst,
|
||||
tries: 0,
|
||||
silent_until: Instant::ZERO,
|
||||
};
|
||||
self.send_arp(now);
|
||||
break;
|
||||
}
|
||||
Err(_) => {
|
||||
self.arp_state = ArpState::Discovered;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let (_, packet) = waiting_packets.dequeue().unwrap();
|
||||
self.send_to(
|
||||
mac,
|
||||
packet.len(),
|
||||
|buf| buf.copy_from_slice(packet),
|
||||
EthernetProtocol::Ipv4,
|
||||
);
|
||||
}
|
||||
|
||||
self.waiting_packets = waiting_packets;
|
||||
}
|
||||
|
||||
fn drop_waiting_packets(&mut self, ip: Ipv4Address, now: Instant) {
|
||||
loop {
|
||||
match self.waiting_packets.peek() {
|
||||
Ok((IpAddress::Ipv4(dst), _)) if dst == &ip => {}
|
||||
Ok((IpAddress::Ipv4(dst), _)) => {
|
||||
self.arp_state = ArpState::Discovering {
|
||||
target: *dst,
|
||||
tries: 0,
|
||||
silent_until: Instant::ZERO,
|
||||
};
|
||||
|
||||
self.send_arp(now);
|
||||
|
||||
return;
|
||||
}
|
||||
Err(_) => {
|
||||
self.arp_state = ArpState::Discovered;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = self.waiting_packets.dequeue();
|
||||
debug!(
|
||||
"Dropped packet on {} because neighbor was not found",
|
||||
self.name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_missing_neighbor(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) {
|
||||
let Ok(buf) = self.waiting_packets.enqueue(packet.len(), next_hop) else {
|
||||
warn!("Dropped packet on {} because waiting queue was full", self.name);
|
||||
return;
|
||||
};
|
||||
buf.copy_from_slice(packet);
|
||||
|
||||
let IpAddress::Ipv4(next_hop) = next_hop;
|
||||
if let ArpState::Discovered = self.arp_state {
|
||||
self.arp_state = ArpState::Discovering {
|
||||
target: next_hop,
|
||||
tries: 0,
|
||||
silent_until: Instant::ZERO,
|
||||
};
|
||||
|
||||
self.send_arp(now)
|
||||
}
|
||||
}
|
||||
|
||||
fn send_arp(&mut self, now: Instant) {
|
||||
match self.arp_state {
|
||||
ArpState::Discovered => {}
|
||||
ArpState::Discovering { silent_until, .. } if silent_until > now => {}
|
||||
ArpState::Discovering { target, tries, .. } if tries >= 3 => {
|
||||
self.drop_waiting_packets(target, now)
|
||||
}
|
||||
ArpState::Discovering {
|
||||
target,
|
||||
ref mut tries,
|
||||
ref mut silent_until,
|
||||
} => {
|
||||
let arp_repr = ArpRepr::EthernetIpv4 {
|
||||
operation: ArpOperation::Request,
|
||||
source_hardware_addr: self.hardware_address,
|
||||
source_protocol_addr: self.ip_address.address(),
|
||||
target_hardware_addr: EthernetAddress::BROADCAST,
|
||||
target_protocol_addr: target,
|
||||
};
|
||||
|
||||
*tries += 1;
|
||||
*silent_until = now + Self::ARP_SILENCE_TIME;
|
||||
|
||||
self.send_to(
|
||||
EthernetAddress::BROADCAST,
|
||||
arp_repr.buffer_len(),
|
||||
|buf| arp_repr.emit(&mut ArpPacket::new_unchecked(buf)),
|
||||
EthernetProtocol::Arp,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LinkDevice for EthernetLink {
|
||||
fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) {
|
||||
|
||||
let local_broadcast = match self.ip_address.broadcast() {
|
||||
Some(addr) => IpAddress::Ipv4(addr) == next_hop,
|
||||
None => false
|
||||
};
|
||||
|
||||
if local_broadcast || next_hop.is_broadcast() {
|
||||
self.send_to(
|
||||
EthernetAddress::BROADCAST,
|
||||
packet.len(),
|
||||
|buf| buf.copy_from_slice(packet),
|
||||
EthernetProtocol::Ipv4,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
match self.neighbor_cache.entry(next_hop) {
|
||||
Entry::Vacant(_) => self.handle_missing_neighbor(next_hop, packet, now),
|
||||
Entry::Occupied(e) => {
|
||||
if e.get().expires_at < now {
|
||||
e.remove();
|
||||
self.handle_missing_neighbor(next_hop, packet, now)
|
||||
} else {
|
||||
let mac = e.get().hardware_address;
|
||||
self.send_to(
|
||||
mac,
|
||||
packet.len(),
|
||||
|buf| buf.copy_from_slice(packet),
|
||||
EthernetProtocol::Ipv4,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn recv(&mut self, now: Instant) -> Option<&[u8]> {
|
||||
let mut input_buffer = std::mem::replace(&mut self.input_buffer, Vec::new());
|
||||
loop {
|
||||
if let Err(e) = self.network_file.read(&mut input_buffer) {
|
||||
if e.kind() != ErrorKind::WouldBlock {
|
||||
error!("Failed to read ethernet device on link {}", self.name);
|
||||
} else {
|
||||
// No packet to read but we check if we have arp to send
|
||||
self.send_arp(now);
|
||||
}
|
||||
self.input_buffer = input_buffer;
|
||||
return None;
|
||||
}
|
||||
let packet = EthernetFrame::new_unchecked(&input_buffer[..]);
|
||||
let Ok(repr) = EthernetRepr::parse(&packet) else {
|
||||
debug!("Dropped incomming frame on {} (Malformed)", self.name);
|
||||
continue;
|
||||
};
|
||||
|
||||
if !repr.dst_addr.is_broadcast() && repr.dst_addr != self.hardware_address {
|
||||
// Drop packets which are not for us
|
||||
continue;
|
||||
}
|
||||
|
||||
match repr.ethertype {
|
||||
EthernetProtocol::Ipv4 => {
|
||||
self.input_buffer = input_buffer;
|
||||
return Some(EthernetFrame::new_unchecked(&self.input_buffer[..]).payload());
|
||||
}
|
||||
EthernetProtocol::Arp => self.process_arp(packet.payload(), now),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &Rc<str> {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::storage::PacketMetadata;
|
||||
use smoltcp::time::Instant;
|
||||
|
||||
use crate::scheme::Smolnetd;
|
||||
|
||||
use super::LinkDevice;
|
||||
|
||||
pub type PacketBuffer = smoltcp::storage::PacketBuffer<'static, ()>;
|
||||
|
||||
pub struct LoopbackDevice {
|
||||
name: Rc<str>,
|
||||
buffer: PacketBuffer,
|
||||
}
|
||||
|
||||
impl Default for LoopbackDevice {
|
||||
fn default() -> Self {
|
||||
let buffer = PacketBuffer::new(
|
||||
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0u8; 1500 * Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
);
|
||||
LoopbackDevice {
|
||||
name: "loopback".into(),
|
||||
buffer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LinkDevice for LoopbackDevice {
|
||||
fn send(&mut self, _next_hop: smoltcp::wire::IpAddress, packet: &[u8], _now: Instant) {
|
||||
match self.buffer.enqueue(packet.len(), ()) {
|
||||
Err(_) => warn!("loopback dropped packet because buffer was full"),
|
||||
Ok(buf) => buf.copy_from_slice(packet),
|
||||
}
|
||||
}
|
||||
|
||||
fn recv(&mut self, _now: Instant) -> Option<&[u8]> {
|
||||
self.buffer.dequeue().ok().map(|((), buf)| &*buf)
|
||||
}
|
||||
|
||||
fn name(&self) -> &std::rc::Rc<str> {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
pub mod loopback;
|
||||
pub mod ethernet;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::IpAddress;
|
||||
|
||||
/// Represent a link layer device (eth0, loopback...)
|
||||
pub trait LinkDevice {
|
||||
|
||||
/// Send the given packet to the machine with the `next_hop` ip address
|
||||
/// This method cannot fail so it's the implementor responsability
|
||||
/// to buffer packets which can't be sent immediatly or decide to
|
||||
/// drop them if necessary
|
||||
fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant);
|
||||
|
||||
/// Returns None if nothing is received.
|
||||
/// Returns an Ip packet otherwise
|
||||
fn recv(&mut self, now: Instant) -> Option<&[u8]>;
|
||||
|
||||
/// Returns the LinkDevice display name used to refer to it and for lookups
|
||||
fn name(&self) -> &Rc<str>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DeviceList {
|
||||
inner: Vec<Box<dyn LinkDevice>>,
|
||||
}
|
||||
|
||||
impl DeviceList {
|
||||
pub fn push<T: LinkDevice + 'static>(&mut self, dev: T) {
|
||||
self.inner.push(Box::new(dev))
|
||||
}
|
||||
|
||||
pub fn get(&self, device_name: &str) -> Option<&dyn LinkDevice> {
|
||||
self.inner
|
||||
.iter()
|
||||
.find(|dev| dev.name().as_ref() == device_name)
|
||||
.map(|device| device.as_ref())
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, device_name: &str) -> Option<&mut (dyn LinkDevice + 'static)> {
|
||||
self.inner
|
||||
.iter_mut()
|
||||
.find(|dev| dev.name().as_ref() == device_name)
|
||||
.map(|device| device.as_mut())
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &(dyn LinkDevice + 'static)> {
|
||||
self.inner.iter().map(|b| b.as_ref())
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (dyn LinkDevice + 'static)> {
|
||||
self.inner.iter_mut().map(|b| b.as_mut())
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,11 @@
|
||||
extern crate event;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate byteorder;
|
||||
extern crate netutils;
|
||||
extern crate redox_netstack;
|
||||
extern crate smoltcp;
|
||||
extern crate syscall;
|
||||
extern crate byteorder;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
@@ -15,14 +15,15 @@ use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::process;
|
||||
use std::rc::Rc;
|
||||
|
||||
use event::EventQueue;
|
||||
use redox_netstack::error::{Error, Result};
|
||||
use redox_netstack::logger;
|
||||
use event::EventQueue;
|
||||
use scheme::Smolnetd;
|
||||
|
||||
mod buffer_pool;
|
||||
mod device;
|
||||
mod link;
|
||||
mod port_set;
|
||||
mod router;
|
||||
mod scheme;
|
||||
|
||||
fn run(daemon: redox_daemon::Daemon) -> Result<()> {
|
||||
@@ -143,7 +144,7 @@ fn run(daemon: redox_daemon::Daemon) -> Result<()> {
|
||||
|
||||
event_queue.trigger_all(event::Event {
|
||||
fd: 0,
|
||||
flags: EventFlags::empty()
|
||||
flags: EventFlags::empty(),
|
||||
})?;
|
||||
|
||||
event_queue.run()
|
||||
@@ -158,5 +159,6 @@ fn main() {
|
||||
process::exit(1);
|
||||
}
|
||||
process::exit(0);
|
||||
}).expect("smoltcp: failed to daemonize");
|
||||
})
|
||||
.expect("smoltcp: failed to daemonize");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::phy::{Device, DeviceCapabilities, Medium};
|
||||
use smoltcp::storage::PacketMetadata;
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::IpAddress;
|
||||
|
||||
use self::route_table::RouteTable;
|
||||
use crate::link::DeviceList;
|
||||
use crate::scheme::Smolnetd;
|
||||
|
||||
pub mod route_table;
|
||||
|
||||
pub type PacketBuffer = smoltcp::storage::PacketBuffer<'static, ()>;
|
||||
|
||||
pub struct Router {
|
||||
rx_buffer: PacketBuffer,
|
||||
tx_buffer: PacketBuffer,
|
||||
devices: Rc<RefCell<DeviceList>>,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
}
|
||||
|
||||
impl Router {
|
||||
pub fn new(devices: Rc<RefCell<DeviceList>>, route_table: Rc<RefCell<RouteTable>>) -> Self {
|
||||
let rx_buffer = PacketBuffer::new(
|
||||
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0u8; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
);
|
||||
let tx_buffer = PacketBuffer::new(
|
||||
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0u8; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
);
|
||||
Self {
|
||||
rx_buffer,
|
||||
tx_buffer,
|
||||
devices,
|
||||
route_table,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MTU: usize = 1486;
|
||||
|
||||
pub fn poll(&mut self, now: Instant) {
|
||||
self.dispatch_outgoing(now);
|
||||
self.process_incoming(now);
|
||||
}
|
||||
|
||||
fn process_incoming(&mut self, now: Instant) {
|
||||
for dev in self.devices.borrow_mut().iter_mut() {
|
||||
if self.rx_buffer.is_full() {
|
||||
break;
|
||||
}
|
||||
|
||||
loop {
|
||||
if self.rx_buffer.is_full() {
|
||||
break;
|
||||
}
|
||||
|
||||
let Some(buf) = dev.recv(now) else {
|
||||
break;
|
||||
};
|
||||
|
||||
self.rx_buffer
|
||||
.enqueue(buf.len(), ())
|
||||
.expect("We checked if it was full")
|
||||
.copy_from_slice(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch_outgoing(&mut self, now: Instant) {
|
||||
while let Ok(((), packet)) = self.tx_buffer.dequeue() {
|
||||
if let Ok(mut packet) = smoltcp::wire::Ipv4Packet::new_checked(packet) {
|
||||
let dst_addr = IpAddress::Ipv4(packet.dst_addr());
|
||||
if packet.dst_addr().is_broadcast() {
|
||||
let buf = packet.into_inner();
|
||||
for dev in self.devices.borrow_mut().iter_mut() {
|
||||
dev.send(dst_addr, buf, now)
|
||||
}
|
||||
} else {
|
||||
let route_table = self.route_table.borrow();
|
||||
let Some(rule) = route_table.lookup_rule(&dst_addr) else {
|
||||
warn!("No route found for destination: {}", dst_addr);
|
||||
continue;
|
||||
};
|
||||
|
||||
let next_hop = match rule.via {
|
||||
Some(via) => via,
|
||||
None => dst_addr,
|
||||
};
|
||||
|
||||
let mut devices = self.devices.borrow_mut();
|
||||
let Some(dev) = devices.get_mut(&rule.dev) else {
|
||||
warn!("Device {} not found", rule.dev);
|
||||
// TODO: Remove route if device doesn't exist anymore ?
|
||||
continue;
|
||||
};
|
||||
|
||||
let IpAddress::Ipv4(src) = rule.src;
|
||||
if src != packet.src_addr() {
|
||||
packet.set_src_addr(src);
|
||||
packet.fill_checksum()
|
||||
}
|
||||
|
||||
dev.send(next_hop, packet.into_inner(), now);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for Router {
|
||||
type RxToken<'a> = RxToken<'a>;
|
||||
|
||||
type TxToken<'a> = TxToken<'a>;
|
||||
|
||||
fn receive(
|
||||
&mut self,
|
||||
_timestamp: smoltcp::time::Instant,
|
||||
) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||
if self.rx_buffer.is_empty() || self.tx_buffer.is_full() {
|
||||
None
|
||||
} else {
|
||||
Some((
|
||||
RxToken {
|
||||
rx_buffer: &mut self.rx_buffer,
|
||||
},
|
||||
TxToken {
|
||||
tx_buffer: &mut self.tx_buffer,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
|
||||
if self.tx_buffer.is_full() {
|
||||
None
|
||||
} else {
|
||||
Some(TxToken {
|
||||
tx_buffer: &mut self.tx_buffer,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.medium = Medium::Ip;
|
||||
caps.max_transmission_unit = Router::MTU;
|
||||
caps.max_burst_size = Some(Smolnetd::SOCKET_BUFFER_SIZE);
|
||||
caps
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TxToken<'a> {
|
||||
tx_buffer: &'a mut PacketBuffer,
|
||||
}
|
||||
|
||||
impl smoltcp::phy::TxToken for TxToken<'_> {
|
||||
fn consume<R, F>(self, len: usize, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> R,
|
||||
{
|
||||
f(self
|
||||
.tx_buffer
|
||||
.enqueue(len, ())
|
||||
.expect("This was checked before creating the TxToken"))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RxToken<'a> {
|
||||
rx_buffer: &'a mut PacketBuffer,
|
||||
}
|
||||
|
||||
impl<'a> smoltcp::phy::RxToken for RxToken<'a> {
|
||||
fn consume<R, F>(self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> R,
|
||||
{
|
||||
let ((), buf) = self
|
||||
.rx_buffer
|
||||
.dequeue()
|
||||
.expect("This was checked before creating the RxToken");
|
||||
|
||||
f(buf)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use smoltcp::wire::{IpAddress, IpCidr};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rule {
|
||||
pub filter: IpCidr,
|
||||
pub via: Option<IpAddress>,
|
||||
pub dev: Rc<str>,
|
||||
pub src: IpAddress,
|
||||
}
|
||||
|
||||
impl Rule {
|
||||
pub fn new(filter: IpCidr, via: Option<IpAddress>, dev: Rc<str>, src: IpAddress) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
via,
|
||||
dev,
|
||||
src,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RouteTable {
|
||||
rules: Vec<Rule>,
|
||||
}
|
||||
|
||||
impl RouteTable {
|
||||
pub fn lookup_rule(&self, dst: &IpAddress) -> Option<&Rule> {
|
||||
self.rules
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|rule| rule.filter.contains_addr(dst))
|
||||
}
|
||||
|
||||
pub fn lookup_src_addr(&self, dst: &IpAddress) -> Option<IpAddress> {
|
||||
Some(self.lookup_rule(dst)?.src)
|
||||
}
|
||||
|
||||
pub fn lookup_gateway(&self, dst: &IpAddress) -> Option<IpAddress> {
|
||||
self.lookup_rule(dst)?.via
|
||||
}
|
||||
|
||||
pub fn insert_rule(&mut self, new_rule: Rule) {
|
||||
let i = match self
|
||||
.rules
|
||||
.binary_search_by_key(&new_rule.filter.prefix_len(), |rule| {
|
||||
rule.filter.prefix_len()
|
||||
}) {
|
||||
Ok(i) | Err(i) => i,
|
||||
};
|
||||
self.rules.insert(i, new_rule);
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,10 @@ use syscall::{Error as SyscallError, Result as SyscallResult};
|
||||
use syscall;
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
|
||||
use crate::device::NetworkDevice;
|
||||
use crate::port_set::PortSet;
|
||||
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
|
||||
use super::{Smolnetd, SocketSet, Interface};
|
||||
use crate::router::Router;
|
||||
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme, Context};
|
||||
use super::{Smolnetd, SocketSet};
|
||||
|
||||
pub type IcmpScheme = SocketScheme<IcmpSocket<'static>>;
|
||||
|
||||
@@ -75,7 +75,7 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
|
||||
path: &str,
|
||||
_uid: u32,
|
||||
ident_set: &mut Self::SchemeDataT,
|
||||
iface: &Interface
|
||||
_context: &Context
|
||||
) -> SyscallResult<(SocketHandle, Self::DataT)> {
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -95,11 +95,11 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
|
||||
let socket = IcmpSocket::new(
|
||||
IcmpSocketBuffer::new(
|
||||
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
),
|
||||
IcmpSocketBuffer::new(
|
||||
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
)
|
||||
);
|
||||
let handle = socket_set.add(socket);
|
||||
@@ -127,11 +127,11 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
|
||||
let socket = IcmpSocket::new(
|
||||
IcmpSocketBuffer::new(
|
||||
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
),
|
||||
IcmpSocketBuffer::new(
|
||||
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
)
|
||||
);
|
||||
let handle = socket_set.add(socket);
|
||||
|
||||
@@ -5,9 +5,10 @@ use std::str;
|
||||
use syscall::{Error as SyscallError, Result as SyscallResult};
|
||||
use syscall;
|
||||
|
||||
use crate::device::NetworkDevice;
|
||||
use super::{Smolnetd, SocketSet, Interface};
|
||||
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
|
||||
use crate::router::Router;
|
||||
|
||||
use super::{Smolnetd, SocketSet};
|
||||
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme, Context};
|
||||
|
||||
pub type IpScheme = SocketScheme<RawSocket<'static>>;
|
||||
|
||||
@@ -59,7 +60,7 @@ impl<'a> SchemeSocket for RawSocket<'a> {
|
||||
path: &str,
|
||||
uid: u32,
|
||||
_: &mut Self::SchemeDataT,
|
||||
iface: &Interface
|
||||
_context: &Context
|
||||
) -> SyscallResult<(SocketHandle, Self::DataT)> {
|
||||
if uid != 0 {
|
||||
return Err(SyscallError::new(syscall::EACCES));
|
||||
@@ -69,11 +70,11 @@ impl<'a> SchemeSocket for RawSocket<'a> {
|
||||
|
||||
let rx_buffer = RawSocketBuffer::new(
|
||||
vec![RawPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
);
|
||||
let tx_buffer = RawSocketBuffer::new(
|
||||
vec![RawPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
);
|
||||
let ip_socket = RawSocket::new(
|
||||
IpVersion::Ipv4,
|
||||
|
||||
+116
-71
@@ -1,35 +1,41 @@
|
||||
use crate::link::ethernet::EthernetLink;
|
||||
use crate::link::LinkDevice;
|
||||
use crate::link::{loopback::LoopbackDevice, DeviceList};
|
||||
use crate::router::route_table::{RouteTable, Rule};
|
||||
use crate::router::Router;
|
||||
use crate::scheme::smoltcp::iface::SocketSet as SmoltcpSocketSet;
|
||||
use netutils::getcfg;
|
||||
use smoltcp;
|
||||
use smoltcp::iface::{Interface as SmoltcpInterface, Routes, Config};
|
||||
use smoltcp::iface::{Config, Interface as SmoltcpInterface};
|
||||
use smoltcp::phy::Tracer;
|
||||
use crate::scheme::smoltcp::iface::SocketSet as SmoltcpSocketSet;
|
||||
use smoltcp::time::{Duration, Instant};
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, IpListenEndpoint, HardwareAddress};
|
||||
use smoltcp::wire::{
|
||||
EthernetAddress, HardwareAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv4Address, Ipv4Cidr,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{Read, Write};
|
||||
use std::mem::size_of;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use syscall::data::TimeSpec;
|
||||
use syscall;
|
||||
use syscall::data::TimeSpec;
|
||||
|
||||
use crate::buffer_pool::{Buffer, BufferPool};
|
||||
use crate::device::NetworkDevice;
|
||||
use redox_netstack::error::{Error, Result};
|
||||
use self::icmp::IcmpScheme;
|
||||
use self::ip::IpScheme;
|
||||
use self::netcfg::NetCfgScheme;
|
||||
use self::tcp::TcpScheme;
|
||||
use self::udp::UdpScheme;
|
||||
use self::icmp::IcmpScheme;
|
||||
use self::netcfg::NetCfgScheme;
|
||||
use crate::buffer_pool::{Buffer, BufferPool};
|
||||
use redox_netstack::error::{Error, Result};
|
||||
|
||||
mod icmp;
|
||||
mod ip;
|
||||
mod netcfg;
|
||||
mod socket;
|
||||
mod tcp;
|
||||
mod udp;
|
||||
mod icmp;
|
||||
mod netcfg;
|
||||
|
||||
type SocketSet = SmoltcpSocketSet<'static>;
|
||||
type Interface = Rc<RefCell<SmoltcpInterface>>;
|
||||
@@ -38,11 +44,12 @@ const MAX_DURATION: Duration = Duration::from_millis(u64::MAX);
|
||||
const MIN_DURATION: Duration = Duration::from_millis(0);
|
||||
|
||||
pub struct Smolnetd {
|
||||
network_file: Rc<RefCell<File>>,
|
||||
network_device: Tracer<NetworkDevice>,
|
||||
router_device: Tracer<Router>,
|
||||
iface: Interface,
|
||||
link_devices: Rc<RefCell<DeviceList>>,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
time_file: File,
|
||||
|
||||
iface: Interface,
|
||||
socket_set: Rc<RefCell<SocketSet>>,
|
||||
timer: ::std::time::Instant,
|
||||
|
||||
@@ -57,10 +64,10 @@ pub struct Smolnetd {
|
||||
}
|
||||
|
||||
impl Smolnetd {
|
||||
const MAX_PACKET_SIZE: usize = 2048;
|
||||
const SOCKET_BUFFER_SIZE: usize = 128; //packets
|
||||
const MIN_CHECK_TIMEOUT: Duration = Duration::from_millis(10);
|
||||
const MAX_CHECK_TIMEOUT: Duration = Duration::from_millis(500);
|
||||
pub const MAX_PACKET_SIZE: usize = 2048;
|
||||
pub const SOCKET_BUFFER_SIZE: usize = 128; //packets
|
||||
pub const MIN_CHECK_TIMEOUT: Duration = Duration::from_millis(10);
|
||||
pub const MAX_CHECK_TIMEOUT: Duration = Duration::from_millis(500);
|
||||
|
||||
pub fn new(
|
||||
network_file: File,
|
||||
@@ -79,48 +86,104 @@ impl Smolnetd {
|
||||
IpCidr::new(local_ip, 24),
|
||||
IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8),
|
||||
];
|
||||
|
||||
let default_gw = Ipv4Address::from_str(getcfg("ip_router").unwrap().trim())
|
||||
.expect("Can't parse the 'ip_router' cfg.");
|
||||
|
||||
let buffer_pool = Rc::new(RefCell::new(BufferPool::new(Self::MAX_PACKET_SIZE)));
|
||||
let input_queue = Rc::new(RefCell::new(VecDeque::new()));
|
||||
let network_file = Rc::new(RefCell::new(network_file));
|
||||
let mut network_device = Tracer::new(NetworkDevice::new(
|
||||
Rc::clone(&network_file),
|
||||
Rc::clone(&input_queue),
|
||||
hardware_addr,
|
||||
Rc::clone(&buffer_pool),
|
||||
), |_timestamp, printer| {
|
||||
trace!("{}", printer)
|
||||
});
|
||||
let config = Config::new(HardwareAddress::Ethernet(hardware_addr));
|
||||
|
||||
let devices = Rc::new(RefCell::new(DeviceList::default()));
|
||||
let route_table = Rc::new(RefCell::new(RouteTable::default()));
|
||||
let mut network_device = Tracer::new(
|
||||
Router::new(Rc::clone(&devices), Rc::clone(&route_table)),
|
||||
|_timestamp, printer| trace!("{}", printer),
|
||||
);
|
||||
|
||||
let config = Config::new(HardwareAddress::Ip);
|
||||
let mut iface = SmoltcpInterface::new(config, &mut network_device, Instant::now());
|
||||
iface.update_ip_addrs(|ip_addrs| ip_addrs.extend(protocol_addrs));
|
||||
iface.routes_mut().add_default_ipv4_route(default_gw).expect("Failed to add default gateway");
|
||||
iface
|
||||
.routes_mut()
|
||||
.add_default_ipv4_route(default_gw)
|
||||
.expect("Failed to add default gateway");
|
||||
|
||||
let iface = Rc::new(RefCell::new(iface));
|
||||
let socket_set = Rc::new(RefCell::new(SocketSet::new(vec![])));
|
||||
|
||||
let loopback = LoopbackDevice::default();
|
||||
route_table.borrow_mut().insert_rule(Rule::new(
|
||||
"127.0.0.0/8".parse().unwrap(),
|
||||
None,
|
||||
Rc::clone(loopback.name()),
|
||||
"127.0.0.1".parse().unwrap(),
|
||||
));
|
||||
|
||||
let IpAddress::Ipv4(local_ip) = local_ip;
|
||||
let eth0 = EthernetLink::new(
|
||||
"eth0",
|
||||
network_file,
|
||||
hardware_addr,
|
||||
Ipv4Cidr::new(local_ip, 24),
|
||||
);
|
||||
|
||||
route_table.borrow_mut().insert_rule(Rule::new(
|
||||
IpCidr::new(IpAddress::Ipv4(local_ip), 24),
|
||||
None,
|
||||
Rc::clone(eth0.name()),
|
||||
IpAddress::Ipv4(local_ip),
|
||||
));
|
||||
|
||||
route_table.borrow_mut().insert_rule(Rule::new(
|
||||
"0.0.0.0/0".parse().unwrap(),
|
||||
Some(IpAddress::Ipv4(default_gw)),
|
||||
Rc::clone(eth0.name()),
|
||||
IpAddress::Ipv4(local_ip),
|
||||
));
|
||||
|
||||
devices.borrow_mut().push(loopback);
|
||||
devices.borrow_mut().push(eth0);
|
||||
|
||||
Smolnetd {
|
||||
iface: Rc::clone(&iface),
|
||||
network_device,
|
||||
router_device: network_device,
|
||||
route_table: Rc::clone(&route_table),
|
||||
socket_set: Rc::clone(&socket_set),
|
||||
timer: ::std::time::Instant::now(),
|
||||
link_devices: devices,
|
||||
time_file,
|
||||
ip_scheme: IpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), ip_file),
|
||||
udp_scheme: UdpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), udp_file),
|
||||
tcp_scheme: TcpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), tcp_file),
|
||||
icmp_scheme: IcmpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), icmp_file),
|
||||
ip_scheme: IpScheme::new(
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
ip_file,
|
||||
),
|
||||
udp_scheme: UdpScheme::new(
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
udp_file,
|
||||
),
|
||||
tcp_scheme: TcpScheme::new(
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
tcp_file,
|
||||
),
|
||||
icmp_scheme: IcmpScheme::new(
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
icmp_file,
|
||||
),
|
||||
netcfg_scheme: NetCfgScheme::new(Rc::clone(&iface), netcfg_file),
|
||||
input_queue,
|
||||
network_file,
|
||||
buffer_pool,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_network_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
if self.read_frames()? > 0 {
|
||||
self.poll()?;
|
||||
}
|
||||
self.poll()?;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@@ -183,22 +246,23 @@ impl Smolnetd {
|
||||
let mut iter_limit = 10usize;
|
||||
let mut iface = self.iface.borrow_mut();
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let timestamp = Instant::from(self.timer);
|
||||
|
||||
loop {
|
||||
let timestamp = Instant::from(self.timer);
|
||||
if iter_limit == 0 {
|
||||
break MIN_DURATION;
|
||||
}
|
||||
iter_limit -= 1;
|
||||
|
||||
// TODO: Check what if the bool returned by poll can be useful
|
||||
iface.poll(timestamp, &mut self.network_device, &mut socket_set);
|
||||
self.router_device.get_mut().poll(timestamp);
|
||||
|
||||
// TODO: Check what if the bool returned by poll can be useful
|
||||
iface.poll(timestamp, &mut self.router_device, &mut socket_set);
|
||||
|
||||
match iface.poll_delay(timestamp, &socket_set) {
|
||||
Some(delay) if delay == Duration::ZERO => { }
|
||||
Some(delay) => {
|
||||
break ::std::cmp::min(MAX_DURATION, delay)
|
||||
}
|
||||
None => break MAX_DURATION
|
||||
Some(delay) if delay == Duration::ZERO => {}
|
||||
Some(delay) => break ::std::cmp::min(MAX_DURATION, delay),
|
||||
None => break MAX_DURATION,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -211,26 +275,6 @@ impl Smolnetd {
|
||||
))
|
||||
}
|
||||
|
||||
fn read_frames(&mut self) -> Result<usize> {
|
||||
let mut total_frames = 0;
|
||||
loop {
|
||||
let mut buffer = self.buffer_pool.borrow_mut().get_buffer();
|
||||
let count = match self.network_file.borrow_mut().read(&mut buffer) {
|
||||
Ok(count) => count,
|
||||
Err(err) => match err.kind() {
|
||||
io::ErrorKind::WouldBlock => break,
|
||||
_ => return Err(
|
||||
Error::from_io_error(err, "Failed to read from network file")
|
||||
)
|
||||
}
|
||||
};
|
||||
buffer.resize(count);
|
||||
self.input_queue.borrow_mut().push_back(buffer);
|
||||
total_frames += 1;
|
||||
}
|
||||
Ok(total_frames)
|
||||
}
|
||||
|
||||
fn notify_sockets(&mut self) -> Result<()> {
|
||||
self.ip_scheme.notify_sockets()?;
|
||||
self.udp_scheme.notify_sockets()?;
|
||||
@@ -257,14 +301,15 @@ fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize)
|
||||
|
||||
fn parse_endpoint(socket: &str) -> IpListenEndpoint {
|
||||
let mut socket_parts = socket.split(':');
|
||||
let host =
|
||||
Ipv4Address::from_str(socket_parts.next().unwrap_or("")).ok().filter(|addr| !addr.is_unspecified()).map(IpAddress::Ipv4);
|
||||
|
||||
let host = Ipv4Address::from_str(socket_parts.next().unwrap_or(""))
|
||||
.ok()
|
||||
.filter(|addr| !addr.is_unspecified())
|
||||
.map(IpAddress::Ipv4);
|
||||
|
||||
let port = socket_parts
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
.parse::<u16>()
|
||||
.unwrap_or(0);
|
||||
IpListenEndpoint{ addr: host, port}
|
||||
IpListenEndpoint { addr: host, port }
|
||||
}
|
||||
|
||||
@@ -158,7 +158,8 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
"mac" => {
|
||||
rw [iface, notifier] (Option<EthernetAddress>, None)
|
||||
|| {
|
||||
format!("{}\n", iface.borrow().hardware_addr())
|
||||
// format!("{}\n", iface.borrow().hardware_addr())
|
||||
String::new()
|
||||
}
|
||||
|cur_value, line| {
|
||||
if cur_value.is_none() {
|
||||
@@ -175,7 +176,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
|
||||
}
|
||||
|cur_value| {
|
||||
if let Some(mac) = *cur_value {
|
||||
iface.borrow_mut().set_hardware_addr(smoltcp::wire::HardwareAddress::Ethernet(mac));
|
||||
// iface.borrow_mut().set_hardware_addr(smoltcp::wire::HardwareAddress::Ethernet(mac));
|
||||
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -19,12 +19,18 @@ use syscall::{
|
||||
};
|
||||
|
||||
use super::Interface;
|
||||
use crate::router::route_table::RouteTable;
|
||||
use crate::scheme::smoltcp::iface::SocketHandle;
|
||||
use redox_netstack::error::{Error, Result};
|
||||
use smoltcp::socket::AnySocket;
|
||||
|
||||
use super::{post_fevent, SocketSet};
|
||||
|
||||
pub struct Context {
|
||||
pub iface: Interface,
|
||||
pub route_table: Rc<RefCell<RouteTable>>,
|
||||
}
|
||||
|
||||
pub struct NullFile {
|
||||
pub flags: usize,
|
||||
pub uid: u32,
|
||||
@@ -192,7 +198,7 @@ where
|
||||
path: &str,
|
||||
uid: u32,
|
||||
data: &mut Self::SchemeDataT,
|
||||
iface: &Interface,
|
||||
context: &Context,
|
||||
) -> SyscallResult<(SocketHandle, Self::DataT)>;
|
||||
|
||||
fn close_file(
|
||||
@@ -231,7 +237,7 @@ where
|
||||
nulls: BTreeMap<usize, NullFile>,
|
||||
files: BTreeMap<usize, SchemeFile<SocketT>>,
|
||||
ref_counts: BTreeMap<SocketHandle, usize>,
|
||||
iface: Interface,
|
||||
context: Context,
|
||||
socket_set: Rc<RefCell<SocketSet>>,
|
||||
scheme_file: File,
|
||||
wait_queue: WaitQueue,
|
||||
@@ -245,13 +251,13 @@ where
|
||||
{
|
||||
pub fn new(
|
||||
iface: Interface,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
socket_set: Rc<RefCell<SocketSet>>,
|
||||
scheme_file: File,
|
||||
) -> SocketScheme<SocketT> {
|
||||
SocketScheme {
|
||||
next_fd: 1,
|
||||
nulls: BTreeMap::new(),
|
||||
iface,
|
||||
files: BTreeMap::new(),
|
||||
ref_counts: BTreeMap::new(),
|
||||
socket_set,
|
||||
@@ -259,6 +265,7 @@ where
|
||||
scheme_file,
|
||||
wait_queue: Vec::new(),
|
||||
_phantom_socket: PhantomData,
|
||||
context: Context { iface, route_table },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +521,7 @@ where
|
||||
path,
|
||||
uid,
|
||||
&mut self.scheme_data,
|
||||
&self.iface,
|
||||
&self.context,
|
||||
)?;
|
||||
|
||||
let file = SchemeFile::Socket(SocketFile {
|
||||
@@ -606,7 +613,12 @@ where
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
|
||||
return SocketT::write_buf(socket, file, buf);
|
||||
let ret = SocketT::write_buf(socket, file, buf);
|
||||
match ret {
|
||||
Ok(None) => {}
|
||||
_ => file.write_notified = false,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -626,7 +638,14 @@ where
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
|
||||
return SocketT::read_buf(socket, file, buf);
|
||||
|
||||
let ret = SocketT::read_buf(socket, file, buf);
|
||||
match ret {
|
||||
Ok(None) => {}
|
||||
_ => file.read_notified = false
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,8 +6,8 @@ use std::str;
|
||||
use syscall;
|
||||
use syscall::{Error as SyscallError, Result as SyscallResult};
|
||||
|
||||
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
|
||||
use super::{parse_endpoint, Interface, SocketSet};
|
||||
use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
|
||||
use super::{parse_endpoint, SocketSet};
|
||||
use crate::port_set::PortSet;
|
||||
|
||||
pub type TcpScheme = SocketScheme<TcpSocket<'static>>;
|
||||
@@ -62,7 +62,7 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
path: &str,
|
||||
uid: u32,
|
||||
port_set: &mut Self::SchemeDataT,
|
||||
iface: &Interface,
|
||||
context: &Context,
|
||||
) -> SyscallResult<(SocketHandle, Self::DataT)> {
|
||||
trace!("TCP open {}", path);
|
||||
let mut parts = path.split('/');
|
||||
@@ -92,10 +92,27 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
let tcp_socket = socket_set.get_mut::<TcpSocket>(socket_handle);
|
||||
|
||||
let listen_enpoint = if remote_endpoint.is_specified() {
|
||||
let local_endpoint_addr = match local_endpoint.addr {
|
||||
Some(addr) if !addr.is_unspecified() => Some(addr),
|
||||
_ => {
|
||||
let route_table = context.route_table.borrow();
|
||||
let addr = route_table
|
||||
.lookup_src_addr(&remote_endpoint.addr.expect("Checked in is_specified"));
|
||||
if matches!(addr, None) {
|
||||
error!("Opening a TCP connection with a probably invalid source IP as no route have been found for destination: {}", remote_endpoint);
|
||||
}
|
||||
addr
|
||||
}
|
||||
};
|
||||
let local_endpoint = IpListenEndpoint {
|
||||
addr: local_endpoint_addr,
|
||||
port: local_endpoint.port,
|
||||
};
|
||||
|
||||
trace!("Connecting tcp {} {}", local_endpoint, remote_endpoint);
|
||||
tcp_socket
|
||||
.connect(
|
||||
iface.borrow_mut().context(),
|
||||
context.iface.borrow_mut().context(),
|
||||
IpEndpoint::new(remote_endpoint.addr.unwrap(), remote_endpoint.port),
|
||||
local_endpoint,
|
||||
)
|
||||
@@ -264,11 +281,13 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
data: Some(endpoint),
|
||||
..
|
||||
}),
|
||||
) => if endpoint.is_specified() {
|
||||
write!(&mut path, "{}", endpoint).unwrap()
|
||||
} else {
|
||||
write!(&mut path, "0.0.0.0:{}", endpoint.port).unwrap()
|
||||
},
|
||||
) => {
|
||||
if endpoint.is_specified() {
|
||||
write!(&mut path, "{}", endpoint).unwrap()
|
||||
} else {
|
||||
write!(&mut path, "0.0.0.0:{}", endpoint.port).unwrap()
|
||||
}
|
||||
}
|
||||
_ => path.push_str(unspecified),
|
||||
}
|
||||
trace!("fpath: {}", path);
|
||||
|
||||
@@ -5,9 +5,9 @@ use std::str;
|
||||
use syscall::{Error as SyscallError, Result as SyscallResult};
|
||||
use syscall;
|
||||
|
||||
use crate::device::NetworkDevice;
|
||||
use crate::port_set::PortSet;
|
||||
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
|
||||
use crate::router::Router;
|
||||
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme, Context};
|
||||
use super::{parse_endpoint, Smolnetd, SocketSet, Interface};
|
||||
|
||||
pub type UdpScheme = SocketScheme<UdpSocket<'static>>;
|
||||
@@ -62,7 +62,7 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
|
||||
path: &str,
|
||||
uid: u32,
|
||||
port_set: &mut Self::SchemeDataT,
|
||||
_iface: &Interface
|
||||
_context: &Context
|
||||
) -> SyscallResult<(SocketHandle, Self::DataT)> {
|
||||
let mut parts = path.split('/');
|
||||
let remote_endpoint = parse_endpoint(parts.next().unwrap_or(""));
|
||||
@@ -74,11 +74,11 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
|
||||
|
||||
let rx_buffer = UdpSocketBuffer::new(
|
||||
vec![UdpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
);
|
||||
let tx_buffer = UdpSocketBuffer::new(
|
||||
vec![UdpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
|
||||
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
|
||||
);
|
||||
let udp_socket = UdpSocket::new(rx_buffer, tx_buffer);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user