Benjamin Poirier writes: > Add support to the emulated hardware to insert vlan tags in packets > going from the guest to the network. > > Signed-off-by: Benjamin Poirier <benjamin.poir...@gmail.com> > Cc: Igor V. Kovalenko <igor.v.kovale...@gmail.com> > Cc: Jason Wang <jasow...@redhat.com> > Cc: Michael S. Tsirkin <m...@redhat.com> > Cc: Blue Swirl <blauwir...@gmail.com> > --- > hw/rtl8139.c | 57 > +++++++++++++++++++++++++++++++++++++++++---------------- > 1 files changed, 41 insertions(+), 16 deletions(-) > > diff --git a/hw/rtl8139.c b/hw/rtl8139.c > index 312d362..11034fb 100644 > --- a/hw/rtl8139.c > +++ b/hw/rtl8139.c > @@ -1821,7 +1821,8 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s) > return ret; > } > > -static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int > size, int do_interrupt) > +static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, > + int do_interrupt, const uint8_t *dot1q_buf) > { > if (!size) > { > @@ -1832,11 +1833,22 @@ static void rtl8139_transfer_frame(RTL8139State *s, > const uint8_t *buf, int size > if (TxLoopBack == (s->TxConfig & TxLoopBack)) > { > DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); > - rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt, NULL); > + rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt, dot1q_buf); > } > else > { > - qemu_send_packet(&s->nic->nc, buf, size); > + if (dot1q_buf) { > + struct iovec iov[] = { > + { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 }, > + { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN }, > + { .iov_base = buf + ETHER_ADDR_LEN * 2, > + .iov_len = size - ETHER_ADDR_LEN * 2 },
Need to protect againt the malicious guest to send packet whose size is less than ETHER_ADDR_LEN*2. Other looks good. > + }; > + > + qemu_sendv_packet(&s->nic->nc, iov, ARRAY_SIZE(iov)); > + } else { > + qemu_send_packet(&s->nic->nc, buf, size); > + } > } > } > > @@ -1870,7 +1882,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int > descriptor) > s->TxStatus[descriptor] |= TxHostOwns; > s->TxStatus[descriptor] |= TxStatOK; > > - rtl8139_transfer_frame(s, txbuffer, txsize, 0); > + rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL); > > DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", > txsize, descriptor)); > > @@ -1997,7 +2009,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) > > cpu_physical_memory_read(cplus_tx_ring_desc, (uint8_t *)&val, 4); > txdw0 = le32_to_cpu(val); > - /* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 > */ > cpu_physical_memory_read(cplus_tx_ring_desc+4, (uint8_t *)&val, 4); > txdw1 = le32_to_cpu(val); > cpu_physical_memory_read(cplus_tx_ring_desc+8, (uint8_t *)&val, 4); > @@ -2009,9 +2020,6 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) > descriptor, > txdw0, txdw1, txbufLO, txbufHI)); > > - /* TODO: the following discard cast should clean clang analyzer output > */ > - (void)txdw1; > - > /* w0 ownership flag */ > #define CP_TX_OWN (1<<31) > /* w0 end of ring flag */ > @@ -2035,9 +2043,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) > /* w0 bits 0...15 : buffer size */ > #define CP_TX_BUFFER_SIZE (1<<16) > #define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1) > -/* w1 tag available flag */ > -#define CP_RX_TAGC (1<<17) > -/* w1 bits 0...15 : VLAN tag */ > +/* w1 add tag flag */ > +#define CP_TX_TAGC (1<<17) > +/* w1 bits 0...15 : VLAN tag (big endian) */ > #define CP_TX_VLAN_TAG_MASK ((1<<16) - 1) > /* w2 low 32bit of Rx buffer ptr */ > /* w3 high 32bit of Rx buffer ptr */ > @@ -2137,13 +2145,13 @@ static int rtl8139_cplus_transmit_one(RTL8139State > *s) > /* update ring data */ > val = cpu_to_le32(txdw0); > cpu_physical_memory_write(cplus_tx_ring_desc, (uint8_t *)&val, 4); > - /* TODO: implement VLAN tagging support, VLAN tag data is read to txdw1 > */ > -// val = cpu_to_le32(txdw1); > -// cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4); > > /* Now decide if descriptor being processed is holding the last segment > of packet */ > if (txdw0 & CP_TX_LS) > { > + uint8_t dot1q_buffer_space[VLAN_HLEN]; > + uint16_t *dot1q_buffer; > + > DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last > segment descriptor\n", descriptor)); > > /* can transfer fully assembled packet */ > @@ -2152,6 +2160,21 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) > int saved_size = s->cplus_txbuffer_offset; > int saved_buffer_len = s->cplus_txbuffer_len; > > + /* create vlan tag */ > + if (txdw1 & CP_TX_TAGC) { > + /* the vlan tag is in BE byte order in the descriptor > + * BE + le_to_cpu() + ~swap()~ = cpu */ > + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : inserting vlan tag with > " > + "tci: %u\n", bswap16(txdw1 & CP_TX_VLAN_TAG_MASK))); > + > + dot1q_buffer = (uint16_t *) dot1q_buffer_space; > + dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q); > + /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */ > + dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK); > + } else { > + dot1q_buffer = NULL; > + } > + > /* reset the card space to protect from recursive call */ > s->cplus_txbuffer = NULL; > s->cplus_txbuffer_offset = 0; > @@ -2305,7 +2328,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) > > int tso_send_size = ETH_HLEN + hlen + tcp_hlen + > chunk_size; > DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring > packet size %d\n", tso_send_size)); > - rtl8139_transfer_frame(s, saved_buffer, > tso_send_size, 0); > + rtl8139_transfer_frame(s, saved_buffer, > tso_send_size, > + 0, (uint8_t *) dot1q_buffer); > > /* add transferred count to TCP sequence number */ > p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + > be32_to_cpu(p_tcp_hdr->th_seq)); > @@ -2378,7 +2402,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) > > DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", > saved_size)); > > - rtl8139_transfer_frame(s, saved_buffer, saved_size, 1); > + rtl8139_transfer_frame(s, saved_buffer, saved_size, 1, > + (uint8_t *) dot1q_buffer); > > /* restore card space if there was no recursion and reset offset */ > if (!s->cplus_txbuffer) > -- > 1.7.2.3 >