Patchwork [v2,2/2] rtl8139: add vlan tag extraction

login
register
mail settings
Submitter Benjamin Poirier
Date Nov. 9, 2010, 1:46 a.m.
Message ID <1289267181-20613-2-git-send-email-benjamin.poirier@polymtl.ca>
Download mbox | patch
Permalink /patch/70486/
State New
Headers show

Comments

Benjamin Poirier - Nov. 9, 2010, 1:46 a.m.
Add support to the emulated hardware to remove vlan tags in packets
going from the network to the guest.

Signed-off-by: Benjamin Poirier <benjamin.poirier@polymtl.ca>
Cc: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>

---
Changes since v1:
* moved the debug print statement inside the if block and reworded
  accordingly. (as suggested by Igor)

AFAIK, extraction is optional to get vlans working. The driver
requests rx detagging but should not assume that it was done. Under
Linux, the mac layer will catch the vlan ethertype. I only added this
part for completeness (to emulate the hardware more truthfully..?).

 hw/rtl8139.c |   40 +++++++++++++++++++++++++++++++++++++---
 1 files changed, 37 insertions(+), 3 deletions(-)

Patch

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index b599945..7762dbb 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -1024,6 +1024,43 @@  static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
 
         target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
 
+        if (s->CpCmd & CPlusRxVLAN && size >= ETHER_ADDR_LEN * 2 +
+            VLAN_HDR_LEN && be16_to_cpup((uint16_t *) &buf[ETHER_ADDR_LEN *
+                2]) == ETHERTYPE_VLAN)
+        {
+            size_t new_size = size - VLAN_HDR_LEN;
+
+            rxdw1 &= ~CP_RX_VLAN_TAG_MASK;
+            rxdw1 |= CP_RX_TAVA |
+                le16_to_cpup((uint16_t *)&buf[ETHER_HDR_LEN]);
+
+            if (buf == buf1 || new_size < MIN_BUF_SIZE)
+            {
+                /* move the end and pad */
+                memmove((uint8_t *)buf + ETHER_ADDR_LEN * 2, buf +
+                    ETHER_ADDR_LEN * 2 + VLAN_HDR_LEN, new_size -
+                    ETHER_ADDR_LEN * 2);
+                memset((uint8_t *)buf + new_size, 0, MIN_BUF_SIZE - new_size);
+                size = MIN_BUF_SIZE;
+            }
+            else
+            {
+                /* move the beginning */
+                memmove((uint8_t *)buf + VLAN_HDR_LEN, buf, ETHER_ADDR_LEN *
+                    2);
+                buf += VLAN_HDR_LEN;
+                size = new_size;
+            }
+
+            DEBUG_PRINT(("RTL8139: C+ Rx mode : extracted vlan tag with tci: "
+                    "%u\n", bswap16(rxdw1 & CP_RX_VLAN_TAG_MASK)));
+        }
+        else
+        {
+            /* reset VLAN tag flag */
+            rxdw1 &= ~CP_RX_TAVA;
+        }
+
         /* receive/copy to target memory */
         cpu_physical_memory_write( rx_addr, buf, size );
 
@@ -1082,9 +1119,6 @@  static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
         rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
         rxdw0 |= (size+4);
 
-        /* reset VLAN tag flag */
-        rxdw1 &= ~CP_RX_TAVA;
-
         /* update ring data */
         val = cpu_to_le32(rxdw0);
         cpu_physical_memory_write(cplus_rx_ring_desc,    (uint8_t *)&val, 4);