Files
rustkernel/kernel/src/network_advanced.rs
2025-06-20 01:50:08 +02:00

374 líneas
10 KiB
Rust

// 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
}
}