Files
rustkernel/kernel/src/network.rs
google-labs-jules[bot] 932310d08c 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.
2025-12-02 01:35:21 +01:00

706 líneas
17 KiB
Rust

// SPDX-License-Identifier: GPL-2.0
//! Network stack implementation
use alloc::{boxed::Box, collections::BTreeMap, collections::VecDeque, string::{String, ToString}, vec::Vec};
use core::fmt;
use crate::error::{Error, Result};
use crate::sync::Spinlock;
/// Network protocol types
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProtocolType {
Ethernet = 0x0001,
IPv4 = 0x0800,
IPv6 = 0x86DD,
ARP = 0x0806,
TCP = 6,
UDP = 17,
ICMP = 2, // Different value to avoid conflict with Ethernet
ICMPv6 = 58,
}
/// MAC address (6 bytes)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacAddress([u8; 6]);
impl MacAddress {
pub const fn new(bytes: [u8; 6]) -> Self {
Self(bytes)
}
pub const fn broadcast() -> Self {
Self([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
}
pub const fn zero() -> Self {
Self([0, 0, 0, 0, 0, 0])
}
pub fn bytes(&self) -> &[u8; 6] {
&self.0
}
pub fn is_broadcast(&self) -> bool {
*self == Self::broadcast()
}
pub fn is_multicast(&self) -> bool {
(self.0[0] & 0x01) != 0
}
}
impl fmt::Display for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
)
}
}
/// IPv4 address
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Ipv4Address([u8; 4]);
impl Ipv4Address {
pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
Self([a, b, c, d])
}
pub const fn from_bytes(bytes: [u8; 4]) -> Self {
Self(bytes)
}
pub const fn localhost() -> Self {
Self([127, 0, 0, 1])
}
pub const fn broadcast() -> Self {
Self([255, 255, 255, 255])
}
pub const fn any() -> Self {
Self([0, 0, 0, 0])
}
pub fn bytes(&self) -> &[u8; 4] {
&self.0
}
pub fn to_u32(&self) -> u32 {
u32::from_be_bytes(self.0)
}
pub fn from_u32(addr: u32) -> Self {
Self(addr.to_be_bytes())
}
pub fn is_private(&self) -> bool {
matches!(self.0, [10, ..] | [172, 16..=31, ..] | [192, 168, ..])
}
pub fn is_multicast(&self) -> bool {
(self.0[0] & 0xF0) == 0xE0
}
pub fn is_broadcast(&self) -> bool {
*self == Self::broadcast()
}
}
impl fmt::Display for Ipv4Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}.{}", self.0[0], self.0[1], self.0[2], self.0[3])
}
}
/// Network packet buffer
#[derive(Debug, Clone)]
pub struct NetworkBuffer {
data: Vec<u8>,
len: usize,
protocol: ProtocolType,
source_mac: Option<MacAddress>,
dest_mac: Option<MacAddress>,
source_ip: Option<Ipv4Address>,
dest_ip: Option<Ipv4Address>,
source_port: Option<u16>,
dest_port: Option<u16>,
}
impl NetworkBuffer {
pub fn new(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
len: 0,
protocol: ProtocolType::Ethernet,
source_mac: None,
dest_mac: None,
source_ip: None,
dest_ip: None,
source_port: None,
dest_port: None,
}
}
pub fn from_data(data: Vec<u8>) -> Self {
let len = data.len();
Self {
data,
len,
protocol: ProtocolType::Ethernet,
source_mac: None,
dest_mac: None,
source_ip: None,
dest_ip: None,
source_port: None,
dest_port: None,
}
}
pub fn data(&self) -> &[u8] {
&self.data[..self.len]
}
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.data[..self.len]
}
pub fn len(&self) -> usize {
self.len
}
pub fn push(&mut self, byte: u8) -> Result<()> {
if self.len >= self.data.capacity() {
return Err(Error::OutOfMemory);
}
if self.len >= self.data.len() {
self.data.push(byte);
} else {
self.data[self.len] = byte;
}
self.len += 1;
Ok(())
}
pub fn extend_from_slice(&mut self, data: &[u8]) -> Result<()> {
if self.len + data.len() > self.data.capacity() {
return Err(Error::OutOfMemory);
}
for &byte in data {
self.push(byte)?;
}
Ok(())
}
pub fn set_protocol(&mut self, protocol: ProtocolType) {
self.protocol = protocol;
}
pub fn set_mac_addresses(&mut self, source: MacAddress, dest: MacAddress) {
self.source_mac = Some(source);
self.dest_mac = Some(dest);
}
pub fn set_ip_addresses(&mut self, source: Ipv4Address, dest: Ipv4Address) {
self.source_ip = Some(source);
self.dest_ip = Some(dest);
}
pub fn set_ports(&mut self, source: u16, dest: u16) {
self.source_port = Some(source);
self.dest_port = Some(dest);
}
}
/// Network interface
pub trait NetworkInterface: Send + Sync {
fn name(&self) -> &str;
fn ip_address(&self) -> Option<Ipv4Address>;
fn mac_address(&self) -> MacAddress;
fn mtu(&self) -> u16;
fn is_up(&self) -> bool;
fn send_packet(&mut self, buffer: &NetworkBuffer) -> Result<()>;
fn receive_packet(&mut self) -> Result<Option<NetworkBuffer>>;
fn set_up(&mut self, up: bool) -> Result<()>;
fn set_mac_address(&mut self, mac: MacAddress) -> Result<()>;
}
/// Network interface statistics
#[derive(Debug, Default, Clone)]
pub struct InterfaceStats {
pub bytes_sent: u64,
pub bytes_received: u64,
pub packets_sent: u64,
pub packets_received: u64,
pub errors: 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
struct PendingArpRequest {
packet: NetworkBuffer,
ip: Ipv4Address,
timestamp: u64,
}
pub struct NetworkStack {
interfaces: BTreeMap<String, Box<dyn NetworkInterface>>,
interface_stats: BTreeMap<String, InterfaceStats>,
routing_table: Vec<RouteEntry>,
arp_table: BTreeMap<Ipv4Address, MacAddress>,
pending_arp_requests: Vec<PendingArpRequest>,
}
/// Routing table entry
#[derive(Debug, Clone)]
pub struct RouteEntry {
pub destination: Ipv4Address,
pub netmask: Ipv4Address,
pub gateway: Option<Ipv4Address>,
pub interface: String,
pub metric: u32,
}
impl NetworkStack {
const fn new() -> Self {
Self {
interfaces: BTreeMap::new(),
interface_stats: BTreeMap::new(),
routing_table: Vec::new(),
arp_table: BTreeMap::new(),
pending_arp_requests: Vec::new(),
}
}
pub fn add_interface(&mut self, name: String, interface: Box<dyn NetworkInterface>) {
self.interface_stats
.insert(name.clone(), InterfaceStats::default());
self.interfaces.insert(name, interface);
}
pub fn remove_interface(&mut self, name: &str) -> Option<Box<dyn NetworkInterface>> {
self.interface_stats.remove(name);
self.interfaces.remove(name)
}
pub fn get_interface(&self, name: &str) -> Option<&dyn NetworkInterface> {
self.interfaces.get(name).map(|i| i.as_ref())
}
pub fn get_interface_mut<'a>(
&'a mut self,
name: &str,
) -> Option<&'a mut (dyn NetworkInterface + 'a)> {
if let Some(interface) = self.interfaces.get_mut(name) {
Some(interface.as_mut())
} else {
None
}
}
pub fn list_interfaces(&self) -> Vec<String> {
self.interfaces.keys().cloned().collect()
}
pub fn add_route(&mut self, route: RouteEntry) {
self.routing_table.push(route);
// Sort by metric (lower is better)
self.routing_table.sort_by_key(|r| r.metric);
}
pub fn find_route(&self, dest: Ipv4Address) -> Option<&RouteEntry> {
for route in &self.routing_table {
let dest_u32 = dest.to_u32();
let route_dest = route.destination.to_u32();
let netmask = route.netmask.to_u32();
if (dest_u32 & netmask) == (route_dest & netmask) {
return Some(route);
}
}
None
}
pub fn add_arp_entry(&mut self, ip: Ipv4Address, mac: MacAddress) {
self.arp_table.insert(ip, mac);
}
pub fn lookup_arp(&self, ip: Ipv4Address) -> Option<MacAddress> {
self.arp_table.get(&ip).copied()
}
pub fn send_packet(
&mut self,
dest: Ipv4Address,
data: &[u8],
protocol: ProtocolType,
) -> 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)
let route = {
let route = self.find_route(dest).ok_or(Error::NetworkUnreachable)?;
route.clone() // Clone to avoid borrowing issues
};
// Look up MAC address first (borrow self immutably)
let dest_mac = if let Some(gateway) = route.gateway {
self.lookup_arp(gateway)
} else {
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
let interface_mac = {
let interface = self
.get_interface(&route.interface)
.ok_or(Error::DeviceNotFound)?;
interface.mac_address()
};
// Build packet
let mut buffer = NetworkBuffer::new(1500);
buffer.set_protocol(protocol);
buffer.set_mac_addresses(interface_mac, dest_mac);
buffer.extend_from_slice(data)?;
// Send packet (borrow self mutably)
{
let interface = self
.get_interface_mut(&route.interface)
.ok_or(Error::DeviceNotFound)?;
interface.send_packet(&buffer)?;
}
// Update statistics
if let Some(stats) = self.interface_stats.get_mut(&route.interface) {
stats.packets_sent += 1;
stats.bytes_sent += buffer.len() as u64;
}
Ok(())
}
pub fn receive_and_handle_packets(&mut self) -> Result<Vec<NetworkBuffer>> {
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 {
while let Some(packet) = interface.receive_packet()? {
if let Some(stats) = self.interface_stats.get_mut(name) {
stats.packets_received += 1;
stats.bytes_received += packet.len() as u64;
}
received_packets.push((name.clone(), packet));
}
}
// 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> {
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
pub static NETWORK_STACK: Spinlock<Option<NetworkStack>> = Spinlock::new(None);
/// Initialize network stack
pub fn init() -> Result<()> {
let mut stack = NETWORK_STACK.lock();
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");
Ok(())
}
/// Add a network interface
pub fn add_network_interface(name: String, interface: Box<dyn NetworkInterface>) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.add_interface(name, interface);
Ok(())
} else {
Err(Error::NotInitialized)
}
}
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
pub fn send_packet(dest: Ipv4Address, data: &[u8], protocol: ProtocolType) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.send_packet(dest, data, protocol)
} else {
Err(Error::NotInitialized)
}
}
/// Add a route
pub fn add_route(
destination: Ipv4Address,
netmask: Ipv4Address,
gateway: Option<Ipv4Address>,
interface: String,
metric: u32,
) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.add_route(RouteEntry {
destination,
netmask,
gateway,
interface,
metric,
});
Ok(())
} else {
Err(Error::NotInitialized)
}
}
/// Add an ARP entry
pub fn add_arp_entry(ip: Ipv4Address, mac: MacAddress) -> Result<()> {
let mut stack_opt = NETWORK_STACK.lock();
if let Some(ref mut stack) = *stack_opt {
stack.add_arp_entry(ip, mac);
Ok(())
} else {
Err(Error::NotInitialized)
}
}