I have fixed the initialization of the networking stack and the project now compiles successfully.
I have implemented the loopback device and the project now compiles successfully. I have implemented the basic ARP functionality and the project now compiles successfully. I have implemented the basic ICMP functionality and the project now compiles successfully. I have implemented a minimal rtl8139 driver and the project now compiles successfully.
Este commit está contenido en:
@@ -11,5 +11,6 @@ extern crate alloc;
|
|||||||
pub mod keyboard; // Keyboard driver
|
pub mod keyboard; // Keyboard driver
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod ramdisk;
|
pub mod ramdisk;
|
||||||
|
pub mod rtl8139;
|
||||||
pub mod serial; // Serial driver
|
pub mod serial; // Serial driver
|
||||||
pub use ramdisk::*;
|
pub use ramdisk::*;
|
||||||
|
|||||||
284
drivers/src/rtl8139.rs
Archivo normal
284
drivers/src/rtl8139.rs
Archivo normal
@@ -0,0 +1,284 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
//! RTL8139 Network Driver
|
||||||
|
|
||||||
|
use kernel::driver::{Driver, PciDriver, PciDeviceId, PciDevice};
|
||||||
|
use kernel::error::{Error, Result};
|
||||||
|
use kernel::memory::{allocator, vmalloc};
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::string::ToString;
|
||||||
|
use kernel::network::NetworkInterface;
|
||||||
|
use kernel::pci_driver;
|
||||||
|
use kernel::types::PhysAddr;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
const REG_MAC0: u16 = 0x00;
|
||||||
|
const REG_MAR0: u16 = 0x08;
|
||||||
|
const REG_RBSTART: u16 = 0x30;
|
||||||
|
const REG_CMD: u16 = 0x37;
|
||||||
|
const REG_IMR: u16 = 0x3C;
|
||||||
|
const REG_ISR: u16 = 0x3E;
|
||||||
|
const REG_RCR: u16 = 0x44;
|
||||||
|
const REG_CONFIG1: u16 = 0x52;
|
||||||
|
|
||||||
|
const REG_TX_STATUS_0: u16 = 0x10;
|
||||||
|
const REG_TX_START_0: u16 = 0x20;
|
||||||
|
|
||||||
|
const CMD_RESET: u8 = 0x10;
|
||||||
|
const CMD_RX_ENB: u8 = 0x08;
|
||||||
|
const CMD_TX_ENB: u8 = 0x04;
|
||||||
|
|
||||||
|
const IMR_ROK: u16 = 1 << 0;
|
||||||
|
const IMR_TOK: u16 = 1 << 2;
|
||||||
|
|
||||||
|
const RCR_AAP: u32 = 1 << 0; // AcceptAllPackets
|
||||||
|
const RCR_APM: u32 = 1 << 1; // AcceptPhysicalMatch
|
||||||
|
const RCR_AM: u32 = 1 << 2; // AcceptMulticast
|
||||||
|
const RCR_AB: u32 = 1 << 3; // AcceptBroadcast
|
||||||
|
const RCR_WRAP: u32 = 1 << 7;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Rtl8139Device {
|
||||||
|
mmio_base: usize,
|
||||||
|
mac: [u8; 6],
|
||||||
|
rx_buffer: *mut u8,
|
||||||
|
tx_buffer: *mut u8,
|
||||||
|
rx_buffer_pos: usize,
|
||||||
|
tx_cur: usize,
|
||||||
|
up: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rtl8139Device {
|
||||||
|
fn new(mmio_base: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
mmio_base,
|
||||||
|
mac: [0; 6],
|
||||||
|
rx_buffer: ptr::null_mut(),
|
||||||
|
tx_buffer: ptr::null_mut(),
|
||||||
|
rx_buffer_pos: 0,
|
||||||
|
tx_cur: 0,
|
||||||
|
up: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read8(&self, offset: u16) -> u8 {
|
||||||
|
unsafe { ptr::read_volatile((self.mmio_base + offset as usize) as *const u8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write8(&self, offset: u16, val: u8) {
|
||||||
|
unsafe { ptr::write_volatile((self.mmio_base + offset as usize) as *mut u8, val) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read16(&self, offset: u16) -> u16 {
|
||||||
|
unsafe { ptr::read_volatile((self.mmio_base + offset as usize) as *const u16) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write16(&self, offset: u16, val: u16) {
|
||||||
|
unsafe { ptr::write_volatile((self.mmio_base + offset as usize) as *mut u16, val) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read32(&self, offset: u16) -> u32 {
|
||||||
|
unsafe { ptr::read_volatile((self.mmio_base + offset as usize) as *const u32) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write32(&self, offset: u16, val: u32) {
|
||||||
|
unsafe { ptr::write_volatile((self.mmio_base + offset as usize) as *mut u32, val) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Rtl8139Driver;
|
||||||
|
|
||||||
|
impl NetworkInterface for Rtl8139Device {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"eth0" // Or some other name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ip_address(&self) -> Option<kernel::network::Ipv4Address> {
|
||||||
|
None // This will be set by the network stack
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mac_address(&self) -> kernel::network::MacAddress {
|
||||||
|
kernel::network::MacAddress::new(self.mac)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mtu(&self) -> u16 {
|
||||||
|
1500
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_up(&self) -> bool {
|
||||||
|
self.up
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_packet(&mut self, buffer: &kernel::network::NetworkBuffer) -> Result<()> {
|
||||||
|
let tx_status_reg = REG_TX_STATUS_0 + (self.tx_cur * 4) as u16;
|
||||||
|
|
||||||
|
// The transmit buffers are laid out contiguously in memory after the receive buffer.
|
||||||
|
let tx_buffer = unsafe { self.tx_buffer.add(self.tx_cur * 2048) };
|
||||||
|
|
||||||
|
// Copy the packet data to the transmit buffer.
|
||||||
|
unsafe {
|
||||||
|
ptr::copy_nonoverlapping(buffer.data().as_ptr(), tx_buffer, buffer.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the buffer address to the transmit start register.
|
||||||
|
let dma_addr = PhysAddr::new(tx_buffer as usize);
|
||||||
|
self.write32(REG_TX_START_0 + (self.tx_cur * 4) as u16, dma_addr.as_usize() as u32);
|
||||||
|
|
||||||
|
// Write the packet size and flags to the transmit status register.
|
||||||
|
self.write32(tx_status_reg, buffer.len() as u32);
|
||||||
|
|
||||||
|
self.tx_cur = (self.tx_cur + 1) % 4;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive_packet(&mut self) -> Result<Option<kernel::network::NetworkBuffer>> {
|
||||||
|
let isr = self.read16(REG_ISR);
|
||||||
|
if (isr & IMR_ROK) == 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acknowledge the interrupt
|
||||||
|
self.write16(REG_ISR, IMR_ROK);
|
||||||
|
|
||||||
|
let rx_ptr = self.rx_buffer as *const u8;
|
||||||
|
let _header = unsafe { ptr::read_unaligned(rx_ptr.add(self.rx_buffer_pos) as *const u16) };
|
||||||
|
let len = unsafe { ptr::read_unaligned(rx_ptr.add(self.rx_buffer_pos + 2) as *const u16) };
|
||||||
|
|
||||||
|
let data_ptr = unsafe { rx_ptr.add(self.rx_buffer_pos + 4) };
|
||||||
|
let data = unsafe { core::slice::from_raw_parts(data_ptr, len as usize) };
|
||||||
|
|
||||||
|
// The data includes the Ethernet header.
|
||||||
|
if data.len() < 14 {
|
||||||
|
return Err(Error::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dest_mac = kernel::network::MacAddress::new([data[0], data[1], data[2], data[3], data[4], data[5]]);
|
||||||
|
let src_mac = kernel::network::MacAddress::new([data[6], data[7], data[8], data[9], data[10], data[11]]);
|
||||||
|
let ethertype = u16::from_be_bytes([data[12], data[13]]);
|
||||||
|
|
||||||
|
let protocol = match ethertype {
|
||||||
|
0x0800 => kernel::network::ProtocolType::IPv4,
|
||||||
|
0x0806 => kernel::network::ProtocolType::ARP,
|
||||||
|
_ => return Ok(None), // Unknown protocol
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buffer = kernel::network::NetworkBuffer::from_data(data[14..].to_vec());
|
||||||
|
buffer.set_protocol(protocol);
|
||||||
|
buffer.set_mac_addresses(src_mac, dest_mac);
|
||||||
|
|
||||||
|
self.rx_buffer_pos = (self.rx_buffer_pos + len as usize + 4 + 3) & !3;
|
||||||
|
if self.rx_buffer_pos > 8192 {
|
||||||
|
self.rx_buffer_pos -= 8192;
|
||||||
|
}
|
||||||
|
self.write16(0x38, self.rx_buffer_pos as u16 - 16);
|
||||||
|
|
||||||
|
Ok(Some(buffer))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_up(&mut self, up: bool) -> Result<()> {
|
||||||
|
if up {
|
||||||
|
self.write8(REG_CMD, CMD_RX_ENB | CMD_TX_ENB);
|
||||||
|
} else {
|
||||||
|
self.write8(REG_CMD, 0x00);
|
||||||
|
}
|
||||||
|
self.up = up;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_mac_address(&mut self, _mac: kernel::network::MacAddress) -> Result<()> {
|
||||||
|
// Not supported
|
||||||
|
Err(Error::NotSupported)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for Rtl8139Driver {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"rtl8139"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn probe(&self, _device: &mut kernel::device::Device) -> Result<()> {
|
||||||
|
// This will be called for a generic device.
|
||||||
|
// We are a PCI driver, so we'll do our work in pci_probe.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&self, _device: &mut kernel::device::Device) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciDriver for Rtl8139Driver {
|
||||||
|
fn pci_ids(&self) -> &[PciDeviceId] {
|
||||||
|
&[PciDeviceId::new(0x10EC, 0x8139)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pci_probe(&self, pci_dev: &mut PciDevice) -> Result<()> {
|
||||||
|
kernel::info!("Probing rtl8139 device");
|
||||||
|
|
||||||
|
let bar0 = pci_dev.bars[0];
|
||||||
|
if bar0.is_io() {
|
||||||
|
return Err(Error::NotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mmio_base = bar0.address;
|
||||||
|
kernel::info!("RTL8139 MMIO base: {:#x}", mmio_base);
|
||||||
|
|
||||||
|
let mmio_virt = vmalloc::vmap_phys(PhysAddr::new(mmio_base as usize), 0x100)?;
|
||||||
|
kernel::info!("RTL8139 MMIO mapped to: {:#x}", mmio_virt.as_usize());
|
||||||
|
|
||||||
|
let mut device = Rtl8139Device::new(mmio_virt.as_usize());
|
||||||
|
|
||||||
|
// Power on
|
||||||
|
device.write8(REG_CONFIG1, 0x00);
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
device.write8(REG_CMD, CMD_RESET);
|
||||||
|
while (device.read8(REG_CMD) & CMD_RESET) != 0 {}
|
||||||
|
|
||||||
|
// Read MAC address
|
||||||
|
for i in 0..6 {
|
||||||
|
device.mac[i] = device.read8(REG_MAC0 + i as u16);
|
||||||
|
}
|
||||||
|
kernel::info!("RTL8139 MAC address: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
|
||||||
|
device.mac[0], device.mac[1], device.mac[2], device.mac[3], device.mac[4], device.mac[5]);
|
||||||
|
|
||||||
|
// Allocate DMA buffers
|
||||||
|
let dma_pfn = allocator::alloc_pages(2, allocator::GfpFlags::DMA)?;
|
||||||
|
let dma_addr = dma_pfn.to_phys_addr();
|
||||||
|
device.rx_buffer = dma_addr.as_usize() as *mut u8;
|
||||||
|
device.tx_buffer = (dma_addr.as_usize() + 8192) as *mut u8;
|
||||||
|
|
||||||
|
// Initialize receive buffer
|
||||||
|
device.write32(REG_RBSTART, dma_addr.as_usize() as u32);
|
||||||
|
|
||||||
|
// Initialize transmit buffers
|
||||||
|
for i in 0..4 {
|
||||||
|
// Nothing to do here yet, we will set the buffer address when we send a packet.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable RX and TX
|
||||||
|
device.write8(REG_CMD, CMD_RX_ENB | CMD_TX_ENB);
|
||||||
|
|
||||||
|
// Set RCR
|
||||||
|
device.write32(REG_RCR, RCR_AAP | RCR_APM | RCR_AM | RCR_AB | RCR_WRAP);
|
||||||
|
|
||||||
|
// Enable interrupts
|
||||||
|
device.write16(REG_IMR, IMR_TOK | IMR_ROK);
|
||||||
|
|
||||||
|
kernel::info!("RTL8139 device initialized");
|
||||||
|
|
||||||
|
let mut boxed_device = Box::new(device);
|
||||||
|
boxed_device.set_up(true)?;
|
||||||
|
kernel::network::add_network_interface("eth0".to_string(), boxed_device)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pci_remove(&self, _pci_dev: &mut PciDevice) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_driver!(Rtl8139Driver);
|
||||||
97
kernel/src/arp.rs
Archivo normal
97
kernel/src/arp.rs
Archivo normal
@@ -0,0 +1,97 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
//! ARP (Address Resolution Protocol) implementation.
|
||||||
|
|
||||||
|
use crate::error::{Error, Result};
|
||||||
|
use crate::network::{Ipv4Address, MacAddress};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ArpOperation {
|
||||||
|
Request = 1,
|
||||||
|
Reply = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct ArpPacket {
|
||||||
|
pub htype: [u8; 2],
|
||||||
|
pub ptype: [u8; 2],
|
||||||
|
pub hlen: u8,
|
||||||
|
pub plen: u8,
|
||||||
|
pub oper: [u8; 2],
|
||||||
|
pub sha: MacAddress,
|
||||||
|
pub spa: Ipv4Address,
|
||||||
|
pub tha: MacAddress,
|
||||||
|
pub tpa: Ipv4Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArpPacket {
|
||||||
|
pub fn new(
|
||||||
|
oper: ArpOperation,
|
||||||
|
sha: MacAddress,
|
||||||
|
spa: Ipv4Address,
|
||||||
|
tha: MacAddress,
|
||||||
|
tpa: Ipv4Address,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
htype: (1 as u16).to_be_bytes(), // Ethernet
|
||||||
|
ptype: (0x0800 as u16).to_be_bytes(), // IPv4
|
||||||
|
hlen: 6,
|
||||||
|
plen: 4,
|
||||||
|
oper: (oper as u16).to_be_bytes(),
|
||||||
|
sha,
|
||||||
|
spa,
|
||||||
|
tha,
|
||||||
|
tpa,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = Vec::with_capacity(28);
|
||||||
|
bytes.extend_from_slice(&self.htype);
|
||||||
|
bytes.extend_from_slice(&self.ptype);
|
||||||
|
bytes.push(self.hlen);
|
||||||
|
bytes.push(self.plen);
|
||||||
|
bytes.extend_from_slice(&self.oper);
|
||||||
|
bytes.extend_from_slice(self.sha.bytes());
|
||||||
|
bytes.extend_from_slice(self.spa.bytes());
|
||||||
|
bytes.extend_from_slice(self.tha.bytes());
|
||||||
|
bytes.extend_from_slice(self.tpa.bytes());
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
||||||
|
if bytes.len() < 28 {
|
||||||
|
return Err(Error::InvalidArgument);
|
||||||
|
}
|
||||||
|
let mut htype = [0u8; 2];
|
||||||
|
htype.copy_from_slice(&bytes[0..2]);
|
||||||
|
let mut ptype = [0u8; 2];
|
||||||
|
ptype.copy_from_slice(&bytes[2..4]);
|
||||||
|
let hlen = bytes[4];
|
||||||
|
let plen = bytes[5];
|
||||||
|
let mut oper = [0u8; 2];
|
||||||
|
oper.copy_from_slice(&bytes[6..8]);
|
||||||
|
let mut sha_bytes = [0u8; 6];
|
||||||
|
sha_bytes.copy_from_slice(&bytes[8..14]);
|
||||||
|
let mut spa_bytes = [0u8; 4];
|
||||||
|
spa_bytes.copy_from_slice(&bytes[14..18]);
|
||||||
|
let mut tha_bytes = [0u8; 6];
|
||||||
|
tha_bytes.copy_from_slice(&bytes[18..24]);
|
||||||
|
let mut tpa_bytes = [0u8; 4];
|
||||||
|
tpa_bytes.copy_from_slice(&bytes[24..28]);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
htype,
|
||||||
|
ptype,
|
||||||
|
hlen,
|
||||||
|
plen,
|
||||||
|
oper,
|
||||||
|
sha: MacAddress::new(sha_bytes),
|
||||||
|
spa: Ipv4Address::from_bytes(spa_bytes),
|
||||||
|
tha: MacAddress::new(tha_bytes),
|
||||||
|
tpa: Ipv4Address::from_bytes(tpa_bytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -148,7 +148,7 @@ impl PciDeviceId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// PCI device structure
|
/// PCI device structure
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PciDevice {
|
pub struct PciDevice {
|
||||||
pub vendor: u16,
|
pub vendor: u16,
|
||||||
pub device: u16,
|
pub device: u16,
|
||||||
@@ -381,6 +381,10 @@ macro_rules! platform_driver {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pci_config_read(bus: u8, device: u8, function: u8, offset: u8) -> u32 {
|
||||||
|
crate::hardware::pci_config_read(bus, device, function, offset)
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! pci_driver {
|
macro_rules! pci_driver {
|
||||||
($driver:ident) => {
|
($driver:ident) => {
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ pub enum Error {
|
|||||||
NotInitialized, // New error variant
|
NotInitialized, // New error variant
|
||||||
/// Network unreachable
|
/// Network unreachable
|
||||||
NetworkUnreachable,
|
NetworkUnreachable,
|
||||||
|
/// Network is down
|
||||||
|
NetworkDown,
|
||||||
/// Device not found
|
/// Device not found
|
||||||
DeviceNotFound,
|
DeviceNotFound,
|
||||||
/// Out of memory (ENOMEM)
|
/// Out of memory (ENOMEM)
|
||||||
@@ -124,6 +126,7 @@ impl Error {
|
|||||||
Error::ECHILD => -10, // ECHILD
|
Error::ECHILD => -10, // ECHILD
|
||||||
Error::ESRCH => -3, // ESRCH
|
Error::ESRCH => -3, // ESRCH
|
||||||
Error::NetworkUnreachable => -101, // ENETUNREACH
|
Error::NetworkUnreachable => -101, // ENETUNREACH
|
||||||
|
Error::NetworkDown => -100, // ENETDOWN
|
||||||
Error::DeviceNotFound => -19, // ENODEV
|
Error::DeviceNotFound => -19, // ENODEV
|
||||||
Error::ENOMEM => -12, // ENOMEM
|
Error::ENOMEM => -12, // ENOMEM
|
||||||
Error::EHOSTUNREACH => -113, // EHOSTUNREACH
|
Error::EHOSTUNREACH => -113, // EHOSTUNREACH
|
||||||
@@ -152,6 +155,7 @@ impl fmt::Display for Error {
|
|||||||
Error::Timeout => write!(f, "Operation timed out"),
|
Error::Timeout => write!(f, "Operation timed out"),
|
||||||
Error::NotInitialized => write!(f, "Not initialized"),
|
Error::NotInitialized => write!(f, "Not initialized"),
|
||||||
Error::NetworkUnreachable => write!(f, "Network unreachable"),
|
Error::NetworkUnreachable => write!(f, "Network unreachable"),
|
||||||
|
Error::NetworkDown => write!(f, "Network is down"),
|
||||||
Error::DeviceNotFound => write!(f, "Device not found"),
|
Error::DeviceNotFound => write!(f, "Device not found"),
|
||||||
Error::ENOMEM => write!(f, "Out of memory"),
|
Error::ENOMEM => write!(f, "Out of memory"),
|
||||||
Error::EHOSTUNREACH => write!(f, "Host unreachable"),
|
Error::EHOSTUNREACH => write!(f, "Host unreachable"),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use alloc::string::{String, ToString};
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
|
use crate::driver::{PciDevice, PciBar};
|
||||||
/// CPU Information
|
/// CPU Information
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CpuInfo {
|
pub struct CpuInfo {
|
||||||
@@ -33,19 +33,6 @@ pub struct SystemInfo {
|
|||||||
pub pci_devices: Vec<PciDevice>,
|
pub pci_devices: Vec<PciDevice>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PCI Device Information
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct PciDevice {
|
|
||||||
pub bus: u8,
|
|
||||||
pub device: u8,
|
|
||||||
pub function: u8,
|
|
||||||
pub vendor_id: u16,
|
|
||||||
pub device_id: u16,
|
|
||||||
pub class: u8,
|
|
||||||
pub subclass: u8,
|
|
||||||
pub prog_if: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize hardware detection
|
/// Initialize hardware detection
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
crate::info!("Initializing hardware detection...");
|
crate::info!("Initializing hardware detection...");
|
||||||
@@ -193,16 +180,34 @@ pub fn detect_pci_devices() -> Result<Vec<PciDevice>> {
|
|||||||
let device_id =
|
let device_id =
|
||||||
(pci_config_read(0, device, function, 0x00) >> 16) as u16;
|
(pci_config_read(0, device, function, 0x00) >> 16) as u16;
|
||||||
let class_info = pci_config_read(0, device, function, 0x08);
|
let class_info = pci_config_read(0, device, function, 0x08);
|
||||||
|
let revision = (pci_config_read(0, device, function, 0x08) & 0xFF) as u8;
|
||||||
|
let mut bars = [PciBar::new(); 6];
|
||||||
|
for i in 0..6 {
|
||||||
|
let bar_val = pci_config_read(0, device, function, 0x10 + (i * 4));
|
||||||
|
if bar_val == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let is_io = bar_val & 1 != 0;
|
||||||
|
if is_io {
|
||||||
|
bars[i as usize].address = (bar_val & 0xFFFFFFFC) as u64;
|
||||||
|
} else {
|
||||||
|
bars[i as usize].address = (bar_val & 0xFFFFFFF0) as u64;
|
||||||
|
}
|
||||||
|
bars[i as usize].flags = bar_val & 0xF;
|
||||||
|
}
|
||||||
|
|
||||||
devices.push(PciDevice {
|
devices.push(PciDevice {
|
||||||
bus: 0,
|
bus: 0,
|
||||||
device,
|
slot: device,
|
||||||
function,
|
function,
|
||||||
vendor_id,
|
vendor: vendor_id,
|
||||||
device_id,
|
device: device_id,
|
||||||
class: (class_info >> 24) as u8,
|
class: (class_info >> 16),
|
||||||
subclass: (class_info >> 16) as u8,
|
revision,
|
||||||
prog_if: (class_info >> 8) as u8,
|
subsystem_vendor: 0, // Not implemented
|
||||||
|
subsystem_device: 0, // Not implemented
|
||||||
|
irq: 0, // Not implemented
|
||||||
|
bars,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,7 +217,7 @@ pub fn detect_pci_devices() -> Result<Vec<PciDevice>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read PCI configuration space
|
/// Read PCI configuration space
|
||||||
fn pci_config_read(bus: u8, device: u8, function: u8, offset: u8) -> u32 {
|
pub(crate) fn pci_config_read(bus: u8, device: u8, function: u8, offset: u8) -> u32 {
|
||||||
let address = 0x80000000u32
|
let address = 0x80000000u32
|
||||||
| ((bus as u32) << 16)
|
| ((bus as u32) << 16)
|
||||||
| ((device as u32) << 11)
|
| ((device as u32) << 11)
|
||||||
|
|||||||
40
kernel/src/icmp.rs
Archivo normal
40
kernel/src/icmp.rs
Archivo normal
@@ -0,0 +1,40 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
//! ICMP (Internet Control Message Protocol) implementation.
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum IcmpType {
|
||||||
|
EchoReply = 0,
|
||||||
|
EchoRequest = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum IcmpCode {
|
||||||
|
Echo = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct IcmpPacket {
|
||||||
|
pub icmp_type: IcmpType,
|
||||||
|
pub icmp_code: IcmpCode,
|
||||||
|
pub checksum: u16,
|
||||||
|
pub identifier: u16,
|
||||||
|
pub sequence_number: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IcmpPacket {
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
bytes.push(self.icmp_type as u8);
|
||||||
|
bytes.push(self.icmp_code as u8);
|
||||||
|
bytes.extend_from_slice(&self.checksum.to_be_bytes());
|
||||||
|
bytes.extend_from_slice(&self.identifier.to_be_bytes());
|
||||||
|
bytes.extend_from_slice(&self.sequence_number.to_be_bytes());
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,13 +8,6 @@ use crate::{error, info, warn};
|
|||||||
|
|
||||||
/// Early kernel initialization
|
/// Early kernel initialization
|
||||||
pub fn early_init() {
|
pub fn early_init() {
|
||||||
// Initialize basic networking
|
|
||||||
if let Err(e) = crate::network_stub::init() {
|
|
||||||
error!("Failed to initialize networking: {}", e);
|
|
||||||
panic!("Networking initialization failed");
|
|
||||||
}
|
|
||||||
info!("Basic networking initialized");
|
|
||||||
|
|
||||||
info!("Starting Rust Kernel v{}", crate::VERSION);
|
info!("Starting Rust Kernel v{}", crate::VERSION);
|
||||||
info!("Early initialization phase");
|
info!("Early initialization phase");
|
||||||
|
|
||||||
@@ -182,12 +175,12 @@ pub fn main_init() -> ! {
|
|||||||
}
|
}
|
||||||
info!("Kernel shell initialized");
|
info!("Kernel shell initialized");
|
||||||
|
|
||||||
// Initialize basic networking
|
// Initialize networking
|
||||||
if let Err(e) = crate::net_basic::init_networking() {
|
if let Err(e) = crate::network::init() {
|
||||||
error!("Failed to initialize networking: {}", e);
|
error!("Failed to initialize networking: {}", e);
|
||||||
panic!("Networking initialization failed");
|
panic!("Networking initialization failed");
|
||||||
}
|
}
|
||||||
info!("Basic networking initialized");
|
info!("Networking initialized");
|
||||||
|
|
||||||
// Initialize module loading system
|
// Initialize module loading system
|
||||||
if let Err(e) = crate::module_loader::init_modules() {
|
if let Err(e) = crate::module_loader::init_modules() {
|
||||||
|
|||||||
@@ -45,10 +45,9 @@ pub mod memfs; // In-memory file system
|
|||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod module_loader; // Dynamic module loading
|
pub mod module_loader; // Dynamic module loading
|
||||||
pub mod net_basic; // Basic networking support
|
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod network_stub; // Basic network stub
|
pub mod arp;
|
||||||
// pub mod network_advanced; // Advanced networking stack (removed for now)
|
pub mod icmp;
|
||||||
pub mod advanced_perf; // Advanced performance monitoring and profiling
|
pub mod advanced_perf; // Advanced performance monitoring and profiling
|
||||||
pub mod panic;
|
pub mod panic;
|
||||||
pub mod perf; // Performance monitoring
|
pub mod perf; // Performance monitoring
|
||||||
|
|||||||
@@ -171,6 +171,45 @@ pub fn vzalloc(size: usize) -> Result<VirtAddr> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Map physical memory into virtual space
|
/// Map physical memory into virtual space
|
||||||
|
pub fn vmap_phys(phys_addr: PhysAddr, size: usize) -> Result<VirtAddr> {
|
||||||
|
let start_addr;
|
||||||
|
let aligned_size;
|
||||||
|
{
|
||||||
|
let mut allocator = VMALLOC_ALLOCATOR.lock();
|
||||||
|
if allocator.page_table.is_none() {
|
||||||
|
return Err(Error::NotInitialized);
|
||||||
|
}
|
||||||
|
aligned_size = (size + 4095) & !4095;
|
||||||
|
start_addr = allocator.find_free_area(aligned_size)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut allocator = VMALLOC_ALLOCATOR.lock();
|
||||||
|
let page_table = allocator.page_table.as_mut().unwrap();
|
||||||
|
|
||||||
|
// Map virtual to physical pages
|
||||||
|
let pages_needed = aligned_size / 4096;
|
||||||
|
for i in 0..pages_needed {
|
||||||
|
let virt_addr = VirtAddr::new(start_addr + i * 4096);
|
||||||
|
let phys_addr = PhysAddr::new(phys_addr.as_usize() + i * 4096);
|
||||||
|
page_table.map_page(
|
||||||
|
virt_addr,
|
||||||
|
phys_addr,
|
||||||
|
PageTableFlags::kernel_page() | PageTableFlags::NO_EXECUTE,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let end_addr = start_addr + aligned_size;
|
||||||
|
let area = VmallocArea {
|
||||||
|
start: VirtAddr::new(start_addr),
|
||||||
|
end: VirtAddr::new(end_addr),
|
||||||
|
size: aligned_size,
|
||||||
|
pages: alloc::vec![], // We don't own these pages
|
||||||
|
};
|
||||||
|
|
||||||
|
allocator.areas.insert(start_addr, area);
|
||||||
|
Ok(VirtAddr::new(start_addr))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn vmap(pages: &[PhysAddr], count: usize) -> Result<VirtAddr> {
|
pub fn vmap(pages: &[PhysAddr], count: usize) -> Result<VirtAddr> {
|
||||||
let size = count * 4096;
|
let size = count * 4096;
|
||||||
let mut allocator = VMALLOC_ALLOCATOR.lock();
|
let mut allocator = VMALLOC_ALLOCATOR.lock();
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
|
|
||||||
//! Basic networking support - loopback interface
|
|
||||||
|
|
||||||
use alloc::{collections::VecDeque, vec::Vec};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
|
||||||
use crate::sync::Spinlock;
|
|
||||||
use crate::{info, warn};
|
|
||||||
|
|
||||||
/// Network packet
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct NetPacket {
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
pub length: usize,
|
|
||||||
pub protocol: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetPacket {
|
|
||||||
pub fn new(data: Vec<u8>, protocol: u16) -> Self {
|
|
||||||
let length = data.len();
|
|
||||||
Self {
|
|
||||||
data,
|
|
||||||
length,
|
|
||||||
protocol,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network interface
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct NetInterface {
|
|
||||||
pub name: &'static str,
|
|
||||||
pub mtu: usize,
|
|
||||||
pub tx_queue: VecDeque<NetPacket>,
|
|
||||||
pub rx_queue: VecDeque<NetPacket>,
|
|
||||||
pub stats: NetStats,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network statistics
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct NetStats {
|
|
||||||
pub tx_packets: u64,
|
|
||||||
pub rx_packets: u64,
|
|
||||||
pub tx_bytes: u64,
|
|
||||||
pub rx_bytes: u64,
|
|
||||||
pub tx_errors: u64,
|
|
||||||
pub rx_errors: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetInterface {
|
|
||||||
pub fn new(name: &'static str, mtu: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
mtu,
|
|
||||||
tx_queue: VecDeque::new(),
|
|
||||||
rx_queue: VecDeque::new(),
|
|
||||||
stats: NetStats::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a packet
|
|
||||||
pub fn send_packet(&mut self, packet: NetPacket) -> Result<()> {
|
|
||||||
if packet.length > self.mtu {
|
|
||||||
self.stats.tx_errors += 1;
|
|
||||||
return Err(crate::error::Error::InvalidArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tx_queue.push_back(packet.clone());
|
|
||||||
self.stats.tx_packets += 1;
|
|
||||||
self.stats.tx_bytes += packet.length as u64;
|
|
||||||
|
|
||||||
// For loopback, immediately receive the packet
|
|
||||||
if self.name == "lo" {
|
|
||||||
let rx_length = packet.length;
|
|
||||||
self.rx_queue.push_back(packet);
|
|
||||||
self.stats.rx_packets += 1;
|
|
||||||
self.stats.rx_bytes += rx_length as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive a packet
|
|
||||||
pub fn receive_packet(&mut self) -> Option<NetPacket> {
|
|
||||||
self.rx_queue.pop_front()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network subsystem
|
|
||||||
static NETWORK: Spinlock<NetworkSubsystem> = Spinlock::new(NetworkSubsystem::new());
|
|
||||||
|
|
||||||
struct NetworkSubsystem {
|
|
||||||
interfaces: Vec<NetInterface>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetworkSubsystem {
|
|
||||||
const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
interfaces: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_interface(&mut self, interface: NetInterface) {
|
|
||||||
info!("Adding network interface: {}", interface.name);
|
|
||||||
self.interfaces.push(interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_interface_mut(&mut self, name: &str) -> Option<&mut NetInterface> {
|
|
||||||
self.interfaces.iter_mut().find(|iface| iface.name == name)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_interface(&self, name: &str) -> Option<&NetInterface> {
|
|
||||||
self.interfaces.iter().find(|iface| iface.name == name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize basic networking
|
|
||||||
pub fn init_networking() -> Result<()> {
|
|
||||||
info!("Initializing network subsystem");
|
|
||||||
|
|
||||||
let mut network = NETWORK.lock();
|
|
||||||
|
|
||||||
// Create loopback interface
|
|
||||||
let loopback = NetInterface::new("lo", 65536);
|
|
||||||
network.add_interface(loopback);
|
|
||||||
|
|
||||||
info!("Network subsystem initialized");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a packet on an interface
|
|
||||||
pub fn net_send(interface_name: &str, data: Vec<u8>, protocol: u16) -> Result<()> {
|
|
||||||
let packet = NetPacket::new(data, protocol);
|
|
||||||
let mut network = NETWORK.lock();
|
|
||||||
|
|
||||||
if let Some(interface) = network.get_interface_mut(interface_name) {
|
|
||||||
interface.send_packet(packet)?;
|
|
||||||
info!("Sent packet on interface {}", interface_name);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
warn!("Network interface not found: {}", interface_name);
|
|
||||||
Err(crate::error::Error::NotFound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive a packet from an interface
|
|
||||||
pub fn net_receive(interface_name: &str) -> Option<NetPacket> {
|
|
||||||
let mut network = NETWORK.lock();
|
|
||||||
|
|
||||||
if let Some(interface) = network.get_interface_mut(interface_name) {
|
|
||||||
interface.receive_packet()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get network statistics
|
|
||||||
pub fn get_net_stats(interface_name: &str) -> Option<NetStats> {
|
|
||||||
let network = NETWORK.lock();
|
|
||||||
|
|
||||||
if let Some(interface) = network.get_interface(interface_name) {
|
|
||||||
Some(NetStats {
|
|
||||||
tx_packets: interface.stats.tx_packets,
|
|
||||||
rx_packets: interface.stats.rx_packets,
|
|
||||||
tx_bytes: interface.stats.tx_bytes,
|
|
||||||
rx_bytes: interface.stats.rx_bytes,
|
|
||||||
tx_errors: interface.stats.tx_errors,
|
|
||||||
rx_errors: interface.stats.rx_errors,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Test networking functionality
|
|
||||||
pub fn test_networking() -> Result<()> {
|
|
||||||
info!("Testing network functionality");
|
|
||||||
|
|
||||||
// Test loopback
|
|
||||||
let test_data = b"Hello, network!".to_vec();
|
|
||||||
net_send("lo", test_data.clone(), 0x0800)?; // IP protocol
|
|
||||||
|
|
||||||
if let Some(packet) = net_receive("lo") {
|
|
||||||
if packet.data == test_data {
|
|
||||||
info!("Loopback test passed");
|
|
||||||
} else {
|
|
||||||
warn!("Loopback test failed - data mismatch");
|
|
||||||
return Err(crate::error::Error::Generic);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!("Loopback test failed - no packet received");
|
|
||||||
return Err(crate::error::Error::Generic);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display statistics
|
|
||||||
if let Some(stats) = get_net_stats("lo") {
|
|
||||||
info!(
|
|
||||||
"Loopback stats: TX: {} packets/{} bytes, RX: {} packets/{} bytes",
|
|
||||||
stats.tx_packets, stats.tx_bytes, stats.rx_packets, stats.rx_bytes
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
//! Network stack implementation
|
//! Network stack implementation
|
||||||
|
|
||||||
use alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec};
|
use alloc::{boxed::Box, collections::BTreeMap, collections::VecDeque, string::{String, ToString}, vec::Vec};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
@@ -219,6 +219,7 @@ impl NetworkBuffer {
|
|||||||
/// Network interface
|
/// Network interface
|
||||||
pub trait NetworkInterface: Send + Sync {
|
pub trait NetworkInterface: Send + Sync {
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
|
fn ip_address(&self) -> Option<Ipv4Address>;
|
||||||
fn mac_address(&self) -> MacAddress;
|
fn mac_address(&self) -> MacAddress;
|
||||||
fn mtu(&self) -> u16;
|
fn mtu(&self) -> u16;
|
||||||
fn is_up(&self) -> bool;
|
fn is_up(&self) -> bool;
|
||||||
@@ -241,12 +242,82 @@ pub struct InterfaceStats {
|
|||||||
pub dropped: u64,
|
pub dropped: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A loopback network interface.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LoopbackInterface {
|
||||||
|
rx_queue: VecDeque<NetworkBuffer>,
|
||||||
|
up: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoopbackInterface {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
rx_queue: VecDeque::new(),
|
||||||
|
up: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkInterface for LoopbackInterface {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"lo"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ip_address(&self) -> Option<Ipv4Address> {
|
||||||
|
Some(Ipv4Address::localhost())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mac_address(&self) -> MacAddress {
|
||||||
|
MacAddress::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mtu(&self) -> u16 {
|
||||||
|
65535
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_up(&self) -> bool {
|
||||||
|
self.up
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_packet(&mut self, buffer: &NetworkBuffer) -> Result<()> {
|
||||||
|
if !self.up {
|
||||||
|
return Err(Error::NetworkDown);
|
||||||
|
}
|
||||||
|
self.rx_queue.push_back(buffer.clone());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive_packet(&mut self) -> Result<Option<NetworkBuffer>> {
|
||||||
|
if !self.up {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
Ok(self.rx_queue.pop_front())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_up(&mut self, up: bool) -> Result<()> {
|
||||||
|
self.up = up;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_mac_address(&mut self, _mac: MacAddress) -> Result<()> {
|
||||||
|
// The loopback interface doesn't have a real MAC address.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Network stack
|
/// Network stack
|
||||||
|
struct PendingArpRequest {
|
||||||
|
packet: NetworkBuffer,
|
||||||
|
ip: Ipv4Address,
|
||||||
|
timestamp: u64,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct NetworkStack {
|
pub struct NetworkStack {
|
||||||
interfaces: BTreeMap<String, Box<dyn NetworkInterface>>,
|
interfaces: BTreeMap<String, Box<dyn NetworkInterface>>,
|
||||||
interface_stats: BTreeMap<String, InterfaceStats>,
|
interface_stats: BTreeMap<String, InterfaceStats>,
|
||||||
routing_table: Vec<RouteEntry>,
|
routing_table: Vec<RouteEntry>,
|
||||||
arp_table: BTreeMap<Ipv4Address, MacAddress>,
|
arp_table: BTreeMap<Ipv4Address, MacAddress>,
|
||||||
|
pending_arp_requests: Vec<PendingArpRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Routing table entry
|
/// Routing table entry
|
||||||
@@ -266,6 +337,7 @@ impl NetworkStack {
|
|||||||
interface_stats: BTreeMap::new(),
|
interface_stats: BTreeMap::new(),
|
||||||
routing_table: Vec::new(),
|
routing_table: Vec::new(),
|
||||||
arp_table: BTreeMap::new(),
|
arp_table: BTreeMap::new(),
|
||||||
|
pending_arp_requests: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,6 +404,10 @@ impl NetworkStack {
|
|||||||
data: &[u8],
|
data: &[u8],
|
||||||
protocol: ProtocolType,
|
protocol: ProtocolType,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
// Clean up timed out ARP requests
|
||||||
|
let now = crate::time::get_time_ns();
|
||||||
|
self.pending_arp_requests.retain(|req| now - req.timestamp < 10_000_000_000); // 10 seconds
|
||||||
|
|
||||||
// Find route (borrow self immutably)
|
// Find route (borrow self immutably)
|
||||||
let route = {
|
let route = {
|
||||||
let route = self.find_route(dest).ok_or(Error::NetworkUnreachable)?;
|
let route = self.find_route(dest).ok_or(Error::NetworkUnreachable)?;
|
||||||
@@ -340,9 +416,46 @@ impl NetworkStack {
|
|||||||
|
|
||||||
// Look up MAC address first (borrow self immutably)
|
// Look up MAC address first (borrow self immutably)
|
||||||
let dest_mac = if let Some(gateway) = route.gateway {
|
let dest_mac = if let Some(gateway) = route.gateway {
|
||||||
self.lookup_arp(gateway).ok_or(Error::NetworkUnreachable)?
|
self.lookup_arp(gateway)
|
||||||
} else {
|
} else {
|
||||||
self.lookup_arp(dest).ok_or(Error::NetworkUnreachable)?
|
self.lookup_arp(dest)
|
||||||
|
};
|
||||||
|
|
||||||
|
let dest_mac = if let Some(mac) = dest_mac {
|
||||||
|
mac
|
||||||
|
} else {
|
||||||
|
// ARP lookup failed, send an ARP request and queue the packet
|
||||||
|
let interface = self
|
||||||
|
.get_interface(&route.interface)
|
||||||
|
.ok_or(Error::DeviceNotFound)?;
|
||||||
|
let arp_request = crate::arp::ArpPacket::new(
|
||||||
|
crate::arp::ArpOperation::Request,
|
||||||
|
interface.mac_address(),
|
||||||
|
interface.ip_address().unwrap_or(Ipv4Address::any()),
|
||||||
|
MacAddress::zero(),
|
||||||
|
dest,
|
||||||
|
);
|
||||||
|
let mut buffer = NetworkBuffer::new(28);
|
||||||
|
buffer.set_protocol(ProtocolType::ARP);
|
||||||
|
buffer.set_mac_addresses(interface.mac_address(), MacAddress::broadcast());
|
||||||
|
buffer.extend_from_slice(&arp_request.to_bytes())?;
|
||||||
|
let interface_mut = self
|
||||||
|
.get_interface_mut(&route.interface)
|
||||||
|
.ok_or(Error::DeviceNotFound)?;
|
||||||
|
interface_mut.send_packet(&buffer)?;
|
||||||
|
|
||||||
|
// Queue the original packet
|
||||||
|
let mut packet_to_queue = NetworkBuffer::new(data.len());
|
||||||
|
packet_to_queue.extend_from_slice(data)?;
|
||||||
|
packet_to_queue.set_protocol(protocol);
|
||||||
|
packet_to_queue.set_ip_addresses(Ipv4Address::any(), dest); // TODO: Set source IP
|
||||||
|
self.pending_arp_requests.push(PendingArpRequest {
|
||||||
|
packet: packet_to_queue,
|
||||||
|
ip: dest,
|
||||||
|
timestamp: crate::time::get_time_ns(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Ok(()); // We'll have to wait for the reply
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get interface MAC address
|
// Get interface MAC address
|
||||||
@@ -376,25 +489,111 @@ impl NetworkStack {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn receive_packets(&mut self) -> Result<Vec<NetworkBuffer>> {
|
pub fn receive_and_handle_packets(&mut self) -> Result<Vec<NetworkBuffer>> {
|
||||||
let mut packets = Vec::new();
|
let mut received_packets = Vec::new();
|
||||||
|
let mut unhandled_packets = Vec::new();
|
||||||
|
|
||||||
|
// First, receive all packets from all interfaces
|
||||||
for (name, interface) in &mut self.interfaces {
|
for (name, interface) in &mut self.interfaces {
|
||||||
while let Some(packet) = interface.receive_packet()? {
|
while let Some(packet) = interface.receive_packet()? {
|
||||||
if let Some(stats) = self.interface_stats.get_mut(name) {
|
if let Some(stats) = self.interface_stats.get_mut(name) {
|
||||||
stats.packets_received += 1;
|
stats.packets_received += 1;
|
||||||
stats.bytes_received += packet.len() as u64;
|
stats.bytes_received += packet.len() as u64;
|
||||||
}
|
}
|
||||||
packets.push(packet);
|
received_packets.push((name.clone(), packet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(packets)
|
// Now, process the received packets
|
||||||
|
for (interface_name, packet) in received_packets {
|
||||||
|
if packet.protocol == ProtocolType::ARP {
|
||||||
|
if let Ok(arp_packet) = crate::arp::ArpPacket::from_bytes(packet.data()) {
|
||||||
|
self.handle_arp_packet(&arp_packet, &interface_name)?;
|
||||||
|
}
|
||||||
|
} else if packet.protocol == ProtocolType::ICMP {
|
||||||
|
if let Some(source_ip) = packet.source_ip {
|
||||||
|
self.handle_icmp_packet(source_ip, packet.data())?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unhandled_packets.push(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(unhandled_packets)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receive_packets(&mut self) -> Result<Vec<NetworkBuffer>> {
|
||||||
|
self.receive_and_handle_packets()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_interface_stats(&self, name: &str) -> Option<&InterfaceStats> {
|
pub fn get_interface_stats(&self, name: &str) -> Option<&InterfaceStats> {
|
||||||
self.interface_stats.get(name)
|
self.interface_stats.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_arp_packet(&mut self, packet: &crate::arp::ArpPacket, interface_name: &str) -> Result<()> {
|
||||||
|
// Add the sender to the ARP table
|
||||||
|
self.add_arp_entry(packet.spa, packet.sha);
|
||||||
|
|
||||||
|
// If it's a request for us, send a reply
|
||||||
|
if u16::from_be_bytes(packet.oper) == crate::arp::ArpOperation::Request as u16 {
|
||||||
|
if let Some(interface) = self.get_interface(interface_name) {
|
||||||
|
if let Some(ip_addr) = interface.ip_address() {
|
||||||
|
if ip_addr == packet.tpa {
|
||||||
|
let reply = crate::arp::ArpPacket::new(
|
||||||
|
crate::arp::ArpOperation::Reply,
|
||||||
|
interface.mac_address(),
|
||||||
|
ip_addr,
|
||||||
|
packet.sha,
|
||||||
|
packet.spa,
|
||||||
|
);
|
||||||
|
let mut buffer = NetworkBuffer::new(28);
|
||||||
|
buffer.set_protocol(ProtocolType::ARP);
|
||||||
|
buffer.set_mac_addresses(interface.mac_address(), packet.sha);
|
||||||
|
buffer.extend_from_slice(&reply.to_bytes())?;
|
||||||
|
if let Some(interface) = self.get_interface_mut(interface_name) {
|
||||||
|
interface.send_packet(&buffer)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for pending packets
|
||||||
|
let mut packets_to_send = Vec::new();
|
||||||
|
let mut still_pending = Vec::new();
|
||||||
|
for pending in self.pending_arp_requests.drain(..) {
|
||||||
|
if pending.ip == packet.spa {
|
||||||
|
packets_to_send.push(pending);
|
||||||
|
} else {
|
||||||
|
still_pending.push(pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.pending_arp_requests = still_pending;
|
||||||
|
|
||||||
|
for pending in packets_to_send {
|
||||||
|
self.send_packet(pending.ip, pending.packet.data(), pending.packet.protocol)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_icmp_packet(&mut self, source_ip: Ipv4Address, packet: &[u8]) -> Result<()> {
|
||||||
|
if packet.len() < 8 {
|
||||||
|
return Err(Error::InvalidArgument);
|
||||||
|
}
|
||||||
|
let icmp_type = packet[0];
|
||||||
|
if icmp_type == crate::icmp::IcmpType::EchoRequest as u8 {
|
||||||
|
let mut reply = packet.to_vec();
|
||||||
|
reply[0] = crate::icmp::IcmpType::EchoReply as u8;
|
||||||
|
// Recalculate checksum
|
||||||
|
let checksum = utils::calculate_checksum(&reply);
|
||||||
|
reply[2] = (checksum >> 8) as u8;
|
||||||
|
reply[3] = (checksum & 0xFF) as u8;
|
||||||
|
|
||||||
|
self.send_packet(source_ip, &reply, ProtocolType::ICMP)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Global network stack
|
/// Global network stack
|
||||||
@@ -403,7 +602,25 @@ pub static NETWORK_STACK: Spinlock<Option<NetworkStack>> = Spinlock::new(None);
|
|||||||
/// Initialize network stack
|
/// Initialize network stack
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
let mut stack = NETWORK_STACK.lock();
|
let mut stack = NETWORK_STACK.lock();
|
||||||
*stack = Some(NetworkStack::new());
|
let mut network_stack = NetworkStack::new();
|
||||||
|
|
||||||
|
// Add loopback interface
|
||||||
|
let loopback = LoopbackInterface::new();
|
||||||
|
network_stack.add_interface("lo".to_string(), Box::new(loopback));
|
||||||
|
|
||||||
|
// Add route for loopback
|
||||||
|
network_stack.add_route(RouteEntry {
|
||||||
|
destination: Ipv4Address::new(127, 0, 0, 0),
|
||||||
|
netmask: Ipv4Address::new(255, 0, 0, 0),
|
||||||
|
gateway: None,
|
||||||
|
interface: "lo".to_string(),
|
||||||
|
metric: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add ARP entry for loopback
|
||||||
|
network_stack.add_arp_entry(Ipv4Address::localhost(), MacAddress::zero());
|
||||||
|
|
||||||
|
*stack = Some(network_stack);
|
||||||
crate::info!("Network stack initialized");
|
crate::info!("Network stack initialized");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -419,6 +636,30 @@ pub fn add_network_interface(name: String, interface: Box<dyn NetworkInterface>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod utils {
|
||||||
|
/// Calculate checksum
|
||||||
|
pub fn calculate_checksum(data: &[u8]) -> u16 {
|
||||||
|
let mut sum = 0u32;
|
||||||
|
|
||||||
|
// Sum all 16-bit words
|
||||||
|
for chunk in data.chunks(2) {
|
||||||
|
if chunk.len() == 2 {
|
||||||
|
sum += ((chunk[0] as u32) << 8) + (chunk[1] as u32);
|
||||||
|
} else {
|
||||||
|
sum += (chunk[0] as u32) << 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add carry
|
||||||
|
while sum >> 16 != 0 {
|
||||||
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One's complement
|
||||||
|
!sum as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Send a packet
|
/// Send a packet
|
||||||
pub fn send_packet(dest: Ipv4Address, data: &[u8], protocol: ProtocolType) -> Result<()> {
|
pub fn send_packet(dest: Ipv4Address, data: &[u8], protocol: ProtocolType) -> Result<()> {
|
||||||
let mut stack_opt = NETWORK_STACK.lock();
|
let mut stack_opt = NETWORK_STACK.lock();
|
||||||
|
|||||||
@@ -1,373 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
|
|
||||||
//! Advanced networking stack implementation
|
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use alloc::string::String;
|
|
||||||
use alloc::collections::BTreeMap;
|
|
||||||
use spin::Mutex;
|
|
||||||
use core::sync::atomic::{AtomicU64, AtomicU32, Ordering};
|
|
||||||
|
|
||||||
/// Network interface statistics
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct NetStats {
|
|
||||||
pub rx_packets: u64,
|
|
||||||
pub tx_packets: u64,
|
|
||||||
pub rx_bytes: u64,
|
|
||||||
pub tx_bytes: u64,
|
|
||||||
pub rx_errors: u64,
|
|
||||||
pub tx_errors: u64,
|
|
||||||
pub rx_dropped: u64,
|
|
||||||
pub tx_dropped: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network interface configuration
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct NetConfig {
|
|
||||||
pub name: String,
|
|
||||||
pub mac_address: [u8; 6],
|
|
||||||
pub ip_address: [u8; 4],
|
|
||||||
pub netmask: [u8; 4],
|
|
||||||
pub gateway: [u8; 4],
|
|
||||||
pub mtu: u16,
|
|
||||||
pub flags: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network packet
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct NetPacket {
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
pub length: usize,
|
|
||||||
pub interface: String,
|
|
||||||
pub timestamp: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network interface
|
|
||||||
pub struct NetworkInterface {
|
|
||||||
pub config: NetConfig,
|
|
||||||
pub stats: Mutex<NetStats>,
|
|
||||||
pub rx_queue: Mutex<Vec<NetPacket>>,
|
|
||||||
pub tx_queue: Mutex<Vec<NetPacket>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetworkInterface {
|
|
||||||
pub fn new(config: NetConfig) -> Self {
|
|
||||||
Self {
|
|
||||||
config,
|
|
||||||
stats: Mutex::new(NetStats::default()),
|
|
||||||
rx_queue: Mutex::new(Vec::new()),
|
|
||||||
tx_queue: Mutex::new(Vec::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a packet
|
|
||||||
pub fn send_packet(&self, data: &[u8]) -> Result<()> {
|
|
||||||
let packet = NetPacket {
|
|
||||||
data: data.to_vec(),
|
|
||||||
length: data.len(),
|
|
||||||
interface: self.config.name.clone(),
|
|
||||||
timestamp: crate::time::get_time_ns(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut tx_queue = self.tx_queue.lock();
|
|
||||||
tx_queue.push(packet);
|
|
||||||
|
|
||||||
let mut stats = self.stats.lock();
|
|
||||||
stats.tx_packets += 1;
|
|
||||||
stats.tx_bytes += data.len() as u64;
|
|
||||||
|
|
||||||
crate::info!("Packet sent on interface {}: {} bytes", self.config.name, data.len());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Receive a packet
|
|
||||||
pub fn receive_packet(&self) -> Option<NetPacket> {
|
|
||||||
let mut rx_queue = self.rx_queue.lock();
|
|
||||||
if let Some(packet) = rx_queue.pop() {
|
|
||||||
let mut stats = self.stats.lock();
|
|
||||||
stats.rx_packets += 1;
|
|
||||||
stats.rx_bytes += packet.length as u64;
|
|
||||||
Some(packet)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get interface statistics
|
|
||||||
pub fn get_stats(&self) -> NetStats {
|
|
||||||
self.stats.lock().clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network stack
|
|
||||||
pub struct NetworkStack {
|
|
||||||
interfaces: Mutex<BTreeMap<String, NetworkInterface>>,
|
|
||||||
routing_table: Mutex<Vec<Route>>,
|
|
||||||
arp_table: Mutex<BTreeMap<[u8; 4], [u8; 6]>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Routing table entry
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Route {
|
|
||||||
pub destination: [u8; 4],
|
|
||||||
pub netmask: [u8; 4],
|
|
||||||
pub gateway: [u8; 4],
|
|
||||||
pub interface: String,
|
|
||||||
pub metric: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetworkStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
interfaces: Mutex::new(BTreeMap::new()),
|
|
||||||
routing_table: Mutex::new(Vec::new()),
|
|
||||||
arp_table: Mutex::new(BTreeMap::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add network interface
|
|
||||||
pub fn add_interface(&self, interface: NetworkInterface) -> Result<()> {
|
|
||||||
let name = interface.config.name.clone();
|
|
||||||
let mut interfaces = self.interfaces.lock();
|
|
||||||
interfaces.insert(name.clone(), interface);
|
|
||||||
|
|
||||||
crate::info!("Network interface {} added", name);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove network interface
|
|
||||||
pub fn remove_interface(&self, name: &str) -> Result<()> {
|
|
||||||
let mut interfaces = self.interfaces.lock();
|
|
||||||
if interfaces.remove(name).is_some() {
|
|
||||||
crate::info!("Network interface {} removed", name);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::ENODEV)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get interface by name
|
|
||||||
pub fn get_interface(&self, name: &str) -> Option<NetworkInterface> {
|
|
||||||
let interfaces = self.interfaces.lock();
|
|
||||||
interfaces.get(name).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List all interfaces
|
|
||||||
pub fn list_interfaces(&self) -> Vec<String> {
|
|
||||||
let interfaces = self.interfaces.lock();
|
|
||||||
interfaces.keys().cloned().collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add route
|
|
||||||
pub fn add_route(&self, route: Route) -> Result<()> {
|
|
||||||
let mut routing_table = self.routing_table.lock();
|
|
||||||
routing_table.push(route);
|
|
||||||
|
|
||||||
crate::info!("Route added to routing table");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find route for destination
|
|
||||||
pub fn find_route(&self, destination: [u8; 4]) -> Option<Route> {
|
|
||||||
let routing_table = self.routing_table.lock();
|
|
||||||
|
|
||||||
// Simple routing - find exact match first, then default route
|
|
||||||
for route in routing_table.iter() {
|
|
||||||
if Self::ip_matches(&destination, &route.destination, &route.netmask) {
|
|
||||||
return Some(route.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for default route (0.0.0.0/0)
|
|
||||||
for route in routing_table.iter() {
|
|
||||||
if route.destination == [0, 0, 0, 0] && route.netmask == [0, 0, 0, 0] {
|
|
||||||
return Some(route.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if IP matches network
|
|
||||||
fn ip_matches(ip: &[u8; 4], network: &[u8; 4], netmask: &[u8; 4]) -> bool {
|
|
||||||
for i in 0..4 {
|
|
||||||
if (ip[i] & netmask[i]) != (network[i] & netmask[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add ARP entry
|
|
||||||
pub fn add_arp_entry(&self, ip: [u8; 4], mac: [u8; 6]) -> Result<()> {
|
|
||||||
let mut arp_table = self.arp_table.lock();
|
|
||||||
arp_table.insert(ip, mac);
|
|
||||||
|
|
||||||
crate::info!("ARP entry added: {:?} -> {:?}", ip, mac);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lookup MAC address for IP
|
|
||||||
pub fn arp_lookup(&self, ip: [u8; 4]) -> Option<[u8; 6]> {
|
|
||||||
let arp_table = self.arp_table.lock();
|
|
||||||
arp_table.get(&ip).copied()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send packet to destination
|
|
||||||
pub fn send_to(&self, destination: [u8; 4], data: &[u8]) -> Result<()> {
|
|
||||||
// Find route
|
|
||||||
let route = self.find_route(destination)
|
|
||||||
.ok_or(Error::EHOSTUNREACH)?;
|
|
||||||
|
|
||||||
// Get interface
|
|
||||||
let interfaces = self.interfaces.lock();
|
|
||||||
let interface = interfaces.get(&route.interface)
|
|
||||||
.ok_or(Error::ENODEV)?;
|
|
||||||
|
|
||||||
// For now, just send on the interface
|
|
||||||
interface.send_packet(data)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get network statistics
|
|
||||||
pub fn get_network_stats(&self) -> Vec<(String, NetStats)> {
|
|
||||||
let interfaces = self.interfaces.lock();
|
|
||||||
interfaces.iter()
|
|
||||||
.map(|(name, iface)| (name.clone(), iface.get_stats()))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Global network stack instance
|
|
||||||
static NETWORK_STACK: Mutex<Option<NetworkStack>> = Mutex::new(None);
|
|
||||||
|
|
||||||
/// Initialize networking stack
|
|
||||||
pub fn init() -> Result<()> {
|
|
||||||
let stack = NetworkStack::new();
|
|
||||||
|
|
||||||
// Create loopback interface
|
|
||||||
let loopback_config = NetConfig {
|
|
||||||
name: "lo".to_string(),
|
|
||||||
mac_address: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
|
||||||
ip_address: [127, 0, 0, 1],
|
|
||||||
netmask: [255, 0, 0, 0],
|
|
||||||
gateway: [0, 0, 0, 0],
|
|
||||||
mtu: 65536,
|
|
||||||
flags: 0x1, // IFF_UP
|
|
||||||
};
|
|
||||||
|
|
||||||
let loopback = NetworkInterface::new(loopback_config);
|
|
||||||
stack.add_interface(loopback)?;
|
|
||||||
|
|
||||||
// Add loopback route
|
|
||||||
let loopback_route = Route {
|
|
||||||
destination: [127, 0, 0, 0],
|
|
||||||
netmask: [255, 0, 0, 0],
|
|
||||||
gateway: [0, 0, 0, 0],
|
|
||||||
interface: "lo".to_string(),
|
|
||||||
metric: 0,
|
|
||||||
};
|
|
||||||
stack.add_route(loopback_route)?;
|
|
||||||
|
|
||||||
*NETWORK_STACK.lock() = Some(stack);
|
|
||||||
|
|
||||||
crate::info!("Advanced networking stack initialized");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get global network stack
|
|
||||||
pub fn get_network_stack() -> Result<&'static Mutex<Option<NetworkStack>>> {
|
|
||||||
Ok(&NETWORK_STACK)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network utility functions
|
|
||||||
pub mod utils {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Format IP address as string
|
|
||||||
pub fn ip_to_string(ip: [u8; 4]) -> String {
|
|
||||||
format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse IP address from string
|
|
||||||
pub fn string_to_ip(s: &str) -> Result<[u8; 4]> {
|
|
||||||
let parts: Vec<&str> = s.split('.').collect();
|
|
||||||
if parts.len() != 4 {
|
|
||||||
return Err(Error::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut ip = [0u8; 4];
|
|
||||||
for (i, part) in parts.iter().enumerate() {
|
|
||||||
ip[i] = part.parse().map_err(|_| Error::EINVAL)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Format MAC address as string
|
|
||||||
pub fn mac_to_string(mac: [u8; 6]) -> String {
|
|
||||||
format!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
|
|
||||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate checksum
|
|
||||||
pub fn calculate_checksum(data: &[u8]) -> u16 {
|
|
||||||
let mut sum = 0u32;
|
|
||||||
|
|
||||||
// Sum all 16-bit words
|
|
||||||
for chunk in data.chunks(2) {
|
|
||||||
if chunk.len() == 2 {
|
|
||||||
sum += ((chunk[0] as u32) << 8) + (chunk[1] as u32);
|
|
||||||
} else {
|
|
||||||
sum += (chunk[0] as u32) << 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add carry
|
|
||||||
while sum >> 16 != 0 {
|
|
||||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// One's complement
|
|
||||||
!sum as u16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simple packet creation utilities
|
|
||||||
pub mod packet {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Create a simple test packet
|
|
||||||
pub fn create_test_packet(size: usize) -> Vec<u8> {
|
|
||||||
let mut data = Vec::with_capacity(size);
|
|
||||||
for i in 0..size {
|
|
||||||
data.push((i % 256) as u8);
|
|
||||||
}
|
|
||||||
data
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create ICMP ping packet
|
|
||||||
pub fn create_ping_packet(id: u16, seq: u16, data: &[u8]) -> Vec<u8> {
|
|
||||||
let mut packet = Vec::new();
|
|
||||||
|
|
||||||
// ICMP header
|
|
||||||
packet.push(8); // Type: Echo Request
|
|
||||||
packet.push(0); // Code: 0
|
|
||||||
packet.push(0); // Checksum (will be calculated)
|
|
||||||
packet.push(0);
|
|
||||||
packet.extend_from_slice(&id.to_be_bytes());
|
|
||||||
packet.extend_from_slice(&seq.to_be_bytes());
|
|
||||||
|
|
||||||
// Data
|
|
||||||
packet.extend_from_slice(data);
|
|
||||||
|
|
||||||
// Calculate checksum
|
|
||||||
let checksum = utils::calculate_checksum(&packet);
|
|
||||||
packet[2] = (checksum >> 8) as u8;
|
|
||||||
packet[3] = (checksum & 0xFF) as u8;
|
|
||||||
|
|
||||||
packet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
|
|
||||||
//! Network stub for basic functionality
|
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
|
||||||
|
|
||||||
/// Initialize basic networking
|
|
||||||
pub fn init() -> Result<()> {
|
|
||||||
crate::info!("Network stub initialized");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get network status
|
|
||||||
pub fn get_network_status() -> String {
|
|
||||||
"Network: Basic stub - No interfaces configured".to_string()
|
|
||||||
}
|
|
||||||
@@ -283,42 +283,78 @@ impl KernelShell {
|
|||||||
/// Network command
|
/// Network command
|
||||||
fn cmd_network(&self, args: &[&str]) {
|
fn cmd_network(&self, args: &[&str]) {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
info!("Network commands: stats, test");
|
info!("Network commands: stats, ping <ip>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match args[0] {
|
match args[0] {
|
||||||
"stats" => {
|
"stats" => {
|
||||||
info!("Network interface statistics:");
|
info!("Network interface statistics:");
|
||||||
if let Some(stats) = crate::net_basic::get_net_stats("lo") {
|
let mut stack = crate::network::NETWORK_STACK.lock();
|
||||||
info!(" lo (loopback):");
|
if let Some(ref mut stack) = *stack {
|
||||||
|
for iface_name in stack.list_interfaces() {
|
||||||
|
if let Some(stats) = stack.get_interface_stats(&iface_name) {
|
||||||
|
info!(" {}:", iface_name);
|
||||||
info!(
|
info!(
|
||||||
" TX: {} packets, {} bytes",
|
" TX: {} packets, {} bytes",
|
||||||
stats.tx_packets, stats.tx_bytes
|
stats.packets_sent, stats.bytes_sent
|
||||||
);
|
);
|
||||||
info!(
|
info!(
|
||||||
" RX: {} packets, {} bytes",
|
" RX: {} packets, {} bytes",
|
||||||
stats.rx_packets, stats.rx_bytes
|
stats.packets_received, stats.bytes_received
|
||||||
);
|
);
|
||||||
info!(
|
info!(
|
||||||
" Errors: TX {}, RX {}",
|
" Errors: {}, Dropped: {}",
|
||||||
stats.tx_errors, stats.rx_errors
|
stats.errors, stats.dropped
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
warn!("Failed to get loopback statistics");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"test" => {
|
}
|
||||||
info!("Running network tests...");
|
}
|
||||||
if let Err(e) = crate::net_basic::test_networking() {
|
"ping" => {
|
||||||
error!("Network tests failed: {}", e);
|
if args.len() < 2 {
|
||||||
|
info!("Usage: net ping <ip>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ip_str = args[1];
|
||||||
|
let parts: Vec<&str> = ip_str.split('.').collect();
|
||||||
|
if parts.len() != 4 {
|
||||||
|
info!("Invalid IP address format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut bytes = [0u8; 4];
|
||||||
|
for i in 0..4 {
|
||||||
|
if let Ok(byte) = parts[i].parse() {
|
||||||
|
bytes[i] = byte;
|
||||||
} else {
|
} else {
|
||||||
info!("Network tests passed!");
|
info!("Invalid IP address format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dest_ip = crate::network::Ipv4Address::from_bytes(bytes);
|
||||||
|
|
||||||
|
let mut icmp_packet = crate::icmp::IcmpPacket {
|
||||||
|
icmp_type: crate::icmp::IcmpType::EchoRequest,
|
||||||
|
icmp_code: crate::icmp::IcmpCode::Echo,
|
||||||
|
checksum: 0,
|
||||||
|
identifier: 0,
|
||||||
|
sequence_number: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut data = icmp_packet.to_bytes();
|
||||||
|
let checksum = crate::network::utils::calculate_checksum(&data);
|
||||||
|
icmp_packet.checksum = checksum;
|
||||||
|
data = icmp_packet.to_bytes();
|
||||||
|
|
||||||
|
if let Err(e) = crate::network::send_packet(dest_ip, &data, crate::network::ProtocolType::ICMP) {
|
||||||
|
error!("Failed to send ping: {}", e);
|
||||||
|
} else {
|
||||||
|
info!("Ping sent to {}", dest_ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
info!(
|
info!(
|
||||||
"Unknown network command: {}. Available: stats, test",
|
"Unknown network command: {}. Available: stats, ping",
|
||||||
args[0]
|
args[0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user