greatbridf преди 7 месеца
родител
ревизия
66c94103a8
променени са 16 файла, в които са добавени 1453 реда и са изтрити 561 реда
  1. 128 7
      Cargo.lock
  2. 13 1
      Cargo.toml
  3. 12 419
      src/driver/e1000e.rs
  4. 81 80
      src/driver/e1000e/defs.rs
  5. 480 0
      src/driver/e1000e/dev.rs
  6. 37 0
      src/driver/e1000e/error.rs
  7. 183 0
      src/driver/e1000e/rx_desc.rs
  8. 157 0
      src/driver/e1000e/tx_desc.rs
  9. 15 0
      src/kernel/syscall/net.rs
  10. 8 0
      src/net.rs
  11. 5 0
      src/net/buffer.rs
  12. 8 0
      src/net/error.rs
  13. 77 0
      src/net/link_info.rs
  14. 223 53
      src/net/netdev.rs
  15. 25 0
      src/net/socket_set.rs
  16. 1 1
      src/prelude.rs

+ 128 - 7
Cargo.lock

@@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94476c7ef97af4c4d998b3f422c1b01d5211aad57c80ed200baf148d1f1efab6"
 dependencies = [
  "bit_field",
- "bitflags",
+ "bitflags 2.9.1",
  "log",
 ]
 
@@ -35,6 +35,12 @@ version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
 
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
 [[package]]
 name = "bitflags"
 version = "2.9.1"
@@ -49,6 +55,12 @@ dependencies = [
  "intrusive_list",
 ]
 
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -61,6 +73,47 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
 
+[[package]]
+name = "defmt"
+version = "0.3.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad"
+dependencies = [
+ "defmt 1.0.1",
+]
+
+[[package]]
+name = "defmt"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
+dependencies = [
+ "bitflags 1.3.2",
+ "defmt-macros",
+]
+
+[[package]]
+name = "defmt-macros"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
+dependencies = [
+ "defmt-parser",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "defmt-parser"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
+dependencies = [
+ "thiserror",
+]
+
 [[package]]
 name = "either"
 version = "1.15.0"
@@ -95,7 +148,7 @@ name = "eonix_hal"
 version = "0.1.0"
 dependencies = [
  "acpi",
- "bitflags",
+ "bitflags 2.9.1",
  "buddy_allocator",
  "cfg-if",
  "eonix_hal_macros",
@@ -123,7 +176,7 @@ dependencies = [
 name = "eonix_hal_traits"
 version = "0.1.0"
 dependencies = [
- "bitflags",
+ "bitflags 2.9.1",
  "eonix_mm",
 ]
 
@@ -134,7 +187,7 @@ dependencies = [
  "acpi",
  "align_ext",
  "atomic_unique_refcell",
- "bitflags",
+ "bitflags 2.9.1",
  "buddy_allocator",
  "eonix_hal",
  "eonix_log",
@@ -150,6 +203,7 @@ dependencies = [
  "pointers",
  "posix_types",
  "slab_allocator",
+ "smoltcp",
  "virtio-drivers",
  "xmas-elf",
 ]
@@ -174,7 +228,7 @@ dependencies = [
 name = "eonix_mm"
 version = "0.1.0"
 dependencies = [
- "bitflags",
+ "bitflags 2.9.1",
 ]
 
 [[package]]
@@ -252,6 +306,25 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
 
+[[package]]
+name = "hash32"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "heapless"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
+dependencies = [
+ "hash32",
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "intrusive-collections"
 version = "0.9.7"
@@ -280,6 +353,12 @@ version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
+[[package]]
+name = "managed"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
+
 [[package]]
 name = "memoffset"
 version = "0.9.1"
@@ -303,10 +382,32 @@ version = "0.1.0"
 name = "posix_types"
 version = "0.1.0"
 dependencies = [
- "bitflags",
+ "bitflags 2.9.1",
  "cfg-if",
 ]
 
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.95"
@@ -379,6 +480,26 @@ dependencies = [
  "intrusive_list",
 ]
 
+[[package]]
+name = "smoltcp"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb"
+dependencies = [
+ "bitflags 1.3.2",
+ "byteorder",
+ "cfg-if",
+ "defmt 0.3.100",
+ "heapless",
+ "managed",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
 [[package]]
 name = "syn"
 version = "2.0.101"
@@ -422,7 +543,7 @@ version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fe3f779fd88436e27b51540d9563c7454c8c814893a1e6f9bb6138bcac60627"
 dependencies = [
- "bitflags",
+ "bitflags 2.9.1",
  "embedded-io",
  "enumn",
  "log",

+ 13 - 1
Cargo.toml

@@ -30,15 +30,27 @@ itertools = { version = "0.13.0", default-features = false }
 acpi = "5.2.0"
 align_ext = "0.1.0"
 xmas-elf = "0.10.0"
+smoltcp = { version = "0.12.0", default-features = false, features = [
+    "alloc",
+    "medium-ethernet",
+    "proto-ipv4",
+    "proto-ipv6",
+    "socket-tcp",
+    "socket-udp",
+    "socket-dhcpv4",
+    "socket-dns",
+    "async",
+] }
 
 [target.'cfg(target_arch = "riscv64")'.dependencies]
 virtio-drivers = { version = "0.11.0" }
 
 [features]
 default = []
+trace_net = []
 trace_syscall = []
 trace_scheduler = []
-log_trace = ["trace_syscall", "trace_scheduler"]
+log_trace = ["trace_syscall", "trace_scheduler", "trace_net"]
 log_debug = []
 smp = []
 

+ 12 - 419
src/driver/e1000e.rs

@@ -15,423 +15,16 @@ use eonix_sync::SpinIrq;
 use paging::Page;
 
 mod defs;
+mod dev;
+mod error;
+mod rx_desc;
+mod tx_desc;
 
-#[repr(C)]
-struct RxDescriptor {
-    buffer: u64,
-    length: u16,
-    checksum: u16,
-    status: u8,
-    errors: u8,
-    vlan: u16,
-}
-
-#[repr(C)]
-struct TxDescriptor {
-    buffer: u64,
-    length: u16,
-    cso: u8, // Checksum offset
-    cmd: u8,
-    status: u8,
-    css: u8, // Checksum start
-    vlan: u16,
-}
-
-const RX_DESC_SIZE: usize = 32;
-const TX_DESC_SIZE: usize = 32;
-
-struct Registers(NonNull<()>);
-
-unsafe impl Send for Registers {}
-unsafe impl Sync for Registers {}
-
-struct E1000eDev {
-    irq_no: usize,
-
-    mac: netdev::Mac,
-    status: netdev::LinkStatus,
-    speed: netdev::LinkSpeed,
-    id: u32,
-
-    regs: Registers,
-    rt_desc_page: Page,
-    rx_head: Option<u32>,
-    rx_tail: Option<u32>,
-    tx_tail: Option<u32>,
-
-    rx_buffers: Option<Box<Vec<Page>>>,
-    tx_buffers: Option<Box<Vec<Page>>>,
-}
-
-fn test(val: u32, bit: u32) -> bool {
-    (val & bit) == bit
-}
-
-struct PrintableBytes<'a>(&'a [u8]);
-
-impl core::fmt::Debug for PrintableBytes<'_> {
-    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
-        write!(f, "PrintableBytes {{")?;
-        for chunk in self.0.chunks(16) {
-            for &byte in chunk {
-                write!(f, "{byte:#2x} ")?;
-            }
-            write!(f, "\n")?;
-        }
-        write!(f, "}}")?;
-
-        Ok(())
-    }
-}
-
-impl Registers {
-    fn new(base: PAddr) -> Self {
-        Self(unsafe { base.as_ptr() })
-    }
-
-    fn read(&self, offset: u32) -> u32 {
-        let retval = unsafe {
-            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
-            self.0.byte_offset(offset as isize).cast().read_volatile()
-        };
-        memory_barrier();
-        retval
-    }
-
-    fn write(&self, offset: u32, value: u32) {
-        unsafe {
-            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
-            self.0
-                .byte_offset(offset as isize)
-                .cast()
-                .write_volatile(value);
-        }
-        memory_barrier();
-    }
-
-    fn read_as<T: Copy>(&self, offset: u32) -> T {
-        let retval = unsafe {
-            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
-            self.0.byte_offset(offset as isize).cast().read_volatile()
-        };
-        memory_barrier();
-        retval
-    }
-}
-
-impl netdev::Netdev for E1000eDev {
-    fn mac(&self) -> netdev::Mac {
-        self.mac
-    }
-
-    fn link_status(&self) -> netdev::LinkStatus {
-        self.status
-    }
-
-    fn link_speed(&self) -> netdev::LinkSpeed {
-        self.speed
-    }
-
-    fn id(&self) -> u32 {
-        self.id
-    }
-
-    fn up(&mut self) -> Result<(), u32> {
-        let ctrl = self.regs.read(defs::REG_CTRL);
-        let status = self.regs.read(defs::REG_STAT);
-
-        // check link up
-        if !test(ctrl, defs::CTRL_SLU) || !test(status, defs::STAT_LU) {
-            return Err(EIO);
-        }
-
-        // auto negotiation of speed
-        match status & defs::STAT_SPEED_MASK {
-            defs::STAT_SPEED_10M => self.speed = netdev::LinkSpeed::Speed10M,
-            defs::STAT_SPEED_100M => self.speed = netdev::LinkSpeed::Speed100M,
-            defs::STAT_SPEED_1000M => self.speed = netdev::LinkSpeed::Speed1000M,
-            _ => return Err(EINVAL),
-        }
-
-        // clear multicast table
-        for i in (0..128).step_by(4) {
-            self.regs.write(defs::REG_MTA + i, 0);
-        }
-
-        self.clear_stats()?;
-
-        // setup interrupt handler
-        let device = netdev::get_netdev(self.id).unwrap();
-        register_irq_handler(self.irq_no as _, move || {
-            device.lock().fire().unwrap();
-        })?;
-
-        // enable interrupts
-        self.regs
-            .write(defs::REG_IMS, defs::ICR_NORMAL | defs::ICR_UP);
-
-        // read to clear any pending interrupts
-        self.regs.read(defs::REG_ICR);
-
-        self.setup_rx()?;
-        self.setup_tx()?;
-
-        self.status = netdev::LinkStatus::Up;
-
-        Ok(())
-    }
-
-    fn fire(&mut self) -> Result<(), u32> {
-        let cause = self.regs.read(defs::REG_ICR);
-        if !test(cause, defs::ICR_INT) {
-            return Ok(());
-        }
-
-        loop {
-            let tail = self.rx_tail.ok_or(EIO)?;
-            let next_tail = (tail + 1) % RX_DESC_SIZE as u32;
-
-            if next_tail == self.regs.read(defs::REG_RDH) {
-                break;
-            }
-
-            let ref mut desc = self.rx_desc_table()[next_tail as usize];
-            if !test(desc.status as u32, defs::RXD_STAT_DD as u32) {
-                Err(EIO)?;
-            }
-
-            desc.status = 0;
-            let len = desc.length as usize;
-
-            let buffers = self.rx_buffers.as_mut().ok_or(EIO)?;
-            let data = unsafe {
-                // SAFETY: No one could be writing to the buffer at this point.
-                &buffers[next_tail as usize].as_memblk().as_bytes()[..len]
-            };
-
-            println_debug!("e1000e: received {len} bytes, {:?}", PrintableBytes(data));
-            self.rx_tail = Some(next_tail);
-        }
-
-        Ok(())
-    }
-
-    fn send(&mut self, buf: &[u8]) -> Result<(), u32> {
-        let tail = self.tx_tail.ok_or(EIO)?;
-        let head = self.regs.read(defs::REG_TDH);
-        let next_tail = (tail + 1) % TX_DESC_SIZE as u32;
-
-        if next_tail == head {
-            return Err(EAGAIN);
-        }
-
-        let ref mut desc = self.tx_desc_table()[tail as usize];
-        if !test(desc.status as u32, defs::TXD_STAT_DD as u32) {
-            return Err(EIO);
-        }
-
-        let buffer_page = Page::alloc();
-        if buf.len() > buffer_page.len() {
-            return Err(EFAULT);
-        }
-
-        unsafe {
-            // SAFETY: We are the only one writing to this memory block.
-            buffer_page.as_memblk().as_bytes_mut()[..buf.len()].copy_from_slice(buf);
-        }
-
-        desc.buffer = PAddr::from(buffer_page.pfn()).addr() as u64;
-        desc.length = buf.len() as u16;
-        desc.cmd = defs::TXD_CMD_EOP | defs::TXD_CMD_IFCS | defs::TXD_CMD_RS;
-        desc.status = 0;
-
-        self.tx_tail = Some(next_tail);
-        self.regs.write(defs::REG_TDT, next_tail);
-
-        // TODO: check if the packets are sent and update self.tx_head state
-
-        Ok(())
-    }
-}
-
-impl E1000eDev {
-    fn setup_rx(&mut self) -> Result<(), u32> {
-        if !self.rx_head.is_none() || !self.rx_tail.is_none() {
-            return Err(EINVAL);
-        }
-
-        let addr = PAddr::from(self.rt_desc_page.pfn()).addr();
-
-        self.regs.write(defs::REG_RDBAL, addr as u32);
-        self.regs.write(defs::REG_RDBAH, (addr >> 32) as u32);
-
-        self.regs.write(
-            defs::REG_RDLEN,
-            (RX_DESC_SIZE * size_of::<RxDescriptor>()) as u32,
-        );
-
-        self.regs.write(defs::REG_RDH, 0);
-        self.regs.write(defs::REG_RDT, RX_DESC_SIZE as u32 - 1);
-
-        self.rx_head = Some(0);
-        self.rx_tail = Some(RX_DESC_SIZE as u32 - 1);
-
-        self.regs.write(
-            defs::REG_RCTL,
-            defs::RCTL_EN
-                | defs::RCTL_MPE
-                | defs::RCTL_LPE
-                | defs::RCTL_LBM_NO
-                | defs::RCTL_DTYP_LEGACY
-                | defs::RCTL_BAM
-                | defs::RCTL_BSIZE_8192
-                | defs::RCTL_SECRC,
-        );
-
-        Ok(())
-    }
-
-    fn setup_tx(&mut self) -> Result<(), u32> {
-        if !self.tx_tail.is_none() {
-            return Err(EINVAL);
-        }
-
-        let addr = PAddr::from(self.rt_desc_page.pfn()).addr() + 0x200;
-
-        self.regs.write(defs::REG_TDBAL, addr as u32);
-        self.regs.write(defs::REG_TDBAH, (addr >> 32) as u32);
-
-        self.regs.write(
-            defs::REG_TDLEN,
-            (TX_DESC_SIZE * size_of::<TxDescriptor>()) as u32,
-        );
-
-        self.regs.write(defs::REG_TDH, 0);
-        self.regs.write(defs::REG_TDT, 0);
-
-        self.tx_tail = Some(0);
-
-        self.regs.write(
-            defs::REG_TCTL,
-            defs::TCTL_EN
-                | defs::TCTL_PSP
-                | (15 << defs::TCTL_CT_SHIFT)
-                | (64 << defs::TCTL_COLD_SHIFT)
-                | defs::TCTL_RTLC,
-        );
-
-        Ok(())
-    }
-
-    fn reset(&self) -> Result<(), u32> {
-        // disable interrupts so we won't mess things up
-        self.regs.write(defs::REG_IMC, 0xffffffff);
-
-        let ctrl = self.regs.read(defs::REG_CTRL);
-        self.regs.write(defs::REG_CTRL, ctrl | defs::CTRL_GIOD);
-
-        while self.regs.read(defs::REG_STAT) & defs::STAT_GIOE != 0 {
-            // wait for link up
-        }
-
-        let ctrl = self.regs.read(defs::REG_CTRL);
-        self.regs.write(defs::REG_CTRL, ctrl | defs::CTRL_RST);
-
-        while self.regs.read(defs::REG_CTRL) & defs::CTRL_RST != 0 {
-            // wait for reset
-        }
-
-        // disable interrupts again
-        self.regs.write(defs::REG_IMC, 0xffffffff);
-
-        Ok(())
-    }
-
-    fn clear_stats(&self) -> Result<(), u32> {
-        self.regs.write(defs::REG_COLC, 0);
-        self.regs.write(defs::REG_GPRC, 0);
-        self.regs.write(defs::REG_MPRC, 0);
-        self.regs.write(defs::REG_GPTC, 0);
-        self.regs.write(defs::REG_GORCL, 0);
-        self.regs.write(defs::REG_GORCH, 0);
-        self.regs.write(defs::REG_GOTCL, 0);
-        self.regs.write(defs::REG_GOTCH, 0);
-        Ok(())
-    }
-
-    pub fn new(base: PAddr, irq_no: usize) -> Result<Self, u32> {
-        let page = Page::zeroed();
-
-        let mut dev = Self {
-            irq_no,
-            mac: [0; 6],
-            status: netdev::LinkStatus::Down,
-            speed: netdev::LinkSpeed::SpeedUnknown,
-            id: netdev::alloc_id(),
-            regs: Registers::new(base),
-            rt_desc_page: page,
-            rx_head: None,
-            rx_tail: None,
-            tx_tail: None,
-            rx_buffers: None,
-            tx_buffers: None,
-        };
-
-        dev.reset()?;
-
-        dev.mac = dev.regs.read_as(0x5400);
-        dev.tx_buffers = Some(Box::new(Vec::with_capacity(TX_DESC_SIZE)));
-
-        let mut rx_buffers = Box::new(Vec::with_capacity(RX_DESC_SIZE));
-
-        for index in 0..RX_DESC_SIZE {
-            let page = Page::alloc_order(2);
-
-            let ref mut desc = dev.rx_desc_table()[index];
-            desc.buffer = PAddr::from(page.pfn()).addr() as u64;
-            desc.status = 0;
-
-            rx_buffers.push(page);
-        }
-
-        for index in 0..TX_DESC_SIZE {
-            let ref mut desc = dev.tx_desc_table()[index];
-            desc.status = defs::TXD_STAT_DD;
-        }
-
-        dev.rx_buffers = Some(rx_buffers);
-
-        Ok(dev)
-    }
-
-    fn rx_desc_table(&self) -> &mut [RxDescriptor; RX_DESC_SIZE] {
-        unsafe {
-            // SAFETY: TODO
-            self.rt_desc_page.as_memblk().as_ptr().as_mut()
-        }
-    }
-
-    fn tx_desc_table(&self) -> &mut [TxDescriptor; TX_DESC_SIZE] {
-        let (_, right) = self.rt_desc_page.as_memblk().split_at(0x200);
-        unsafe {
-            // SAFETY: TODO
-            right.as_ptr().as_mut()
-        }
-    }
-}
-
-impl Drop for E1000eDev {
-    fn drop(&mut self) {
-        assert_eq!(self.status, netdev::LinkStatus::Down);
-
-        if let Some(_) = self.rx_buffers.take() {}
-
-        // TODO: we should wait until all packets are sent
-        if let Some(_) = self.tx_buffers.take() {}
-
-        let _ = self.rt_desc_page;
-    }
-}
+use crate::kernel::constants::{EINVAL, EIO};
+use crate::kernel::pcie::{self, Header, PCIDevice, PCIDriver, PciError};
+use alloc::sync::Arc;
+use dev::E1000eDev;
+use eonix_mm::address::PAddr;
 
 struct Driver {
     dev_id: u16,
@@ -460,10 +53,10 @@ impl PCIDriver for Driver {
         device.enable_bus_mastering();
 
         let base = PAddr::from(bar0 as usize);
-        let e1000e = E1000eDev::new(base, header.interrupt_line as usize)?;
 
-        let dev = netdev::register_netdev(e1000e)?;
-        dev.lock_irq().up()?;
+        let dev = E1000eDev::create(header.interrupt_line as usize, base).map_err(|_| EIO)?;
+        dev.register().map_err(|_| EIO)?;
+        dev.up().map_err(|_| EIO)?;
 
         Ok(())
     }

+ 81 - 80
src/driver/e1000e/defs.rs

@@ -1,198 +1,199 @@
 #![allow(dead_code)]
 
 // Register names
-// Control register
+/// Control register
 pub const REG_CTRL: u32 = 0x00000;
-// Status register
+/// Status register
 pub const REG_STAT: u32 = 0x00008;
-// Interrupt cause register
+/// Interrupt cause register
 pub const REG_ICR: u32 = 0x000C0;
-// Interrupt mask set/clear register
+/// Interrupt mask set/clear register
 pub const REG_IMS: u32 = 0x000D0;
-// Interrupt mask clear register
+/// Interrupt mask clear register
 pub const REG_IMC: u32 = 0x000D8;
-// Multicast table array start
+/// Multicast table array start
 pub const REG_MTA: u32 = 0x05200;
 
-// Receive control
+/// Receive control
 pub const REG_RCTL: u32 = 0x00100;
 
 // These registers are per-queue
 
-// Receive descriptor base address low
+/// Receive descriptor base address low
 pub const REG_RDBAL: u32 = 0x02800;
-// Receive descriptor base address high
+/// Receive descriptor base address high
 pub const REG_RDBAH: u32 = 0x02804;
-// Receive descriptor length
+/// Receive descriptor length
 pub const REG_RDLEN: u32 = 0x02808;
-// Receive descriptor head
+/// Receive descriptor head
 pub const REG_RDH: u32 = 0x02810;
-// Receive descriptor tail
+/// Receive descriptor tail
 pub const REG_RDT: u32 = 0x02818;
-// Receive descriptor control
+/// Receive interrupt delay timer
+pub const REG_RDTR: u32 = 0x02820;
+/// Receive descriptor control
 pub const REG_RXDCTL: u32 = 0x02828;
 
-// Transmit control
+/// Transmit control
 pub const REG_TCTL: u32 = 0x00400;
 
 // These registers are per-queue
 
-// Transmit descriptor base address low
+/// Transmit descriptor base address low
 pub const REG_TDBAL: u32 = 0x03800;
-// Transmit descriptor base address high
+/// Transmit descriptor base address high
 pub const REG_TDBAH: u32 = 0x03804;
-// Transmit descriptor length
+/// Transmit descriptor length
 pub const REG_TDLEN: u32 = 0x03808;
-// Transmit descriptor head
+/// Transmit descriptor head
 pub const REG_TDH: u32 = 0x03810;
-// Transmit descriptor tail
+/// Transmit descriptor tail
 pub const REG_TDT: u32 = 0x03818;
-// Transmit descriptor control
+/// Transmit descriptor control
 pub const REG_TXDCTL: u32 = 0x03828;
 
-// Collision counter
+/// Collision counter
 pub const REG_COLC: u32 = 0x04028;
-// Good packets received counter
+/// Good packets received counter
 pub const REG_GPRC: u32 = 0x04074;
-// Multicast packets received counter
+/// Multicast packets received counter
 pub const REG_MPRC: u32 = 0x0407C;
-// Good packets transmitted counter
+/// Good packets transmitted counter
 pub const REG_GPTC: u32 = 0x04080;
-// Good octets received counter low
+/// Good octets received counter low
 pub const REG_GORCL: u32 = 0x04088;
-// Good octets received counter high
+/// Good octets received counter high
 pub const REG_GORCH: u32 = 0x0408C;
-// Good octets transmitted counter low
+/// Good octets transmitted counter low
 pub const REG_GOTCL: u32 = 0x04090;
-// Good octets transmitted counter high
+/// Good octets transmitted counter high
 pub const REG_GOTCH: u32 = 0x04094;
 
-// Full-duplex
+/// Full-duplex
 pub const CTRL_FD: u32 = 0x00000001;
-// GIO master disable
+/// GIO master disable
 pub const CTRL_GIOD: u32 = 0x00000004;
-// Set link up
+/// Set link up
 pub const CTRL_SLU: u32 = 0x00000040;
-// Software reset
+/// Software reset
 pub const CTRL_RST: u32 = 0x04000000;
-// Receive flow control enable
+/// Receive flow control enable
 pub const CTRL_RFCE: u32 = 0x08000000;
-// Transmit flow control enable
+/// Transmit flow control enable
 pub const CTRL_TFCE: u32 = 0x10000000;
 
-// Full-duplex
+/// Full-duplex
 pub const STAT_FD: u32 = 0x00000001;
-// Link up
+/// Link up
 pub const STAT_LU: u32 = 0x00000002;
-// Transmit paused
+/// Transmit paused
 pub const STAT_TXOFF: u32 = 0x00000010;
-// Link speed settings
+/// Link speed settings
 pub const STAT_SPEED_MASK: u32 = 0x000000C0;
 pub const STAT_SPEED_10M: u32 = 0x00000000;
 pub const STAT_SPEED_100M: u32 = 0x00000040;
 pub const STAT_SPEED_1000M: u32 = 0x00000080;
-// GIO master enable
+/// GIO master enable
 pub const STAT_GIOE: u32 = 0x00080000;
 
-// Receive control enable
+/// Receive control enable
 pub const RCTL_EN: u32 = 0x00000002;
-// Store bad packets
+/// Store bad packets
 pub const RCTL_SBP: u32 = 0x00000004;
-// Unicast promiscuous mode
+/// Unicast promiscuous mode
 pub const RCTL_UPE: u32 = 0x00000008;
-// Multicast promiscuous mode
+/// Multicast promiscuous mode
 pub const RCTL_MPE: u32 = 0x00000010;
-// Long packet enable
+/// Long packet enable
 pub const RCTL_LPE: u32 = 0x00000020;
-// Loopback mode
+/// Loopback mode
 pub const RCTL_LBM_MASK: u32 = 0x000000C0;
 pub const RCTL_LBM_NO: u32 = 0x00000000;
 pub const RCTL_LBM_MAC: u32 = 0x00000040;
-// Receive descriptor minimum threshold size
+/// Receive descriptor minimum threshold size
 pub const RCTL_RDMTS_MASK: u32 = 0x00000300;
 pub const RCTL_RDMTS_HALF: u32 = 0x00000000;
 pub const RCTL_RDMTS_QUARTER: u32 = 0x00000100;
 pub const RCTL_RDMTS_EIGHTH: u32 = 0x00000200;
-// Receive descriptor type
+/// Receive descriptor type
 pub const RCTL_DTYP_MASK: u32 = 0x00000C00;
 pub const RCTL_DTYP_LEGACY: u32 = 0x00000000;
 pub const RCTL_DTYP_SPLIT: u32 = 0x00000400;
-// Multicast offset
+/// Multicast offset
 pub const RCTL_MO_MASK: u32 = 0x00003000;
-// Broadcast accept mode
+/// Broadcast accept mode
 pub const RCTL_BAM: u32 = 0x00008000;
-// Receive buffer size
+/// Receive buffer size
 pub const RCTL_BSIZE_MASK: u32 = 0x00030000;
 pub const RCTL_BSIZE_2048: u32 = 0x00000000;
 pub const RCTL_BSIZE_1024: u32 = 0x00010000;
 pub const RCTL_BSIZE_512: u32 = 0x00020000;
 pub const RCTL_BSIZE_256: u32 = 0x00030000;
-// VLAN filter enable
+/// VLAN filter enable
 pub const RCTL_VFE: u32 = 0x00040000;
-// Canonical form indicator enable
+/// Canonical form indicator enable
 pub const RCTL_CFIEN: u32 = 0x00080000;
-// Canonical form indicator bit value
+/// Canonical form indicator bit value
 pub const RCTL_CFI: u32 = 0x00100000;
-// Discard pause frames
+/// Discard pause frames
 pub const RCTL_DPF: u32 = 0x00400000;
-// Pass MAC control frames
+/// Pass MAC control frames
 pub const RCTL_PMCF: u32 = 0x00800000;
-// Buffer size extension
+/// Buffer size extension
 pub const RCTL_BSEX: u32 = 0x02000000;
-// Strip Ethernet CRC
+/// Strip Ethernet CRC
 pub const RCTL_SECRC: u32 = 0x04000000;
-// Flexible buffer size
+/// Flexible buffer size
 pub const RCTL_FLXBUF_MASK: u32 = 0x78000000;
 pub const RCTL_BSIZE_16384: u32 = RCTL_BSIZE_1024 | RCTL_BSEX;
 pub const RCTL_BSIZE_8192: u32 = RCTL_BSIZE_512 | RCTL_BSEX;
 pub const RCTL_BSIZE_4096: u32 = RCTL_BSIZE_256 | RCTL_BSEX;
 
-// Transmit control enable
+/// Transmit control enable
 pub const TCTL_EN: u32 = 0x00000002;
-// Pad short packets
+/// Pad short packets
 pub const TCTL_PSP: u32 = 0x00000008;
-// Collision threshold
+/// Collision threshold
 pub const TCTL_CT_MASK: u32 = 0x00000ff0;
 pub const TCTL_CT_SHIFT: u32 = 4;
-// Collision distance
+/// Collision distance
 pub const TCTL_COLD_MASK: u32 = 0x003ff000;
 pub const TCTL_COLD_SHIFT: u32 = 12;
-// Software XOFF transmission
+/// Software XOFF transmission
 pub const TCTL_SWXOFF: u32 = 0x00400000;
-// Packet burst enable
+/// Packet burst enable
 pub const TCTL_PBE: u32 = 0x00800000;
-// Re-transmit on late collision
+/// Re-transmit on late collision
 pub const TCTL_RTLC: u32 = 0x01000000;
 
-// Transmit descriptor written back
+/// Transmit descriptor written back
 pub const ICR_TXDW: u32 = 0x00000001;
-// Link status change
+/// Link status change
 pub const ICR_LSC: u32 = 0x00000004;
-// Receive sequence error
+/// Receive sequence error
 pub const ICR_RXSEQ: u32 = 0x00000008;
-// Receive descriptor minimum threshold
+/// Receive descriptor minimum threshold
 pub const ICR_RXDMT0: u32 = 0x00000010;
-// Receive overrun
+/// Receive overrun
 pub const ICR_RXO: u32 = 0x00000040;
-// Receive timer expired
+/// Receive timer expired
 pub const ICR_RXT0: u32 = 0x00000080;
-// MDIO access complete
+/// MDIO access complete
 pub const ICR_MDAC: u32 = 0x00000200;
-// Transmit descriptor low minimum threshold
+/// Transmit descriptor low minimum threshold
 pub const ICR_TXD_LOW: u32 = 0x00008000;
-// Small packet received
+/// Small packet received
 pub const ICR_SRPD: u32 = 0x00010000;
-// ACK frame received
+/// ACK frame received
 pub const ICR_ACK: u32 = 0x0020000;
-// Management frame received
+/// Management frame received
 pub const ICR_MNG: u32 = 0x0040000;
-// Other interrupt
+/// Other interrupt
 pub const ICR_OTHER: u32 = 0x01000000;
-// Interrupt asserted
+/// Interrupt asserted
 pub const ICR_INT: u32 = 0x80000000;
 
-pub const ICR_NORMAL: u32 =
-    ICR_LSC | ICR_RXO | ICR_MDAC | ICR_SRPD | ICR_ACK | ICR_MNG;
+pub const ICR_NORMAL: u32 = ICR_LSC | ICR_RXO | ICR_MDAC | ICR_SRPD | ICR_ACK | ICR_MNG;
 pub const ICR_UP: u32 = ICR_TXDW | ICR_RXSEQ | ICR_RXDMT0 | ICR_RXT0;
 
 pub const RXD_STAT_DD: u8 = 0x01;

+ 480 - 0
src/driver/e1000e/dev.rs

@@ -0,0 +1,480 @@
+use super::defs;
+use super::error::E1000eError;
+use super::rx_desc::RxDescriptorTable;
+use super::tx_desc::TxDescriptorTable;
+use crate::net::netdev::{NetDevice, PhyDevice};
+use crate::net::{LinkSpeed, LinkState, LinkStatus, NetBuffer, NetError};
+use crate::prelude::*;
+use crate::sync::fence::memory_barrier;
+use crate::{kernel::interrupt::register_irq_handler, net::Mac};
+use alloc::sync::Arc;
+use core::ops::DerefMut;
+use core::ptr::NonNull;
+use eonix_hal::mm::ArchPhysAccess;
+use eonix_mm::address::{Addr, PAddr, PRange, PhysAccess};
+use eonix_sync::{SpinIrq, WaitList};
+
+pub struct Registers(NonNull<()>);
+
+unsafe impl Send for Registers {}
+unsafe impl Sync for Registers {}
+
+struct Stats {
+    packet_rx: usize,
+    packet_tx: usize,
+    byte_rx: usize,
+    byte_tx: usize,
+    /// Multicast packets received
+    mprx: usize,
+}
+
+pub struct E1000eInner {
+    up: bool,
+    speed_megs: Option<u32>,
+    mac: Mac,
+
+    stats: Stats,
+
+    regs: Registers,
+    rx_desc_table: RxDescriptorTable,
+    tx_desc_table: TxDescriptorTable,
+}
+
+pub struct E1000eDev {
+    irq_no: usize,
+
+    inner: Spin<E1000eInner>,
+    wait_list: WaitList,
+}
+
+#[derive(Clone)]
+pub struct E1000eHandle {
+    pub dev: Arc<E1000eDev>,
+}
+
+fn test(val: u32, bit: u32) -> bool {
+    (val & bit) == bit
+}
+
+impl Registers {
+    fn new(base: PAddr) -> Self {
+        Self(unsafe { ArchPhysAccess::as_ptr(base) })
+    }
+
+    pub fn read(&self, offset: u32) -> u32 {
+        memory_barrier();
+        let retval = unsafe {
+            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
+            self.0.byte_offset(offset as isize).cast().read_volatile()
+        };
+        memory_barrier();
+        retval
+    }
+
+    pub fn write(&self, offset: u32, value: u32) {
+        memory_barrier();
+        unsafe {
+            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
+            self.0
+                .byte_offset(offset as isize)
+                .cast()
+                .write_volatile(value);
+        }
+        memory_barrier();
+    }
+
+    fn read_as<T: Copy>(&self, offset: u32) -> T {
+        memory_barrier();
+        let retval = unsafe {
+            // SAFETY: The offset is within the bounds of the device's memory-mapped registers.
+            self.0.byte_offset(offset as isize).cast().read_volatile()
+        };
+        memory_barrier();
+        retval
+    }
+}
+
+impl Stats {
+    const fn new() -> Self {
+        Self {
+            packet_rx: 0,
+            packet_tx: 0,
+            byte_rx: 0,
+            byte_tx: 0,
+            mprx: 0,
+        }
+    }
+
+    fn update_tx(&mut self, regs: &Registers) {
+        self.packet_tx += regs.read(defs::REG_GPTC) as usize;
+
+        self.byte_tx +=
+            regs.read(defs::REG_GOTCL) as usize + (regs.read(defs::REG_GOTCH) as usize) << 32;
+    }
+
+    fn update_rx(&mut self, regs: &Registers) {
+        self.packet_rx += regs.read(defs::REG_GPRC) as usize;
+        self.mprx += regs.read(defs::REG_MPRC) as usize;
+
+        self.byte_rx +=
+            regs.read(defs::REG_GORCL) as usize + (regs.read(defs::REG_GORCH) as usize) << 32;
+    }
+}
+
+impl PhyDevice for E1000eHandle {
+    type Device = E1000eInner;
+
+    fn device(&self) -> impl DerefMut<Target = Self::Device> {
+        self.dev.inner.lock_irq()
+    }
+
+    fn state(&self) -> LinkState {
+        let inner = self.dev.inner.lock_irq();
+        let status = if inner.up { LinkStatus::Up } else { LinkStatus::Down };
+        let speed = match inner.speed_megs {
+            Some(speed) => LinkSpeed::SpeedMegs(speed as usize),
+            None => LinkSpeed::SpeedUnknown,
+        };
+
+        LinkState {
+            status,
+            speed,
+            mac: inner.mac,
+        }
+    }
+
+    fn up(&self) -> Result<(), NetError> {
+        self.dev.up()
+    }
+
+    fn down(&self) -> Result<(), NetError> {
+        unimplemented!("E1000e: down() is not implemented yet");
+    }
+}
+
+impl E1000eInner {
+    fn send(&mut self, buf: &dyn NetBuffer) -> Result<(), E1000eError> {
+        self.tx_desc_table.send(&self.regs, buf.as_phys())?;
+
+        Ok(())
+    }
+
+    fn up(&mut self) -> Result<(), E1000eError> {
+        let ctrl = self.regs.read(defs::REG_CTRL);
+        let status = self.regs.read(defs::REG_STAT);
+
+        // check link up
+        if !test(ctrl, defs::CTRL_SLU) || !test(status, defs::STAT_LU) {
+            return Err(E1000eError::DeviceNotReady);
+        }
+
+        // auto negotiation of speed
+        match status & defs::STAT_SPEED_MASK {
+            defs::STAT_SPEED_10M => self.speed_megs = Some(10),
+            defs::STAT_SPEED_100M => self.speed_megs = Some(100),
+            defs::STAT_SPEED_1000M => self.speed_megs = Some(1000),
+            _ => return Err(E1000eError::UnsupportedSpeed),
+        }
+
+        // clear multicast table
+        for i in (0..128).step_by(4) {
+            self.regs.write(defs::REG_MTA + i, 0);
+        }
+
+        self.clear_stats()?;
+
+        // enable interrupts
+        self.regs
+            .write(defs::REG_IMS, defs::ICR_NORMAL | defs::ICR_UP);
+
+        // read to clear any pending interrupts
+        self.regs.read(defs::REG_ICR);
+
+        self.setup_rx()?;
+        self.setup_tx()?;
+
+        self.up = true;
+
+        Ok(())
+    }
+
+    fn on_rx_done(&mut self) {
+        self.stats.update_rx(&self.regs);
+
+        // TODO: Call the wakers if any.
+    }
+
+    fn on_tx_done(&mut self) {
+        self.stats.update_tx(&self.regs);
+
+        // TODO: Wake up the TX wakers if any.
+    }
+
+    fn fire(&mut self) -> Result<(), u32> {
+        let cause = self.regs.read(defs::REG_ICR);
+
+        if !test(cause, defs::ICR_INT) {
+            return Ok(());
+        }
+
+        if test(cause, defs::ICR_TXDW) {
+            println_trace!("trace_net", "E1000e: TX done");
+            self.on_tx_done();
+        }
+
+        if test(cause, defs::ICR_RXT0) {
+            println_trace!("trace_net", "E1000e: RX done");
+            self.on_rx_done();
+        }
+
+        Ok(())
+    }
+
+    fn setup_rx(&mut self) -> Result<(), E1000eError> {
+        let base = self.rx_desc_table.base();
+
+        self.regs.write(defs::REG_RDBAL, base.addr() as u32);
+        self.regs.write(defs::REG_RDBAH, (base.addr() >> 32) as u32);
+
+        self.regs
+            .write(defs::REG_RDLEN, self.rx_desc_table.byte_len());
+
+        self.regs.write(defs::REG_RDH, 0);
+        self.regs.write(defs::REG_RDT, self.rx_desc_table.tail());
+
+        self.regs.write(defs::REG_RDTR, 8); // 8us delay
+
+        self.regs.write(
+            defs::REG_RCTL,
+            defs::RCTL_EN
+                | defs::RCTL_MPE
+                | defs::RCTL_LPE
+                | defs::RCTL_LBM_NO
+                | defs::RCTL_DTYP_LEGACY
+                | defs::RCTL_BAM
+                | defs::RCTL_BSIZE_8192
+                | defs::RCTL_SECRC,
+        );
+
+        Ok(())
+    }
+
+    fn setup_tx(&mut self) -> Result<(), E1000eError> {
+        let base = self.tx_desc_table.base();
+
+        self.regs.write(defs::REG_TDBAL, base.addr() as u32);
+        self.regs.write(defs::REG_TDBAH, (base.addr() >> 32) as u32);
+
+        self.regs
+            .write(defs::REG_TDLEN, self.tx_desc_table.byte_len());
+
+        self.regs.write(defs::REG_TDH, 0);
+        self.regs.write(defs::REG_TDT, self.tx_desc_table.tail());
+
+        self.regs.write(
+            defs::REG_TCTL,
+            defs::TCTL_EN
+                | defs::TCTL_PSP
+                | (15 << defs::TCTL_CT_SHIFT)
+                | (64 << defs::TCTL_COLD_SHIFT)
+                | defs::TCTL_RTLC,
+        );
+
+        Ok(())
+    }
+
+    fn reset(&self) -> Result<(), E1000eError> {
+        // disable interrupts so we won't mess things up
+        self.regs.write(defs::REG_IMC, 0xffffffff);
+
+        let ctrl = self.regs.read(defs::REG_CTRL);
+        self.regs.write(defs::REG_CTRL, ctrl | defs::CTRL_GIOD);
+
+        while self.regs.read(defs::REG_STAT) & defs::STAT_GIOE != 0 {
+            // wait for link up
+        }
+
+        let ctrl = self.regs.read(defs::REG_CTRL);
+        self.regs.write(defs::REG_CTRL, ctrl | defs::CTRL_RST);
+
+        while self.regs.read(defs::REG_CTRL) & defs::CTRL_RST != 0 {
+            // wait for reset
+        }
+
+        // disable interrupts again
+        self.regs.write(defs::REG_IMC, 0xffffffff);
+
+        Ok(())
+    }
+
+    fn clear_stats(&self) -> Result<(), E1000eError> {
+        self.regs.write(defs::REG_COLC, 0);
+        self.regs.write(defs::REG_GPRC, 0);
+        self.regs.write(defs::REG_MPRC, 0);
+        self.regs.write(defs::REG_GPTC, 0);
+        self.regs.write(defs::REG_GORCL, 0);
+        self.regs.write(defs::REG_GORCH, 0);
+        self.regs.write(defs::REG_GOTCL, 0);
+        self.regs.write(defs::REG_GOTCH, 0);
+        Ok(())
+    }
+
+    fn new(base: PAddr) -> Result<Self, E1000eError> {
+        let mut dev = Self {
+            up: false,
+            speed_megs: None,
+            mac: Mac::zeros(),
+            stats: Stats::new(),
+            regs: Registers::new(base),
+            rx_desc_table: RxDescriptorTable::new(32)?,
+            tx_desc_table: TxDescriptorTable::new(32)?,
+        };
+
+        dev.reset()?;
+
+        let mac: [u8; 6] = dev.regs.read_as(0x5400);
+        dev.mac = Mac::new(mac);
+
+        Ok(dev)
+    }
+}
+
+impl Drop for E1000eInner {
+    fn drop(&mut self) {
+        assert!(!self.up, "E1000e device is still up when being dropped");
+    }
+}
+
+impl E1000eDev {
+    pub fn create(irq_no: usize, base: PAddr) -> Result<NetDevice<E1000eHandle>, E1000eError> {
+        let dev_handle = E1000eHandle {
+            dev: Arc::new(Self {
+                irq_no,
+                inner: Spin::new(E1000eInner::new(base)?),
+                wait_list: WaitList::new(),
+            }),
+        };
+
+        Ok(NetDevice::new(dev_handle))
+    }
+
+    fn up(self: &Arc<Self>) -> Result<(), NetError> {
+        self.inner.lock_irq().up()?;
+
+        let dev = self.clone();
+        register_irq_handler(self.irq_no as i32, move || {
+            dev.inner
+                .lock()
+                .fire()
+                .expect("e1000e: failed to handle interrupt");
+        })
+        .map_err(|code| NetError::SystemError(code, "Cannot register IRQ handler"))?;
+
+        Ok(())
+    }
+}
+
+pub struct RxToken<'a, 'r> {
+    table: &'a mut RxDescriptorTable,
+    regs: &'r Registers,
+}
+
+pub struct TxToken<'a, 'r> {
+    table: &'a mut TxDescriptorTable,
+    regs: &'r Registers,
+}
+
+impl smoltcp::phy::RxToken for RxToken<'_, '_> {
+    fn consume<R, F: FnOnce(&[u8]) -> R>(self, f: F) -> R {
+        let buf = self
+            .table
+            .received(&self.regs)
+            .next()
+            .expect("There should be a packet available");
+
+        f(buf.as_bytes())
+    }
+}
+
+impl smoltcp::phy::TxToken for TxToken<'_, '_> {
+    fn consume<R, F: FnOnce(&mut [u8]) -> R>(self, len: usize, f: F) -> R {
+        let mut buffer = [0; 1536];
+        let result = f(&mut buffer[..len]);
+
+        let buffer_addr = unsafe {
+            // SAFETY: `buffer` is in the kernel space and a mutable reference can't be null.
+            ArchPhysAccess::from_ptr(NonNull::new_unchecked(&mut buffer))
+        };
+
+        self.table
+            .send(self.regs, PRange::from(buffer_addr).grow(len))
+            .expect("There should be space in TX buffer");
+
+        result
+    }
+}
+
+impl smoltcp::phy::Device for E1000eInner {
+    type RxToken<'a>
+        = RxToken<'a, 'a>
+    where
+        Self: 'a;
+
+    type TxToken<'a>
+        = TxToken<'a, 'a>
+    where
+        Self: 'a;
+
+    fn receive(
+        &mut self,
+        _timestamp: smoltcp::time::Instant,
+    ) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
+        if !self.up {
+            return None; // Device is not up
+        }
+
+        if !self.rx_desc_table.has_data(&self.regs) {
+            return None; // No new packets
+        }
+
+        if !self.tx_desc_table.can_send(&self.regs) {
+            return None; // No space in TX buffer
+        }
+
+        Some((
+            RxToken {
+                table: &mut self.rx_desc_table,
+                regs: &self.regs,
+            },
+            TxToken {
+                table: &mut self.tx_desc_table,
+                regs: &self.regs,
+            },
+        ))
+    }
+
+    fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
+        if !self.up {
+            return None; // Device is not up
+        }
+
+        if !self.tx_desc_table.can_send(&self.regs) {
+            return None; // No space in TX buffer
+        }
+
+        Some(TxToken {
+            table: &mut self.tx_desc_table,
+            regs: &self.regs,
+        })
+    }
+
+    fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
+        let mut caps = smoltcp::phy::DeviceCapabilities::default();
+
+        caps.medium = smoltcp::phy::Medium::Ethernet;
+        caps.max_transmission_unit = 1536;
+        caps.max_burst_size = Some(32);
+
+        caps
+    }
+}

+ 37 - 0
src/driver/e1000e/error.rs

@@ -0,0 +1,37 @@
+use crate::{
+    kernel::constants::{EAGAIN, EINVAL, EIO, EOVERFLOW},
+    net::NetError,
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum E1000eError {
+    TooManyDescriptors,
+    TooBigDataSize,
+    NoFreeDescriptor,
+    DeviceNotReady,
+    UnsupportedSpeed,
+}
+
+impl From<E1000eError> for u32 {
+    fn from(err: E1000eError) -> Self {
+        match err {
+            E1000eError::TooManyDescriptors => EINVAL,
+            E1000eError::TooBigDataSize => EOVERFLOW,
+            E1000eError::NoFreeDescriptor => EAGAIN,
+            E1000eError::DeviceNotReady => EIO,
+            E1000eError::UnsupportedSpeed => EINVAL,
+        }
+    }
+}
+
+impl From<E1000eError> for NetError {
+    fn from(err: E1000eError) -> Self {
+        match err {
+            E1000eError::TooManyDescriptors => NetError::Unsupported,
+            E1000eError::TooBigDataSize => NetError::Unsupported,
+            E1000eError::NoFreeDescriptor => NetError::DeviceBusy,
+            E1000eError::DeviceNotReady => NetError::IoFailure,
+            E1000eError::UnsupportedSpeed => NetError::Unsupported,
+        }
+    }
+}

+ 183 - 0
src/driver/e1000e/rx_desc.rs

@@ -0,0 +1,183 @@
+use super::{dev::Registers, error::E1000eError};
+use crate::{
+    driver::e1000e::defs::{REG_RDH, REG_RDT, RXD_STAT_DD},
+    kernel::mem::{AsMemoryBlock, Page},
+};
+use core::{cell::UnsafeCell, ptr::NonNull};
+use eonix_mm::{
+    address::{Addr, PAddr},
+    paging::{PAGE_SIZE, PFN},
+};
+
+#[repr(C)]
+struct RxDescriptor {
+    buffer: u64,
+    length: u16,
+    checksum: u16,
+    status: u8,
+    errors: u8,
+    vlan: u16,
+}
+
+/// Represents a table of RX descriptors for the E1000E network driver.
+///
+/// TODO: impl `Drop` for RxDescriptorTable to free the pages.
+pub struct RxDescriptorTable {
+    tail: u32,
+    len: u32,
+    table: NonNull<[UnsafeCell<RxDescriptor>]>,
+    _table_page: Page,
+}
+
+unsafe impl Send for RxDescriptorTable {}
+unsafe impl Sync for RxDescriptorTable {}
+
+pub struct RxBuffer {
+    buffer: NonNull<[u8]>,
+    _page: Page,
+}
+
+unsafe impl Send for RxBuffer {}
+unsafe impl Sync for RxBuffer {}
+
+impl RxDescriptor {
+    const fn zeroed() -> Self {
+        Self {
+            buffer: 0,
+            length: 0,
+            checksum: 0,
+            status: 0,
+            errors: 0,
+            vlan: 0,
+        }
+    }
+
+    fn zero(&mut self) {
+        *self = Self::zeroed();
+    }
+
+    fn set_buffer(&mut self, page: Page) {
+        self.zero();
+        self.buffer = PAddr::from(page.pfn()).addr() as u64;
+
+        page.into_raw();
+    }
+
+    fn take_buffer(&mut self) -> RxBuffer {
+        let len = self.length as usize;
+        let page = unsafe {
+            // SAFETY: The buffer is guaranteed to be valid as it was set before.
+            Page::from_raw(PFN::from(PAddr::from(self.buffer as usize)))
+        };
+
+        self.zero();
+
+        let buffer_ptr = page.as_memblk().as_byte_ptr();
+        RxBuffer {
+            buffer: NonNull::slice_from_raw_parts(buffer_ptr, len),
+            _page: page,
+        }
+    }
+}
+
+impl RxDescriptorTable {
+    /// Maximum number of descriptors in the RX descriptor table.
+    pub const MAX_DESCS: u32 = 65536;
+
+    pub const fn tail(&self) -> u32 {
+        self.tail
+    }
+
+    pub const fn next_tail(&self) -> u32 {
+        (self.tail + 1) % self.len
+    }
+
+    pub fn new(len: u32) -> Result<Self, E1000eError> {
+        if len > Self::MAX_DESCS {
+            return Err(E1000eError::TooManyDescriptors);
+        }
+
+        let size = len as usize * size_of::<RxDescriptor>();
+        let page_count = size / PAGE_SIZE;
+
+        let table_page = Page::alloc_at_least(page_count);
+        let page_ptr = table_page.as_memblk().as_byte_ptr();
+        let table_ptr = NonNull::slice_from_raw_parts(page_ptr.cast(), len as usize);
+
+        unsafe {
+            let table: &mut [UnsafeCell<RxDescriptor>] = table_ptr.clone().as_mut();
+
+            for entry in table.iter_mut().map(UnsafeCell::get_mut) {
+                entry.set_buffer(Page::alloc());
+            }
+        }
+
+        Ok(Self {
+            tail: len - 1,
+            len,
+            table: table_ptr,
+            _table_page: table_page,
+        })
+    }
+
+    pub fn base(&self) -> PAddr {
+        PAddr::from(self._table_page.pfn())
+    }
+
+    pub fn byte_len(&self) -> u32 {
+        self.len * size_of::<RxDescriptor>() as u32
+    }
+
+    pub fn has_data(&self, regs: &Registers) -> bool {
+        let head = regs.read(REG_RDH);
+        let next_tail = self.next_tail();
+        next_tail != head
+    }
+
+    pub fn received<'b>(
+        &mut self,
+        regs: &'b Registers,
+    ) -> impl Iterator<Item = RxBuffer> + use<'_, 'b> {
+        struct Received<'a, 'b> {
+            table: &'a mut RxDescriptorTable,
+            regs: &'b Registers,
+        }
+
+        impl Iterator for Received<'_, '_> {
+            type Item = RxBuffer;
+
+            fn next(&mut self) -> Option<Self::Item> {
+                if !self.table.has_data(self.regs) {
+                    return None; // No new packets
+                }
+
+                let next_tail = self.table.next_tail();
+
+                let descriptor = unsafe {
+                    // SAFETY: The descriptor at position `tail` belongs to us.
+                    &mut *self.table.table.as_ref()[next_tail as usize].get()
+                };
+
+                debug_assert!(descriptor.status & RXD_STAT_DD != 0, "Descriptor not ready");
+                let rx_buffer = descriptor.take_buffer();
+                descriptor.set_buffer(Page::alloc());
+
+                self.table.tail = next_tail;
+                self.regs.write(REG_RDT, next_tail);
+
+                Some(rx_buffer)
+            }
+        }
+
+        Received { table: self, regs }
+    }
+}
+
+impl RxBuffer {
+    pub fn as_bytes(&self) -> &[u8] {
+        unsafe {
+            // SAFETY: The buffer is guaranteed to be valid as it was set before.
+            self.buffer.as_ref()
+        }
+    }
+}

+ 157 - 0
src/driver/e1000e/tx_desc.rs

@@ -0,0 +1,157 @@
+use eonix_mm::{
+    address::{Addr, PAddr, PRange},
+    paging::PAGE_SIZE,
+};
+
+use crate::{
+    driver::e1000e::defs::{REG_TDT, TXD_STAT_DD},
+    kernel::mem::{AsMemoryBlock, Page},
+};
+use core::{cell::UnsafeCell, ptr::NonNull};
+
+use super::{
+    defs::{REG_TDH, TXD_CMD_EOP, TXD_CMD_IFCS, TXD_CMD_RS},
+    dev::Registers,
+    error::E1000eError,
+};
+
+#[repr(C)]
+struct TxDescriptor {
+    buffer: u64,
+    length: u16,
+    cso: u8, // Checksum offset
+    cmd: u8,
+    status: u8,
+    css: u8, // Checksum start
+    vlan: u16,
+}
+
+/// Represents a table of RX descriptors for the E1000E network driver.
+pub struct TxDescriptorTable {
+    tail: u32,
+    len: u32,
+    table: NonNull<[UnsafeCell<TxDescriptor>]>,
+    _table_page: Page,
+}
+
+unsafe impl Send for TxDescriptorTable {}
+unsafe impl Sync for TxDescriptorTable {}
+
+impl TxDescriptor {
+    const fn zeroed() -> Self {
+        Self {
+            buffer: 0,
+            length: 0,
+            cso: 0,
+            cmd: 0,
+            status: 0,
+            css: 0,
+            vlan: 0,
+        }
+    }
+
+    fn zero(&mut self) {
+        *self = Self::zeroed();
+    }
+
+    fn set(&mut self, data: PRange) -> Result<(), E1000eError> {
+        if data.len() > PAGE_SIZE as usize {
+            return Err(E1000eError::TooBigDataSize);
+        }
+
+        self.buffer = data.start().addr() as u64;
+        self.length = data.len() as u16;
+        self.cmd = TXD_CMD_EOP | TXD_CMD_IFCS | TXD_CMD_RS; // End of packet, Insert FCS, Report status.
+        self.status = 0; // Clear status.
+
+        Ok(())
+    }
+}
+
+impl TxDescriptorTable {
+    /// Maximum number of descriptors in the TX descriptor table.
+    pub const MAX_DESCS: u32 = 65536;
+
+    pub const fn tail(&self) -> u32 {
+        self.tail
+    }
+
+    pub const fn next_tail(&self) -> u32 {
+        (self.tail + 1) % self.len
+    }
+
+    pub fn new(len: u32) -> Result<Self, E1000eError> {
+        if len > Self::MAX_DESCS {
+            return Err(E1000eError::TooManyDescriptors);
+        }
+
+        let size = len as usize * size_of::<TxDescriptor>();
+        let page_count = size / PAGE_SIZE;
+
+        let table_page = Page::alloc_at_least(page_count);
+        let page_ptr = table_page.as_memblk().as_byte_ptr();
+        let table_ptr = NonNull::slice_from_raw_parts(page_ptr.cast(), len as usize);
+
+        unsafe {
+            let table: &mut [UnsafeCell<TxDescriptor>] = table_ptr.clone().as_mut();
+
+            for entry in table.iter_mut().map(UnsafeCell::get_mut) {
+                entry.zero();
+                entry.status = TXD_STAT_DD; // Mark descriptor as ready.
+            }
+        }
+
+        Ok(Self {
+            tail: 0,
+            len,
+            table: NonNull::slice_from_raw_parts(page_ptr.cast(), len as usize),
+            _table_page: table_page,
+        })
+    }
+
+    pub fn base(&self) -> PAddr {
+        PAddr::from(self._table_page.pfn())
+    }
+
+    pub fn byte_len(&self) -> u32 {
+        self.len * size_of::<TxDescriptor>() as u32
+    }
+
+    pub fn can_send(&self, regs: &Registers) -> bool {
+        let head = regs.read(REG_TDH);
+        let next_tail = self.next_tail();
+        head != next_tail
+    }
+
+    pub fn send(&mut self, regs: &Registers, data: PRange) -> Result<(), E1000eError> {
+        if !self.can_send(regs) {
+            return Err(E1000eError::NoFreeDescriptor);
+        }
+
+        let next_tail = self.next_tail();
+
+        let descriptor = unsafe {
+            // SAFETY: The descriptor at position `tail` belongs to us.
+            &mut *self.table.as_ref()[self.tail() as usize].get()
+        };
+
+        debug_assert!(descriptor.status & TXD_STAT_DD != 0, "Descriptor not ready");
+
+        descriptor.zero();
+        descriptor.set(data)?;
+
+        self.tail = next_tail;
+        regs.write(REG_TDT, next_tail);
+
+        while regs.read(REG_TDH) != next_tail {
+            core::hint::spin_loop();
+        }
+
+        debug_assert!(
+            descriptor.status & TXD_STAT_DD != 0,
+            "Descriptor not ready after sending"
+        );
+
+        Ok(())
+    }
+}

+ 15 - 0
src/kernel/syscall/net.rs

@@ -2,8 +2,23 @@ use crate::kernel::constants::EINVAL;
 use crate::prelude::*;
 use posix_types::syscall_no::*;
 
+const AF_INET: u32 = 2; // IPv4
+
+const SOCK_STREAM: u32 = 1; // TCP
+const SOCK_RAW: u32 = 3; // Raw socket
+
+const IPPROTO_TCP: u32 = 6; // TCP protocol
+const IPPROTO_ICMP: u32 = 1; // ICMP protocol
+
 #[eonix_macros::define_syscall(SYS_SOCKET)]
 fn socket(_domain: u32, _socket_type: u32, _protocol: u32) -> KResult<u32> {
+    println_info!(
+        "socket called with domain: {}, type: {}, protocol: {}",
+        _domain,
+        _socket_type,
+        _protocol
+    );
+
     Err(EINVAL)
 }
 

+ 8 - 0
src/net.rs

@@ -1 +1,9 @@
+mod buffer;
+mod error;
+mod link_info;
 pub mod netdev;
+mod socket_set;
+
+pub use buffer::NetBuffer;
+pub use error::NetError;
+pub use link_info::{LinkId, LinkSpeed, LinkState, LinkStatus, Mac};

+ 5 - 0
src/net/buffer.rs

@@ -0,0 +1,5 @@
+use eonix_mm::address::PRange;
+
+pub trait NetBuffer {
+    fn as_phys(&self) -> PRange;
+}

+ 8 - 0
src/net/error.rs

@@ -0,0 +1,8 @@
+#[derive(Clone, Copy)]
+pub enum NetError {
+    SystemError(u32, &'static str),
+    IoFailure,
+    DeviceBusy,
+    Unsupported,
+    AlreadyRegistered,
+}

+ 77 - 0
src/net/link_info.rs

@@ -0,0 +1,77 @@
+use core::{
+    fmt,
+    sync::atomic::{AtomicUsize, Ordering},
+};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct LinkId(usize);
+
+#[derive(Debug, Clone, Copy)]
+pub enum LinkStatus {
+    Up,
+    Down,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum LinkSpeed {
+    SpeedUnknown,
+    SpeedMegs(usize),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct Mac([u8; 6]);
+
+pub struct LinkState {
+    pub status: LinkStatus,
+    pub speed: LinkSpeed,
+    pub mac: Mac,
+}
+
+impl LinkId {
+    pub fn new() -> Self {
+        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
+        Self(NEXT_ID.fetch_add(1, Ordering::Relaxed))
+    }
+}
+
+impl LinkState {
+    pub fn new() -> Self {
+        Self {
+            status: LinkStatus::Down,
+            speed: LinkSpeed::SpeedUnknown,
+            mac: Mac::zeros(),
+        }
+    }
+}
+
+impl Mac {
+    pub const fn zeros() -> Self {
+        Self([0; 6])
+    }
+
+    pub const fn new(mac: [u8; 6]) -> Self {
+        Self(mac)
+    }
+}
+
+impl fmt::Debug for Mac {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "MAC({self:?})",)
+    }
+}
+
+impl fmt::Display for Mac {
+    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]
+        )
+    }
+}
+
+impl AsRef<[u8; 6]> for Mac {
+    fn as_ref(&self) -> &[u8; 6] {
+        &self.0
+    }
+}

+ 223 - 53
src/net/netdev.rs

@@ -1,79 +1,249 @@
-use core::sync::atomic::{AtomicU32, Ordering};
-
-use crate::kernel::constants::EFAULT;
-use alloc::{
-    collections::btree_map::{BTreeMap, Entry},
-    sync::Arc,
-};
+use super::{LinkId, LinkState, NetError};
+use crate::kernel::timer::{sleep, Ticks};
+use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec, vec::Vec};
+use core::ops::{Deref, DerefMut};
+use eonix_log::println_trace;
 use eonix_sync::Spin;
+use smoltcp::{
+    iface::{Config, Interface, PollIngressSingleResult, PollResult, SocketSet},
+    phy::Device,
+    socket::Socket,
+    time::Instant,
+    wire::{EthernetAddress, IpAddress},
+};
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum LinkStatus {
-    Up,
-    Down,
+static NETDEVS: Spin<Vec<Arc<dyn AnyNetDevice>>> = Spin::new(Vec::new());
+static ADDRESS_DEVS: Spin<BTreeMap<IpAddress, Arc<dyn BindSocket>>> = Spin::new(BTreeMap::new());
+
+pub trait AnyNetDevice: Send + Sync {
+    fn id(&self) -> LinkId;
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum LinkSpeed {
-    SpeedUnknown,
-    Speed10M,
-    Speed100M,
-    Speed1000M,
+pub trait PhyDevice: Send + Sync {
+    type Device: Device;
+
+    fn device(&self) -> impl DerefMut<Target = Self::Device>;
+    fn state(&self) -> LinkState;
+
+    fn up(&self) -> Result<(), NetError>;
+    fn down(&self) -> Result<(), NetError>;
 }
 
-pub type Mac = [u8; 6];
+pub trait BindSocket: Send + Sync {
+    fn bind(&self, address: IpAddress, socket: Socket) -> Result<(), NetError>;
+}
 
-#[allow(dead_code)]
-pub trait Netdev: Send {
-    fn up(&mut self) -> Result<(), u32>;
-    fn send(&mut self, data: &[u8]) -> Result<(), u32>;
-    fn fire(&mut self) -> Result<(), u32>;
+pub struct NetDeviceInner<P>
+where
+    P: PhyDevice,
+{
+    id: LinkId,
+    link_state: Spin<LinkState>,
 
-    fn link_status(&self) -> LinkStatus;
-    fn link_speed(&self) -> LinkSpeed;
-    fn mac(&self) -> Mac;
+    phy: P,
+    interface: Spin<Interface>,
+    sockets: Spin<SocketSet<'static>>,
+    addresses: Spin<Vec<IpAddress>>,
+}
 
-    fn id(&self) -> u32;
+#[derive(Clone)]
+pub struct NetDevice<P>
+where
+    P: PhyDevice,
+{
+    _inner: Arc<NetDeviceInner<P>>,
 }
 
-impl PartialEq for dyn Netdev {
-    fn eq(&self, other: &Self) -> bool {
-        self.id() == other.id()
+impl<P> Deref for NetDevice<P>
+where
+    P: PhyDevice,
+{
+    type Target = NetDeviceInner<P>;
+
+    fn deref(&self) -> &Self::Target {
+        &self._inner
     }
 }
 
-impl Eq for dyn Netdev {}
-
-impl PartialOrd for dyn Netdev {
-    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
-        Some(self.cmp(other))
+impl<P> AnyNetDevice for NetDeviceInner<P>
+where
+    P: PhyDevice,
+{
+    fn id(&self) -> LinkId {
+        self.id
     }
 }
 
-impl Ord for dyn Netdev {
-    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
-        self.id().cmp(&other.id())
+impl<P> NetDevice<P>
+where
+    P: PhyDevice + 'static,
+{
+    pub fn register(&self) -> Result<(), NetError> {
+        let mut netdevs = NETDEVS.lock();
+        if let Some(_) = netdevs.iter().find(|dev| dev.id() == self.id) {
+            return Err(NetError::AlreadyRegistered);
+        }
+        netdevs.push(self._inner.clone());
+        Ok(())
     }
 }
 
-static NETDEVS_ID: AtomicU32 = AtomicU32::new(0);
-static NETDEVS: Spin<BTreeMap<u32, Arc<Spin<dyn Netdev>>>> = Spin::new(BTreeMap::new());
+impl<P> NetDevice<P>
+where
+    P: PhyDevice,
+{
+    pub fn new(phy: P) -> Self {
+        let state = phy.state();
+        let config = Config::new(EthernetAddress::from_bytes(state.mac.as_ref()).into());
 
-pub fn alloc_id() -> u32 {
-    NETDEVS_ID.fetch_add(1, Ordering::SeqCst)
-}
+        let interface = Interface::new(
+            config,
+            &mut *phy.device(),
+            Instant::ZERO + Ticks::since_boot().into(),
+        );
 
-pub fn register_netdev(netdev: impl Netdev + 'static) -> Result<Arc<Spin<dyn Netdev>>, u32> {
-    match NETDEVS.lock().entry(netdev.id()) {
-        Entry::Vacant(entry) => {
-            let netdev = Arc::new(Spin::new(netdev));
-            entry.insert(netdev.clone());
-            Ok(netdev)
+        Self {
+            _inner: Arc::new(NetDeviceInner {
+                id: LinkId::new(),
+                link_state: Spin::new(state),
+                phy,
+                interface: Spin::new(interface),
+                sockets: Spin::new(SocketSet::new(vec![])),
+                addresses: Spin::new(vec![]),
+            }),
         }
-        Entry::Occupied(_) => Err(EFAULT),
     }
-}
 
-pub fn get_netdev(id: u32) -> Option<Arc<Spin<dyn Netdev>>> {
-    NETDEVS.lock().get(&id).map(|netdev| netdev.clone())
+    pub fn update_link_state(&self, link_state: LinkState) {
+        *self.link_state.lock() = link_state;
+    }
+
+    pub fn up(&self) -> Result<(), NetError> {
+        self.phy.up()
+    }
+
+    pub fn down(&self) -> Result<(), NetError> {
+        self.phy.down()
+    }
+
+    pub async fn worker(&self) {
+        loop {
+            const POLL_IN_MAX: usize = 4096;
+
+            let mut phy = self.phy.device();
+            let mut interface = self.interface.lock();
+            let mut sockets = self.sockets.lock();
+            let now = Instant::ZERO + Ticks::since_boot().into();
+
+            let mut result = PollResult::None;
+
+            for _ in 0..POLL_IN_MAX {
+                match interface.poll_ingress_single(now, &mut *phy, &mut sockets) {
+                    PollIngressSingleResult::None => break,
+                    PollIngressSingleResult::PacketProcessed => {}
+                    PollIngressSingleResult::SocketStateChanged => {
+                        result = PollResult::SocketStateChanged;
+                    }
+                }
+            }
+
+            if let PollResult::SocketStateChanged =
+                interface.poll_egress(now, &mut *phy, &mut sockets)
+            {
+                result = PollResult::SocketStateChanged;
+            }
+
+            if let PollResult::None = result {
+                let Some(duration_before_next_poll) = interface.poll_delay(now, &sockets) else {
+                    continue;
+                };
+
+                sleep(duration_before_next_poll.into()).await;
+                continue;
+            }
+
+            println_trace!("trace_net", "Socket state changed");
+
+            for (_, socket) in sockets.iter_mut() {
+                match socket {
+                    Socket::Udp(socket) => todo!(),
+                    Socket::Tcp(socket) => {
+                        let mut active = false;
+                        if socket.is_active() && !active {
+                            println_trace!("trace_net", "TCP socket is active");
+                        } else if !socket.is_active() && active {
+                            println_trace!("trace_net", "TCP socket is no longer active");
+                        }
+                        active = socket.is_active();
+
+                        if socket.can_recv() {
+                            socket
+                                .recv(|buffer| {
+                                    #[allow(unused_variables)]
+                                    let string = str::from_utf8(buffer);
+                                    println_trace!(
+                                        "trace_net",
+                                        "Received data on TCP socket: {string:#?}"
+                                    );
+
+                                    (buffer.len(), ())
+                                })
+                                .expect("Failed to receive data on TCP socket");
+                        }
+
+                        if socket.can_send() {
+                            socket
+                                .send(|buffer| {
+                                    let data =
+                                        b"GET / HTTP/1.1\r\nHost: self.greatbridf.com\r\n\r\n";
+                                    buffer[..data.len()].copy_from_slice(data);
+
+                                    (data.len(), ())
+                                })
+                                .expect("Failed to send data on TCP socket");
+                        }
+                    }
+                    Socket::Dhcpv4(socket) => match socket.poll() {
+                        Some(smoltcp::socket::dhcpv4::Event::Configured(config)) => {
+                            println_trace!("trace_net", "DHCP configured: {:?}", config);
+
+                            interface.update_ip_addrs(|addrs| {
+                                addrs.clear();
+                                addrs.push(config.address.into()).unwrap();
+                            });
+
+                            if let Some(router) = config.router {
+                                interface
+                                    .routes_mut()
+                                    .add_default_ipv4_route(router)
+                                    .unwrap();
+                            } else {
+                                interface.routes_mut().remove_default_ipv4_route();
+                            }
+
+                            #[allow(unused_variables)]
+                            for dns in config.dns_servers {
+                                // TODO: export DNS servers to `/etc/resolv.conf`
+                                println_trace!("trace_net", "Found DNS server: {:?}", dns);
+                            }
+                        }
+                        Some(smoltcp::socket::dhcpv4::Event::Deconfigured) => {
+                            println_trace!("trace_net", "DHCP deconfigured");
+                        }
+                        None => {}
+                    },
+                    Socket::Dns(socket) => todo!(),
+                }
+            }
+        }
+
+        // sockets
+        //     .get_mut::<smoltcp::socket::tcp::Socket>(tcp)
+        //     .connect(
+        //         iface.context(),
+        //         (IpAddress::from(Ipv4Addr::new(212, 50, 246, 131)), 80),
+        //         56789,
+        //     )
+        //     .expect("Failed to connect TCP socket");
+    }
 }

+ 25 - 0
src/net/socket_set.rs

@@ -0,0 +1,25 @@
+use super::netdev::AnyNetDevice;
+use alloc::{collections::BTreeSet, sync::Arc};
+use core::marker::PhantomData;
+use smoltcp::{iface::SocketHandle, socket::AnySocket, wire::IpAddress};
+
+pub struct BoundSocket {
+    address: IpAddress,
+    port: u16,
+
+    handle: SocketHandle,
+    net_device: Arc<dyn AnyNetDevice>,
+}
+
+pub enum Socket {
+    Unbound,
+    Bound(Arc<BoundSocket>),
+}
+
+pub struct SocketSet<T>
+where
+    T: for<'a> AnySocket<'a>,
+{
+    sockets: BTreeSet<Arc<BoundSocket>>,
+    _phantom: PhantomData<T>,
+}

+ 1 - 1
src/prelude.rs

@@ -44,7 +44,7 @@ macro_rules! impl_any {
 
 macro_rules! addr_of_mut_field {
     ($pointer:expr, $field:ident) => {
-        core::ptr::addr_of_mut!((*$pointer).$field)
+        core::ptr::addr_of_mut!((&mut (*$pointer)).$field)
     };
 }