From b5d1ba1bcad6c44ad3929b8fa6851e00f153d228 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Thu, 9 Jul 2026 11:24:56 +0300 Subject: [PATCH] vlan: parent device integration + networking plan doc update VlanDevice gains devices: Rc> field. send() now forwards tagged frames to parent device via the shared list, instead of dropping them (R43 drop fix) or self-looping (original). Constructor changed: VlanDevice::new(name, parent, vlan_id, devices). netfilter/netcfg/route: direct routes + flush + version + help docs: NETWORKING-IMPROVEMENT-PLAN.md updated with Phase 4 completion status (firewall/conntrack/NAT) and Phase 6 VLAN status. All 31 tests pass. --- netstack/src/link/vlan.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/netstack/src/link/vlan.rs b/netstack/src/link/vlan.rs index 3958712e85..b9d3d7f7fe 100644 --- a/netstack/src/link/vlan.rs +++ b/netstack/src/link/vlan.rs @@ -9,6 +9,7 @@ //! the 4-byte 802.1Q tag (TPID 0x8100 + TCI) before/after the Ethernet //! header on each frame. +use std::cell::RefCell; use std::collections::VecDeque; use std::rc::Rc; @@ -17,13 +18,14 @@ use smoltcp::wire::{ EthernetAddress, EthernetFrame, EthernetProtocol, IpAddress, IpCidr, }; -use super::LinkDevice; +use super::{DeviceList, LinkDevice}; const TPID_8021Q: u16 = 0x8100; pub struct VlanDevice { name: Rc, parent_name: Rc, + devices: Rc>, vlan_id: u16, priority: u8, tag: [u8; 4], @@ -35,7 +37,7 @@ pub struct VlanDevice { } impl VlanDevice { - pub fn new(name: &str, parent_name: &str, vlan_id: u16) -> Self { + pub fn new(name: &str, parent_name: &str, vlan_id: u16, devices: Rc>) -> Self { let tci: u16 = vlan_id & 0x0fff; let tag: [u8; 4] = [ (TPID_8021Q >> 8) as u8, @@ -46,6 +48,7 @@ impl VlanDevice { Self { name: name.into(), parent_name: parent_name.into(), + devices, vlan_id, priority: 0, tag, @@ -117,13 +120,17 @@ impl VlanDevice { } impl LinkDevice for VlanDevice { - fn send(&mut self, next_hop: IpAddress, packet: &[u8], _now: Instant) { - // The VLAN device has no parent device reference, so we cannot - // send the tagged frame out. Log and drop the packet rather than - // creating a self-loop (which would re-deliver the packet to - // recv() and never reach a real interface). - log::debug!("vlan: dropping {} byte frame (no parent device)", packet.len()); - let _ = next_hop; + fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) { + let tagged = self.insert_tag(packet).to_vec(); + // Forward the tagged frame to the parent device by looking it + // up in the shared device list. If the parent doesn't exist or + // isn't ready, drop the packet with a debug log. + if let Some(parent) = self.devices.borrow_mut().get_mut(&self.parent_name) { + parent.send(next_hop, &tagged, now); + } else { + log::debug!("vlan: parent {} not found, dropping {} byte frame", + self.parent_name, packet.len()); + } } fn recv(&mut self, _now: Instant) -> Option<&[u8]> {