From 8e9bb56a29f4d1920c57fc0a87a9a5844b054ecc Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Mon, 31 Aug 2026 02:52:00 +0200 Subject: [PATCH] nic: send a frame with the layout it actually has tcpip_output() decides whether to splice in the 802.1Q tag, and that decision also moves the frame: the header is shifted forward over its padding, so a tagged frame starts at uip_buf with the q_frame layout, while an untagged one keeps the padding and the nonq_frame layout. nic_tx_packet() took that decision a second time, from management_vlan alone. That agreed while the sender suppressed the management VLAN around the transmission, but not since the tag is skipped per frame for a CPU-tagged one: the descriptor then still sits behind the padding while the transfer is set up for the shifted layout. The frame goes out four bytes early and its length is read from the offset where tx_seq and chksum_flags live, so a sixty byte BPDU is sent as around 1800 bytes of whatever follows it. Looped back it is no longer a BPDU, the port hears nothing, auto edge promotes it and the loop stays open. Record the decision where it is taken and let the transfer follow it. A variable rather than an argument because internal RAM is full once the aggregation module shares the image: the overlay area ends at 0x7f, and an argument or any temporary for the condition no longer fits. --- rtlplayground.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/rtlplayground.c b/rtlplayground.c index b63eed1..23e93fa 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -118,6 +118,7 @@ __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2]; __xdata uint16_t rx_packet_vlan; __xdata uint16_t management_vlan; +__xdata bool frame_tagged; __xdata uint8_t tx_seq; __xdata uint8_t stp_enabled; @@ -711,13 +712,11 @@ void nic_tx_packet(uint16_t ring_ptr) uint16_t len; uint16_t guard = 0; - /* If we have a management VLAN, we have inserted a dot1Q-tag into the frame and - * the frame starts at the beginning of uip_buf with the RTL TX descriptor, - * otherwise the frame is a normal Ethernet frame which starts with - * an RTL TX descriptor being padded at the beginning, in the second case - * we need to skip the padding for the sending of the frame. + /* A frame that got a dot1Q tag was shifted forward over its padding, so it + * starts at uip_buf and carries the q_frame layout. One that did not keeps + * the padding in front and the nonq_frame layout, so the padding is skipped. */ - if (management_vlan) { + if (frame_tagged) { SFR_NIC_DATA_U16LE = (uint16_t) uip_buf; len = FRAME_Q->len; /* @@ -1122,7 +1121,9 @@ void tcpip_output(void) // For the management VLAN we insert an 802.1Q VLAN tag, but never into a // CPU-tagged frame, where the ASIC expects its tag right behind the addresses + frame_tagged = false; if (management_vlan && FRAME_ETHERTYPE != HTONS(RTL_FRAME_TAG_ID)) { + frame_tagged = true; // Shift the ethernet header before the HW type including the rtl_frame_desc to the beginning of uip_buf // to allow space to insert the dot 1Q tag for (uint8_t i = 0; i < sizeof(struct q_frame) - DOT_1Q_TAG_SIZE; i++)