-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
xous: net: initial commit of network support
This is an initial commit of network support for Xous. On hardware, is backed by smoltcp running via a Xous server in a separate process space. This patch adds TCP and UDP client and server support as well as DNS resolution support using the dns Xous server. Signed-off-by: Sean Cross <sean@xobs.io>
- Loading branch information
Showing
9 changed files
with
1,493 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use crate::os::xous::ffi::Connection; | ||
use crate::os::xous::services::connect; | ||
use core::sync::atomic::{AtomicU32, Ordering}; | ||
|
||
#[repr(usize)] | ||
pub(crate) enum DnsLendMut { | ||
RawLookup = 6, | ||
} | ||
|
||
impl Into<usize> for DnsLendMut { | ||
fn into(self) -> usize { | ||
self as usize | ||
} | ||
} | ||
|
||
/// Return a `Connection` to the DNS lookup server. This server is used for | ||
/// querying domain name values. | ||
pub(crate) fn dns_server() -> Connection { | ||
static DNS_CONNECTION: AtomicU32 = AtomicU32::new(0); | ||
let cid = DNS_CONNECTION.load(Ordering::Relaxed); | ||
if cid != 0 { | ||
return cid.into(); | ||
} | ||
|
||
let cid = connect("_DNS Resolver Middleware_").unwrap(); | ||
DNS_CONNECTION.store(cid.into(), Ordering::Relaxed); | ||
cid | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use crate::os::xous::ffi::Connection; | ||
use crate::os::xous::services::connect; | ||
use core::sync::atomic::{AtomicU32, Ordering}; | ||
|
||
pub(crate) enum NetBlockingScalar { | ||
StdGetTtlUdp(u16 /* fd */), /* 36 */ | ||
StdSetTtlUdp(u16 /* fd */, u32 /* ttl */), /* 37 */ | ||
StdGetTtlTcp(u16 /* fd */), /* 36 */ | ||
StdSetTtlTcp(u16 /* fd */, u32 /* ttl */), /* 37 */ | ||
StdGetNodelay(u16 /* fd */), /* 38 */ | ||
StdSetNodelay(u16 /* fd */, bool), /* 39 */ | ||
StdTcpClose(u16 /* fd */), /* 34 */ | ||
StdUdpClose(u16 /* fd */), /* 41 */ | ||
StdTcpStreamShutdown(u16 /* fd */, crate::net::Shutdown /* how */), /* 46 */ | ||
} | ||
|
||
pub(crate) enum NetLendMut { | ||
StdTcpConnect, /* 30 */ | ||
StdTcpTx(u16 /* fd */), /* 31 */ | ||
StdTcpPeek(u16 /* fd */, bool /* nonblocking */), /* 32 */ | ||
StdTcpRx(u16 /* fd */, bool /* nonblocking */), /* 33 */ | ||
StdGetAddress(u16 /* fd */), /* 35 */ | ||
StdUdpBind, /* 40 */ | ||
StdUdpRx(u16 /* fd */), /* 42 */ | ||
StdUdpTx(u16 /* fd */), /* 43 */ | ||
StdTcpListen, /* 44 */ | ||
StdTcpAccept(u16 /* fd */), /* 45 */ | ||
} | ||
|
||
impl Into<usize> for NetLendMut { | ||
fn into(self) -> usize { | ||
match self { | ||
NetLendMut::StdTcpConnect => 30, | ||
NetLendMut::StdTcpTx(fd) => 31 | ((fd as usize) << 16), | ||
NetLendMut::StdTcpPeek(fd, blocking) => { | ||
32 | ((fd as usize) << 16) | if blocking { 0x8000 } else { 0 } | ||
} | ||
NetLendMut::StdTcpRx(fd, blocking) => { | ||
33 | ((fd as usize) << 16) | if blocking { 0x8000 } else { 0 } | ||
} | ||
NetLendMut::StdGetAddress(fd) => 35 | ((fd as usize) << 16), | ||
NetLendMut::StdUdpBind => 40, | ||
NetLendMut::StdUdpRx(fd) => 42 | ((fd as usize) << 16), | ||
NetLendMut::StdUdpTx(fd) => 43 | ((fd as usize) << 16), | ||
NetLendMut::StdTcpListen => 44, | ||
NetLendMut::StdTcpAccept(fd) => 45 | ((fd as usize) << 16), | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Into<[usize; 5]> for NetBlockingScalar { | ||
fn into(self) -> [usize; 5] { | ||
match self { | ||
NetBlockingScalar::StdGetTtlTcp(fd) => [36 | ((fd as usize) << 16), 0, 0, 0, 0], | ||
NetBlockingScalar::StdGetTtlUdp(fd) => [36 | ((fd as usize) << 16), 0, 0, 0, 1], | ||
NetBlockingScalar::StdSetTtlTcp(fd, ttl) => { | ||
[37 | ((fd as usize) << 16), ttl as _, 0, 0, 0] | ||
} | ||
NetBlockingScalar::StdSetTtlUdp(fd, ttl) => { | ||
[37 | ((fd as usize) << 16), ttl as _, 0, 0, 1] | ||
} | ||
NetBlockingScalar::StdGetNodelay(fd) => [38 | ((fd as usize) << 16), 0, 0, 0, 0], | ||
NetBlockingScalar::StdSetNodelay(fd, enabled) => { | ||
[39 | ((fd as usize) << 16), if enabled { 1 } else { 0 }, 0, 0, 1] | ||
} | ||
NetBlockingScalar::StdTcpClose(fd) => [34 | ((fd as usize) << 16), 0, 0, 0, 0], | ||
NetBlockingScalar::StdUdpClose(fd) => [41 | ((fd as usize) << 16), 0, 0, 0, 0], | ||
NetBlockingScalar::StdTcpStreamShutdown(fd, how) => [ | ||
46 | ((fd as usize) << 16), | ||
match how { | ||
crate::net::Shutdown::Read => 1, | ||
crate::net::Shutdown::Write => 2, | ||
crate::net::Shutdown::Both => 3, | ||
}, | ||
0, | ||
0, | ||
0, | ||
], | ||
} | ||
} | ||
} | ||
|
||
/// Return a `Connection` to the Network server. This server provides all | ||
/// OS-level networking functions. | ||
pub(crate) fn net_server() -> Connection { | ||
static NET_CONNECTION: AtomicU32 = AtomicU32::new(0); | ||
let cid = NET_CONNECTION.load(Ordering::Relaxed); | ||
if cid != 0 { | ||
return cid.into(); | ||
} | ||
|
||
let cid = connect("_Middleware Network Server_").unwrap(); | ||
NET_CONNECTION.store(cid.into(), Ordering::Relaxed); | ||
cid | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
use crate::io; | ||
use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; | ||
use crate::os::xous::ffi::lend_mut; | ||
use crate::os::xous::services::{dns_server, DnsLendMut}; | ||
use core::convert::{TryFrom, TryInto}; | ||
|
||
pub struct DnsError { | ||
pub code: u8, | ||
} | ||
|
||
#[repr(C, align(4096))] | ||
struct LookupHostQuery([u8; 4096]); | ||
|
||
pub struct LookupHost { | ||
data: LookupHostQuery, | ||
port: u16, | ||
offset: usize, | ||
count: usize, | ||
} | ||
|
||
impl LookupHost { | ||
pub fn port(&self) -> u16 { | ||
self.port | ||
} | ||
} | ||
|
||
impl Iterator for LookupHost { | ||
type Item = SocketAddr; | ||
fn next(&mut self) -> Option<SocketAddr> { | ||
if self.offset >= self.data.0.len() { | ||
return None; | ||
} | ||
match self.data.0.get(self.offset) { | ||
Some(&4) => { | ||
self.offset += 1; | ||
if self.offset + 4 > self.data.0.len() { | ||
return None; | ||
} | ||
let result = Some(SocketAddr::V4(SocketAddrV4::new( | ||
Ipv4Addr::new( | ||
self.data.0[self.offset], | ||
self.data.0[self.offset + 1], | ||
self.data.0[self.offset + 2], | ||
self.data.0[self.offset + 3], | ||
), | ||
self.port, | ||
))); | ||
self.offset += 4; | ||
result | ||
} | ||
Some(&6) => { | ||
self.offset += 1; | ||
if self.offset + 16 > self.data.0.len() { | ||
return None; | ||
} | ||
let mut new_addr = [0u8; 16]; | ||
for (src, octet) in self.data.0[(self.offset + 1)..(self.offset + 16 + 1)] | ||
.iter() | ||
.zip(new_addr.iter_mut()) | ||
{ | ||
*octet = *src; | ||
} | ||
let result = | ||
Some(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.port, 0, 0))); | ||
self.offset += 16; | ||
result | ||
} | ||
_ => None, | ||
} | ||
} | ||
} | ||
|
||
pub fn lookup(query: &str, port: u16) -> Result<LookupHost, DnsError> { | ||
let mut result = LookupHost { data: LookupHostQuery([0u8; 4096]), offset: 0, count: 0, port }; | ||
|
||
// Copy the query into the message that gets sent to the DNS server | ||
for (query_byte, result_byte) in query.as_bytes().iter().zip(result.data.0.iter_mut()) { | ||
*result_byte = *query_byte; | ||
} | ||
|
||
lend_mut( | ||
dns_server(), | ||
DnsLendMut::RawLookup.into(), | ||
&mut result.data.0, | ||
0, | ||
query.as_bytes().len(), | ||
) | ||
.unwrap(); | ||
if result.data.0[0] != 0 { | ||
return Err(DnsError { code: result.data.0[1] }); | ||
} | ||
assert_eq!(result.offset, 0); | ||
result.count = result.data.0[1] as usize; | ||
|
||
// Advance the offset to the first record | ||
result.offset = 2; | ||
Ok(result) | ||
} | ||
|
||
impl TryFrom<&str> for LookupHost { | ||
type Error = io::Error; | ||
|
||
fn try_from(s: &str) -> io::Result<LookupHost> { | ||
macro_rules! try_opt { | ||
($e:expr, $msg:expr) => { | ||
match $e { | ||
Some(r) => r, | ||
None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, &$msg)), | ||
} | ||
}; | ||
} | ||
|
||
// split the string by ':' and convert the second part to u16 | ||
let (host, port_str) = try_opt!(s.rsplit_once(':'), "invalid socket address"); | ||
let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); | ||
(host, port).try_into() | ||
} | ||
} | ||
|
||
impl TryFrom<(&str, u16)> for LookupHost { | ||
type Error = io::Error; | ||
|
||
fn try_from(v: (&str, u16)) -> io::Result<LookupHost> { | ||
lookup(v.0, v.1) | ||
.map_err(|_e| io::const_io_error!(io::ErrorKind::InvalidInput, &"DNS failure")) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
mod dns; | ||
|
||
mod tcpstream; | ||
pub use tcpstream::*; | ||
|
||
mod tcplistener; | ||
pub use tcplistener::*; | ||
|
||
mod udp; | ||
pub use udp::*; | ||
|
||
// this structure needs to be synchronized with what's in net/src/api.rs | ||
#[repr(C)] | ||
#[derive(Debug)] | ||
enum NetError { | ||
// Ok = 0, | ||
Unaddressable = 1, | ||
SocketInUse = 2, | ||
// AccessDenied = 3, | ||
Invalid = 4, | ||
// Finished = 5, | ||
LibraryError = 6, | ||
// AlreadyUsed = 7, | ||
TimedOut = 8, | ||
WouldBlock = 9, | ||
} | ||
|
||
#[repr(C, align(4096))] | ||
struct ConnectRequest { | ||
raw: [u8; 4096], | ||
} | ||
|
||
#[repr(C, align(4096))] | ||
struct SendData { | ||
raw: [u8; 4096], | ||
} | ||
|
||
#[repr(C, align(4096))] | ||
pub struct ReceiveData { | ||
raw: [u8; 4096], | ||
} | ||
|
||
#[repr(C, align(4096))] | ||
pub struct GetAddress { | ||
raw: [u8; 4096], | ||
} | ||
|
||
pub use dns::LookupHost; | ||
|
||
#[allow(nonstandard_style)] | ||
pub mod netc { | ||
pub const AF_INET: u8 = 0; | ||
pub const AF_INET6: u8 = 1; | ||
pub type sa_family_t = u8; | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct in_addr { | ||
pub s_addr: u32, | ||
} | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct sockaddr_in { | ||
pub sin_family: sa_family_t, | ||
pub sin_port: u16, | ||
pub sin_addr: in_addr, | ||
} | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct in6_addr { | ||
pub s6_addr: [u8; 16], | ||
} | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct sockaddr_in6 { | ||
pub sin6_family: sa_family_t, | ||
pub sin6_port: u16, | ||
pub sin6_addr: in6_addr, | ||
pub sin6_flowinfo: u32, | ||
pub sin6_scope_id: u32, | ||
} | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct sockaddr {} | ||
} |
Oops, something went wrong.