Redo networking (#22)

* Rewriting network functions

* Add buffer to dup
Fix non-blocking handling by triggering once on enabling events to read to EOF

* Modifications for UDP API

* Implement TCP client side

* Add active close

* Add DMAR parser

* Implement basic TCP listening. Need to improve the state machine

* Reduce debugging

* Fixes for close procedure

* Updates to fix path processing in libstd
This commit is contained in:
Jeremy Soller 2016-10-26 13:19:56 -06:00 committed by GitHub
parent 268c859fd6
commit 2491e4771e
54 changed files with 1884 additions and 1476 deletions

View file

@ -3,6 +3,6 @@ name = "ipd"
version = "0.1.0"
[dependencies]
event = { path = "../../crates/event/" }
netutils = { path = "../../programs/netutils/" }
resource_scheme = { path = "../../crates/resource_scheme/" }
syscall = { path = "../../syscall/" }

View file

@ -1,120 +1,371 @@
#![feature(rand)]
//! Implementation of the IP Scheme as a userland driver.
//!
//! # Role
//!
//! See https://en.wikipedia.org/wiki/Internet_Protocol for more details about the
//! IP protocol. Clients will often prefer using either higher-level protocols TCP
//! or UDP, both of which are built upon IP.
//!
//! # URL Syntax
//!
//! To open a IP connection, use `ip:[host]/protocol`.
//!
//! * If `host` is specified, it must be an ipv4 number (e.g. `192.168.0.1`)
//! and the connection may be used immediately to send/receive data. Ip v4 number
//! `127.0.0.1` is hardwired to the loopback device (i.e. localhost), which doesn't
//! access any physical device and in which data can only be read by the same
//! connection that has written it.
//! * If `host` is omitted, this connectino will wait for a distant peer to
//! connect.
//! * The `protocol` is the hex-based number of the ip protocol
//! (see http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml).
extern crate event;
extern crate netutils;
extern crate resource_scheme;
extern crate syscall;
use event::EventQueue;
use netutils::{getcfg, n16, Ipv4Addr, MacAddr, Ipv4, EthernetII, EthernetIIHeader, Arp, Tcp};
use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{Read, Write};
use std::thread;
use std::io::{self, Read, Write};
use std::os::unix::io::FromRawFd;
use std::rc::Rc;
use std::{slice, str, thread};
use syscall::data::Packet;
use syscall::error::{Error, Result, EACCES, EADDRNOTAVAIL, EBADF, EINVAL, ENOENT, EWOULDBLOCK};
use syscall::flag::{EVENT_READ, O_NONBLOCK};
use syscall::scheme::SchemeMut;
use resource_scheme::ResourceScheme;
use syscall::Packet;
struct Interface {
mac: MacAddr,
ip: Ipv4Addr,
router: Ipv4Addr,
subnet: Ipv4Addr,
arp_file: File,
ip_file: File,
arp: BTreeMap<Ipv4Addr, MacAddr>,
rarp: BTreeMap<MacAddr, Ipv4Addr>,
}
use scheme::IpScheme;
impl Interface {
fn new(arp_fd: usize, ip_fd: usize) -> Self {
Interface {
mac: MacAddr::from_str(&getcfg("mac").unwrap()),
ip: Ipv4Addr::from_str(&getcfg("ip").unwrap()),
router: Ipv4Addr::from_str(&getcfg("ip_router").unwrap()),
subnet: Ipv4Addr::from_str(&getcfg("ip_subnet").unwrap()),
arp_file: unsafe { File::from_raw_fd(arp_fd) },
ip_file: unsafe { File::from_raw_fd(ip_fd) },
arp: BTreeMap::new(),
rarp: BTreeMap::new(),
}
}
}
mod resource;
mod scheme;
struct Handle {
proto: u8,
flags: usize,
events: usize,
data: VecDeque<Vec<u8>>,
todo: VecDeque<Packet>,
}
struct Ipd {
scheme_file: File,
interfaces: Vec<Interface>,
next_id: usize,
handles: BTreeMap<usize, Handle>,
}
impl Ipd {
fn new(scheme_file: File) -> Self {
Ipd {
scheme_file: scheme_file,
interfaces: Vec::new(),
next_id: 1,
handles: BTreeMap::new(),
}
}
fn scheme_event(&mut self) -> io::Result<()> {
loop {
let mut packet = Packet::default();
if self.scheme_file.read(&mut packet)? == 0 {
break;
}
let a = packet.a;
self.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
if let Some(mut handle) = self.handles.get_mut(&packet.b) {
handle.todo.push_back(packet);
}
} else {
self.scheme_file.write(&packet)?;
}
}
Ok(())
}
fn arp_event(&mut self, if_id: usize) -> io::Result<()> {
if let Some(mut interface) = self.interfaces.get_mut(if_id) {
loop {
let mut bytes = [0; 65536];
let count = interface.arp_file.read(&mut bytes)?;
if count == 0 {
break;
}
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
if let Some(packet) = Arp::from_bytes(&frame.data) {
if packet.header.oper.get() == 1 {
if packet.header.dst_ip == interface.ip {
let mut response = Arp {
header: packet.header,
data: packet.data.clone(),
};
response.header.oper.set(2);
response.header.dst_mac = packet.header.src_mac;
response.header.dst_ip = packet.header.src_ip;
response.header.src_mac = interface.mac;
response.header.src_ip = interface.ip;
let mut response_frame = EthernetII {
header: frame.header,
data: response.to_bytes()
};
response_frame.header.dst = response_frame.header.src;
response_frame.header.src = interface.mac;
interface.arp_file.write(&response_frame.to_bytes())?;
}
}
}
}
}
}
Ok(())
}
fn ip_event(&mut self, if_id: usize) -> io::Result<()> {
if let Some(mut interface) = self.interfaces.get_mut(if_id) {
loop {
let mut bytes = [0; 65536];
let count = interface.ip_file.read(&mut bytes)?;
if count == 0 {
break;
}
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
if let Some(ip) = Ipv4::from_bytes(&frame.data) {
if ip.header.dst == interface.ip || ip.header.dst == Ipv4Addr::BROADCAST {
//TODO: Handle ping here
for (id, handle) in self.handles.iter_mut() {
if ip.header.proto == handle.proto {
handle.data.push_back(frame.data.clone());
while ! handle.todo.is_empty() && ! handle.data.is_empty() {
let mut packet = handle.todo.pop_front().unwrap();
let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) };
let data = handle.data.pop_front().unwrap();
let mut i = 0;
while i < buf.len() && i < data.len() {
buf[i] = data[i];
i += 1;
}
packet.a = i;
self.scheme_file.write(&packet)?;
}
if handle.events & EVENT_READ == EVENT_READ {
if let Some(data) = handle.data.get(0) {
self.scheme_file.write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: *id,
c: EVENT_READ,
d: data.len()
})?;
}
}
}
}
}
}
}
}
}
Ok(())
}
}
impl SchemeMut for Ipd {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?;
let proto = u8::from_str_radix(path, 16).or(Err(Error::new(ENOENT)))?;
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle {
proto: proto,
flags: flags,
events: 0,
data: VecDeque::new(),
todo: VecDeque::new(),
});
Ok(id)
} else {
Err(Error::new(EACCES))
}
}
fn dup(&mut self, file: usize, _buf: &[u8]) -> Result<usize> {
let handle = {
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
Handle {
proto: handle.proto,
flags: handle.flags,
events: 0,
data: handle.data.clone(),
todo: VecDeque::new(),
}
};
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, handle);
Ok(id)
}
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
if let Some(data) = handle.data.pop_front() {
let mut i = 0;
while i < buf.len() && i < data.len() {
buf[i] = data[i];
i += 1;
}
Ok(i)
} else if handle.flags & O_NONBLOCK == O_NONBLOCK {
Ok(0)
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
if let Some(mut ip) = Ipv4::from_bytes(buf) {
for mut interface in self.interfaces.iter_mut() {
if ip.header.src == interface.ip || ip.header.src == Ipv4Addr::NULL {
ip.header.src = interface.ip;
ip.header.proto = handle.proto;
if let Some(mut tcp) = Tcp::from_bytes(&ip.data) {
tcp.checksum(&ip.header.src, &ip.header.dst);
ip.data = tcp.to_bytes();
}
ip.checksum();
let frame = EthernetII {
header: EthernetIIHeader {
//TODO: Get real dst
dst: MacAddr::BROADCAST,
src: interface.mac,
ethertype: n16::new(0x800),
},
data: ip.to_bytes()
};
interface.ip_file.write(&frame.to_bytes()).map_err(|err| err.into_sys())?;
return Ok(buf.len());
}
}
Err(Error::new(EADDRNOTAVAIL))
} else {
Err(Error::new(EINVAL))
}
}
fn fevent(&mut self, file: usize, flags: usize) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
handle.events = flags;
Ok(file)
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_string = format!("ip:{:X}", handle.proto);
let path = path_string.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
fn fsync(&mut self, file: usize) -> Result<usize> {
let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
Ok(0)
}
fn close(&mut self, file: usize) -> Result<usize> {
let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?;
drop(handle);
Ok(0)
}
}
fn main() {
thread::spawn(move || {
let mut socket = File::create(":ip").expect("ipd: failed to create ip scheme");
let scheme = IpScheme::new();
loop {
let mut packet = Packet::default();
socket.read(&mut packet).expect("ipd: failed to read events from ip scheme");
scheme.handle(&mut packet);
socket.write(&packet).expect("ipd: failed to write responses to ip scheme");
let scheme_fd = syscall::open(":ip", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ipd: failed to create :ip");
let scheme_file = unsafe { File::from_raw_fd(scheme_fd) };
let ipd = Rc::new(RefCell::new(Ipd::new(scheme_file)));
let mut event_queue = EventQueue::<()>::new().expect("ipd: failed to create event queue");
//TODO: Multiple interfaces
{
let arp_fd = syscall::open("ethernet:806", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:806");
let ip_fd = syscall::open("ethernet:800", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:800");
let if_id = {
let mut ipd = ipd.borrow_mut();
let if_id = ipd.interfaces.len();
ipd.interfaces.push(Interface::new(arp_fd, ip_fd));
if_id
};
let arp_ipd = ipd.clone();
event_queue.add(arp_fd, move |_count: usize| -> io::Result<Option<()>> {
arp_ipd.borrow_mut().arp_event(if_id)?;
Ok(None)
}).expect("ipd: failed to listen to events on ethernet:806");
let ip_ipd = ipd.clone();
event_queue.add(ip_fd, move |_count: usize| -> io::Result<Option<()>> {
ip_ipd.borrow_mut().ip_event(if_id)?;
Ok(None)
}).expect("ipd: failed to listen to events on ethernet:800");
}
event_queue.add(scheme_fd, move |_count: usize| -> io::Result<Option<()>> {
ipd.borrow_mut().scheme_event()?;
Ok(None)
}).expect("ipd: failed to listen to events on :ip");
// Make sure that all descriptors are at EOF
event_queue.trigger_all(0).expect("ipd: failed to trigger event queue");
event_queue.run().expect("ipd: failed to run event queue");
});
}
#[cfg(test)]
fn test() {
use scheme::IpScheme;
println!("* Test that we can read a simple packet from the same connection.");
let bytes = "TEST".as_bytes();
let mut scheme = IpScheme::new();
let a = scheme.open(&"ip:127.0.0.1/11".as_bytes(), 0, 0, 0).unwrap();
let num_bytes_written = scheme.write(a, bytes).unwrap();
assert_eq!(num_bytes_written, bytes.len());
let mut buf = [0;65536];
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(num_bytes_read, num_bytes_written);
let bytes_read = &buf[0..num_bytes_read];
assert_eq!(bytes, bytes_read);
println!("* Test that the loopback is now empty.");
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(num_bytes_read, 0);
println!("* Test that we can read the same packet from a different connection.");
let num_bytes_written = scheme.write(a, bytes).unwrap();
assert_eq!(num_bytes_written, bytes.len());
let b = scheme.open("ip:127.0.0.1/11".as_bytes(), 0, 0, 0).unwrap();
let num_bytes_read = scheme.read(b, &mut buf).unwrap();
assert_eq!(num_bytes_read, num_bytes_written);
let bytes_read = &buf[0..num_bytes_read];
assert_eq!(bytes, bytes_read);
println!("* Test that the loopback is now empty for both connections.");
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(num_bytes_read, 0);
let num_bytes_read = scheme.read(b, &mut buf).unwrap();
assert_eq!(num_bytes_read, 0);
println!("* Push a number of packets, check that we get them in the right order.");
let mut payloads : Vec<String> = (0..100).map(|i| format!("TEST {}", i)).collect();
for payload in &payloads {
let bytes = payload.into_bytes();
let num_bytes_written = scheme.write(a, &bytes).unwrap();
assert_eq!(bytes.len(), num_bytes_written);
}
for payload in &payloads {
let bytes = payload.into_bytes();
let mut buf = [0;65536];
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(bytes.len(), num_bytes_read);
let bytes_read = &buf[0..num_bytes_read];
assert_eq!(bytes, bytes_read);
}
}

View file

@ -1,242 +0,0 @@
use std::cell::RefCell;
use std::{cmp, mem};
use std::collections::VecDeque;
use std::rc::Rc;
use std::sync::Mutex;
use netutils::{n16, Ipv4Addr, Checksum, Ipv4Header, Ipv4};
use resource_scheme::Resource;
use syscall;
use syscall::error::*;
/// Max number of bytes in a packet.
const MAX_PACKET_LENGTH : usize = 65536;
/// A IP (internet protocol) resource.
///
/// Each instance represents a connection (~ a IP socket).
pub struct IpResource {
/// The underlying mechanism ensured to connect to the peer.
pub connection: Connection,
/// The IP address of the host (i.e. this machine).
pub host_addr: Ipv4Addr,
/// The IP address of the peer (i.e. the other machine).
pub peer_addr: Ipv4Addr,
/// The IP protocol used by this connection. See
/// http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
/// for the list of valid protocols.
pub proto: u8,
/// The id of the next packet being sent.
/// See https://en.wikipedia.org/wiki/IPv4#Identification .
pub id: u16,
}
pub enum Connection {
Device {
/// Link to the underlying device (typically, an Ethernet card).
link: usize,
/// If this connection was opened waiting for a peer (i.e. `ip:/protocol`),
/// the data received when the peer actually connected. Otherwise, empty.
/// Emptied during the first call to `read()`.
init_data: Vec<u8>,
},
Loopback {
/// FIFO queue of packets written to the loopback and waiting to be read.
///
/// The data stored contains the exact data that has been added by the client
/// calling `write()`, without adding any headers.
///
/// This buffer is shared between all loopback connections.
packets: Rc<RefCell<VecDeque<Vec<u8>>>>
}
}
impl Resource for IpResource {
/// Duplicate the connection.
///
/// This duplicates both `self.link` and `self.init_data`.
///
/// # Errors
///
/// Fails if the `link` to the underlying device cannot be
/// duplicated.
fn dup(&self) -> Result<Box<Self>> {
use self::Connection::*;
let connection = match self.connection {
Loopback { ref packets }=> Loopback { packets: packets.clone() },
Device { link, ref init_data } => {
let link = try!(syscall::dup(link));
let init_data = init_data.clone();
Device {
link: link,
init_data: init_data
}
}
};
Ok(Box::new(IpResource {
host_addr: self.host_addr,
peer_addr: self.peer_addr,
proto: self.proto,
id: self.id,
connection: connection,
}))
}
/// Get the current path, as `ip:peer/protocol`, where `peer`
/// is the IPv4 address of the peer and `protocol` is the hex-based
/// number of the IP protocol used.
///
/// Note that the `peer` is specified even if the connection was initially
/// created as `ip:/protocol`.
fn path(&self, buf: &mut [u8]) -> Result<usize> {
let path_string = format!("ip:{}/{:X}", self.peer_addr.to_string(), self.proto);
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
}
Ok(cmp::min(buf.len(), path.len()))
}
/// Read data from the device.
///
/// If some data has already been made available during the establishment
/// of the connection, this data is (entirely) read during the first call
/// to `read()`, without attempting to actually read from the device. This
/// can happen only if the connection was waiting for a remote peer to connect, i.e.
/// with a url `ip:/protocol`, without host.
///
/// If this connection is a loopback, oldest unread packet written is read.
///
/// # Errors
///
/// Fails if the call to `syscall::read()` fails for this device.
///
/// # Data loss
///
/// If `buf` is too small, *exceeding data is discarded*. To be sure that you read
/// all data, you should provide a 64kb `buf`.
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
use self::Connection::*;
match self.connection {
Loopback { ref packets }=> {
match packets.borrow_mut().pop_front() {
None => Ok(0),
Some(data) => {
for (b, d) in buf.iter_mut().zip(data.iter()) {
*b = *d;
}
// Note: We're discarding excess `data`.
Ok(cmp::min(buf.len(), data.len()))
}
}
}
Device { ref mut init_data, link } => {
if !init_data.is_empty() {
let mut data: Vec<u8> = Vec::new();
mem::swap(init_data, &mut data);
for (b, d) in buf.iter_mut().zip(data.iter()) {
*b = *d;
}
return Ok(cmp::min(buf.len(), data.len()));
}
let mut bytes = [0; MAX_PACKET_LENGTH];
let count = try!(syscall::read(link, &mut bytes));
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
if packet.header.proto == self.proto &&
(packet.header.dst.equals(self.host_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) &&
(packet.header.src.equals(self.peer_addr) || self.peer_addr.equals(Ipv4Addr::BROADCAST)) {
for (b, d) in buf.iter_mut().zip(packet.data.iter()) {
*b = *d;
}
return Ok(cmp::min(buf.len(), packet.data.len()));
}
}
Ok(0)
}
}
}
/// Send data to the peer.
///
/// # Errors
///
/// Fails if the call to `syscall::write()` fails for this device.
fn write(&mut self, buf: &[u8]) -> Result<usize> {
use self::Connection::*;
let ip_data = Vec::from(buf);
match self.connection {
Loopback { ref packets } => {
// Make sure that we're not going to store data that can't be read.
let buf =
if buf.len() > MAX_PACKET_LENGTH {
&buf[0..MAX_PACKET_LENGTH]
} else {
buf
};
packets.borrow_mut().push_back(buf.to_vec());
return Ok(buf.len())
}
Device { link, .. } => {
self.id += 1;
let mut ip = Ipv4 {
header: Ipv4Header {
ver_hlen: 0x40 | (mem::size_of::<Ipv4Header>() / 4 & 0xF) as u8, // No Options
services: 0,
len: n16::new((mem::size_of::<Ipv4Header>() + ip_data.len()) as u16), // No Options
id: n16::new(self.id),
flags_fragment: n16::new(0),
ttl: 128,
proto: self.proto,
checksum: Checksum { data: 0 },
src: self.host_addr,
dst: self.peer_addr,
},
options: Vec::new(),
data: ip_data,
};
unsafe {
let header_ptr: *const Ipv4Header = &ip.header;
ip.header.checksum.data =
Checksum::compile(Checksum::sum(header_ptr as usize, mem::size_of::<Ipv4Header>()) +
Checksum::sum(ip.options.as_ptr() as usize, ip.options.len()));
}
match syscall::write(link, &ip.to_bytes()) {
Ok(_) => Ok(buf.len()),
Err(err) => Err(err),
}
}
}
}
fn sync(&mut self) -> Result<usize> {
if let Connection::Device { link, .. } = self.connection {
syscall::fsync(link)
} else {
Ok(0)
}
}
}
impl Drop for IpResource {
fn drop(&mut self) {
if let Connection::Device { link, .. } = self.connection {
let _ = syscall::close(link);
}
}
}

View file

@ -1,193 +0,0 @@
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rand;
use std::rc::Rc;
use std::{str, u16};
use netutils::{getcfg, n16, MacAddr, Ipv4Addr, ArpHeader, Arp, Ipv4};
use resource_scheme::ResourceScheme;
use syscall;
use syscall::error::{Error, Result, EACCES, ENOENT, EINVAL};
use syscall::flag::O_RDWR;
use resource::*;
/// The IP address of the localhost.
const LOCALHOST: Ipv4Addr = Ipv4Addr { bytes: [127, 0, 0, 1] };
/// A ARP entry (MAC + IP)
pub struct ArpEntry {
ip: Ipv4Addr,
mac: MacAddr,
}
/// A IP scheme
pub struct IpScheme {
pub arp: RefCell<Vec<ArpEntry>>,
/// FIFO queue of packets written to the loopback and waiting to be read.
///
/// The data stored contains the exact data that has been added by the client
/// calling `write()`, without adding any headers.
///
/// This buffer is shared between all loopback connections.
pub loopback_fifo: Rc<RefCell<VecDeque<Vec<u8>>>>,
}
impl IpScheme {
pub fn new() -> IpScheme {
IpScheme {
arp: RefCell::new(Vec::new()),
loopback_fifo: Rc::new(RefCell::new(VecDeque::new())),
}
}
}
impl ResourceScheme<IpResource> for IpScheme {
fn open_resource(&self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<Box<IpResource>> {
if uid == 0 {
let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?);
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").map_err(|err| err.into_sys())?);
let ip_subnet = Ipv4Addr::from_str(&getcfg("ip_subnet").map_err(|err| err.into_sys())?);
let ip_router = Ipv4Addr::from_str(&getcfg("ip_router").map_err(|err| err.into_sys())?);
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
let mut parts = path.split('/');
if let Some(host_string) = parts.next() {
if let Some(proto_string) = parts.next() {
let proto = u8::from_str_radix(proto_string, 16).unwrap_or(0);
if ! host_string.is_empty() {
let peer_addr = Ipv4Addr::from_str(host_string);
let mut route_mac = MacAddr::BROADCAST;
if ! peer_addr.equals(Ipv4Addr::BROADCAST) {
if peer_addr.equals(LOCALHOST) {
return Ok(Box::new(IpResource {
connection: Connection::Loopback {
packets: self.loopback_fifo.clone()
},
host_addr: ip_addr,
peer_addr: peer_addr,
proto: proto,
id: (rand() % 65536) as u16,
}));
}
let mut needs_routing = false;
for octet in 0..4 {
let me = ip_addr.bytes[octet];
let mask = ip_subnet.bytes[octet];
let them = peer_addr.bytes[octet];
if me & mask != them & mask {
needs_routing = true;
break;
}
}
let route_addr = if needs_routing {
ip_router
} else {
peer_addr
};
for entry in self.arp.borrow().iter() {
if entry.ip.equals(route_addr) {
route_mac = entry.mac;
break;
}
}
if route_mac.equals(MacAddr::BROADCAST) {
if let Ok(link) = syscall::open(&format!("ethernet:{}/806", &route_mac.to_string()), O_RDWR) {
let arp = Arp {
header: ArpHeader {
htype: n16::new(1),
ptype: n16::new(0x800),
hlen: 6,
plen: 4,
oper: n16::new(1),
src_mac: mac_addr,
src_ip: ip_addr,
dst_mac: route_mac,
dst_ip: route_addr,
},
data: Vec::new(),
};
match syscall::write(link, &arp.to_bytes()) {
Ok(_) => loop {
let mut bytes = [0; 65536];
match syscall::read(link, &mut bytes) {
Ok(count) => if let Some(packet) = Arp::from_bytes(&bytes[..count]) {
if packet.header.oper.get() == 2 &&
packet.header.src_ip.equals(route_addr) {
route_mac = packet.header.src_mac;
self.arp.borrow_mut().push(ArpEntry {
ip: route_addr,
mac: route_mac,
});
break;
}
},
Err(_) => (),
}
},
Err(err) => println!("IP: ARP Write Failed: {}", err),
}
}
}
}
if let Ok(link) = syscall::open(&format!("ethernet:{}/800", &route_mac.to_string()), O_RDWR) {
return Ok(Box::new(IpResource {
connection: Connection::Device {
link: link,
init_data: Vec::new(),
},
host_addr: ip_addr,
peer_addr: peer_addr,
proto: proto,
id: (rand() % 65536) as u16,
}));
}
} else {
while let Ok(link) = syscall::open("ethernet:/800", O_RDWR) {
let mut bytes = [0; 65536];
// FIXME: Blocking call?
match syscall::read(link, &mut bytes) {
Ok(count) => {
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
if packet.header.proto == proto &&
(packet.header.dst.equals(ip_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) {
return Ok(Box::new(IpResource {
connection: Connection::Device {
link: link,
init_data: packet.data,
},
host_addr: ip_addr,
peer_addr: packet.header.src,
proto: proto,
id: (rand() % 65536) as u16,
}));
}
}
}
Err(_) => break,
}
}
}
} else {
println!("IP: No protocol provided");
}
} else {
println!("IP: No host provided");
}
Err(Error::new(ENOENT))
} else {
Err(Error::new(EACCES))
}
}
}