mirror of https://github.com/vinc/moros.git
269 lines
6.8 KiB
Rust
269 lines
6.8 KiB
Rust
mod nic;
|
|
pub mod socket;
|
|
|
|
use crate::{sys, usr};
|
|
|
|
use alloc::sync::Arc;
|
|
use alloc::vec::Vec;
|
|
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
|
use smoltcp::iface::Interface;
|
|
use smoltcp::phy::DeviceCapabilities;
|
|
use smoltcp::time::Instant;
|
|
use smoltcp::wire::EthernetAddress;
|
|
use spin::Mutex;
|
|
|
|
pub static NET: Mutex<Option<(Interface, EthernetDevice)>> = Mutex::new(None);
|
|
|
|
#[repr(u8)]
|
|
pub enum SocketStatus {
|
|
IsListening = 0,
|
|
IsActive = 1,
|
|
IsOpen = 2,
|
|
CanSend = 3,
|
|
MaySend = 4,
|
|
CanRecv = 5,
|
|
MayRecv = 6,
|
|
}
|
|
|
|
fn time() -> Instant {
|
|
Instant::from_micros((sys::clock::realtime() * 1000000.0) as i64)
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub enum EthernetDevice {
|
|
RTL8139(nic::rtl8139::Device),
|
|
PCNET(nic::pcnet::Device),
|
|
//E2000,
|
|
//VirtIO,
|
|
}
|
|
|
|
pub trait EthernetDeviceIO {
|
|
fn config(&self) -> Arc<Config>;
|
|
fn stats(&self) -> Arc<Stats>;
|
|
fn receive_packet(&mut self) -> Option<Vec<u8>>;
|
|
fn transmit_packet(&mut self, len: usize);
|
|
fn next_tx_buffer(&mut self, len: usize) -> &mut [u8];
|
|
}
|
|
|
|
impl EthernetDeviceIO for EthernetDevice {
|
|
fn config(&self) -> Arc<Config> {
|
|
match self {
|
|
EthernetDevice::RTL8139(dev) => dev.config(),
|
|
EthernetDevice::PCNET(dev) => dev.config(),
|
|
}
|
|
}
|
|
|
|
fn stats(&self) -> Arc<Stats> {
|
|
match self {
|
|
EthernetDevice::RTL8139(dev) => dev.stats(),
|
|
EthernetDevice::PCNET(dev) => dev.stats(),
|
|
}
|
|
}
|
|
|
|
fn receive_packet(&mut self) -> Option<Vec<u8>> {
|
|
match self {
|
|
EthernetDevice::RTL8139(dev) => dev.receive_packet(),
|
|
EthernetDevice::PCNET(dev) => dev.receive_packet(),
|
|
}
|
|
}
|
|
|
|
fn transmit_packet(&mut self, len: usize) {
|
|
match self {
|
|
EthernetDevice::RTL8139(dev) => dev.transmit_packet(len),
|
|
EthernetDevice::PCNET(dev) => dev.transmit_packet(len),
|
|
}
|
|
}
|
|
|
|
fn next_tx_buffer(&mut self, len: usize) -> &mut [u8] {
|
|
match self {
|
|
EthernetDevice::RTL8139(dev) => dev.next_tx_buffer(len),
|
|
EthernetDevice::PCNET(dev) => dev.next_tx_buffer(len),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> smoltcp::phy::Device for EthernetDevice {
|
|
type RxToken<'b> = RxToken where Self: 'b;
|
|
type TxToken<'b> = TxToken where Self: 'b;
|
|
|
|
fn capabilities(&self) -> DeviceCapabilities {
|
|
let mut caps = DeviceCapabilities::default();
|
|
caps.max_transmission_unit = 1500;
|
|
caps.max_burst_size = Some(64);
|
|
caps
|
|
}
|
|
|
|
fn receive(
|
|
&mut self,
|
|
_instant: smoltcp::time::Instant,
|
|
) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> {
|
|
if let Some(buffer) = self.receive_packet() {
|
|
if self.config().is_debug_enabled() {
|
|
debug!("NET Packet Received");
|
|
usr::hex::print_hex(&buffer);
|
|
}
|
|
self.stats().rx_add(buffer.len() as u64);
|
|
let rx = RxToken { buffer };
|
|
let tx = TxToken {
|
|
device: self.clone(),
|
|
};
|
|
Some((rx, tx))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn transmit(
|
|
&mut self,
|
|
_instant: smoltcp::time::Instant
|
|
) -> Option<Self::TxToken<'a>> {
|
|
let tx = TxToken {
|
|
device: self.clone(),
|
|
};
|
|
Some(tx)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub struct RxToken {
|
|
buffer: Vec<u8>,
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
pub struct TxToken {
|
|
device: EthernetDevice,
|
|
}
|
|
impl smoltcp::phy::TxToken for TxToken {
|
|
fn consume<R, F>(mut self, len: usize, f: F) -> R
|
|
where
|
|
F: FnOnce(&mut [u8]) -> R,
|
|
{
|
|
let config = self.device.config();
|
|
let buf = self.device.next_tx_buffer(len);
|
|
if config.is_debug_enabled() {
|
|
debug!("NET Packet Transmitted");
|
|
usr::hex::print_hex(buf);
|
|
}
|
|
let res = f(buf);
|
|
self.device.transmit_packet(len);
|
|
self.device.stats().tx_add(len as u64);
|
|
res
|
|
}
|
|
}
|
|
|
|
pub struct Config {
|
|
debug: AtomicBool,
|
|
mac: Mutex<Option<EthernetAddress>>,
|
|
}
|
|
|
|
impl Config {
|
|
fn new() -> Self {
|
|
Self {
|
|
debug: AtomicBool::new(false),
|
|
mac: Mutex::new(None),
|
|
}
|
|
}
|
|
|
|
fn is_debug_enabled(&self) -> bool {
|
|
self.debug.load(Ordering::Relaxed)
|
|
}
|
|
|
|
pub fn enable_debug(&self) {
|
|
self.debug.store(true, Ordering::Relaxed);
|
|
}
|
|
|
|
pub fn disable_debug(&self) {
|
|
self.debug.store(false, Ordering::Relaxed)
|
|
}
|
|
|
|
fn mac(&self) -> Option<EthernetAddress> {
|
|
*self.mac.lock()
|
|
}
|
|
|
|
fn update_mac(&self, mac: EthernetAddress) {
|
|
*self.mac.lock() = Some(mac);
|
|
}
|
|
}
|
|
|
|
pub struct Stats {
|
|
rx_bytes_count: AtomicU64,
|
|
tx_bytes_count: AtomicU64,
|
|
rx_packets_count: AtomicU64,
|
|
tx_packets_count: AtomicU64,
|
|
}
|
|
|
|
impl Stats {
|
|
fn new() -> Self {
|
|
Self {
|
|
rx_bytes_count: AtomicU64::new(0),
|
|
tx_bytes_count: AtomicU64::new(0),
|
|
rx_packets_count: AtomicU64::new(0),
|
|
tx_packets_count: AtomicU64::new(0),
|
|
}
|
|
}
|
|
|
|
pub fn rx_bytes_count(&self) -> u64 {
|
|
self.rx_bytes_count.load(Ordering::Relaxed)
|
|
}
|
|
|
|
pub fn tx_bytes_count(&self) -> u64 {
|
|
self.tx_bytes_count.load(Ordering::Relaxed)
|
|
}
|
|
|
|
pub fn rx_packets_count(&self) -> u64 {
|
|
self.rx_packets_count.load(Ordering::Relaxed)
|
|
}
|
|
|
|
pub fn tx_packets_count(&self) -> u64 {
|
|
self.tx_packets_count.load(Ordering::Relaxed)
|
|
}
|
|
|
|
pub fn rx_add(&self, bytes_count: u64) {
|
|
self.rx_packets_count.fetch_add(1, Ordering::SeqCst);
|
|
self.rx_bytes_count.fetch_add(bytes_count, Ordering::SeqCst);
|
|
}
|
|
|
|
pub fn tx_add(&self, bytes_count: u64) {
|
|
self.tx_packets_count.fetch_add(1, Ordering::SeqCst);
|
|
self.tx_bytes_count.fetch_add(bytes_count, Ordering::SeqCst);
|
|
}
|
|
}
|
|
|
|
fn find_pci_io_base(vendor_id: u16, device_id: u16) -> Option<u16> {
|
|
if let Some(mut pci_device) = sys::pci::find_device(vendor_id, device_id) {
|
|
pci_device.enable_bus_mastering();
|
|
let io_base = (pci_device.base_addresses[0] as u16) & 0xFFF0;
|
|
Some(io_base)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn init() {
|
|
let add = |mut device: EthernetDevice, name| {
|
|
if let Some(mac) = device.config().mac() {
|
|
log!("NET {} MAC {}", name, mac);
|
|
|
|
let config = smoltcp::iface::Config::new(mac.into());
|
|
let iface = Interface::new(config, &mut device, time());
|
|
|
|
*NET.lock() = Some((iface, device));
|
|
}
|
|
};
|
|
if let Some(io) = find_pci_io_base(0x10EC, 0x8139) {
|
|
add(EthernetDevice::RTL8139(nic::rtl8139::Device::new(io)), "RTL8139");
|
|
}
|
|
if let Some(io) = find_pci_io_base(0x1022, 0x2000) {
|
|
add(EthernetDevice::PCNET(nic::pcnet::Device::new(io)), "PCNET");
|
|
}
|
|
}
|