-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJaPGoNAAoJEO8Ells5jWIR7lMH/iQrtE4qSCKbdIMM6Qf4ccpS qMV15tZmT2cVpGXWSrDl6xhQ+7BXmQX6buJqyuf97Q1niVJuqnilsmQrYkkh2mR4 0NIunu3t24v0eeKcmIWnT/L7+9/S0h97X5TFQCZYST5W/ZsUYCYN2EaIGQWUN8y+ dSrpJvoxDvFrMv66W5H/Kskm84LL2sqQg76cxawLy7nYF/M6SiRIoovuDSB58ceq iUZd1Jxk8IWPFktiAJ/zc3VKPfVuAomJhNMCNWNFEdDHEBmFe+TxqtsnnCMM22mA fZQCu3eOObW8J+1V/y+5S1g7cpHqUS4tpivQzGEYO6/OWpMPIOYseHIDIYM87G4= =BYlK -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging # gpg: Signature made Fri 22 Dec 2017 02:12:29 GMT # gpg: using RSA key 0xEF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: qemu-doc: Update the deprecation information of -tftp, -bootp, -redir and -smb qemu-doc: The "-net nic" option can be used with "netdev=...", too net: Remove the legacy "-net channel" parameter net: remove unused compute_mcast_idx() function rtl8139: use inline net_crc32() and bitshift instead of compute_mcast_idx() ne2000: use inline net_crc32() and bitshift instead of compute_mcast_idx() ftgmac100: use inline net_crc32() and bitshift instead of compute_mcast_idx() lan9118: use inline net_crc32() and bitshift instead of compute_mcast_idx() opencores_eth: use inline net_crc32() and bitshift instead of compute_mcast_idx() eepro100: use inline net_crc32() and bitshift instead of compute_mcast_idx() sungem: fix multicast filter CRC calculation sunhme: switch sunhme over to use net_crc32_le() eepro100: switch eepro100 e100_compute_mcast_idx() over to use net_crc32() pcnet: switch pcnet over to use net_crc32_le() net: introduce net_crc32_le() function net: move CRC32 calculation from compute_mcast_idx() into its own net_crc32() function e1000: Separate TSO and non-TSO contexts, fixing UDP TX corruption e1000, e1000e: Move per-packet TX offload flags out of context state Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
8671016261
@ -98,7 +98,10 @@ typedef struct E1000State_st {
|
||||
unsigned char data[0x10000];
|
||||
uint16_t size;
|
||||
unsigned char vlan_needed;
|
||||
unsigned char sum_needed;
|
||||
bool cptse;
|
||||
e1000x_txd_props props;
|
||||
e1000x_txd_props tso_props;
|
||||
uint16_t tso_frames;
|
||||
} tx;
|
||||
|
||||
@ -539,35 +542,37 @@ xmit_seg(E1000State *s)
|
||||
uint16_t len;
|
||||
unsigned int frames = s->tx.tso_frames, css, sofar;
|
||||
struct e1000_tx *tp = &s->tx;
|
||||
struct e1000x_txd_props *props = tp->cptse ? &tp->tso_props : &tp->props;
|
||||
|
||||
if (tp->props.tse && tp->props.cptse) {
|
||||
css = tp->props.ipcss;
|
||||
if (tp->cptse) {
|
||||
css = props->ipcss;
|
||||
DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
|
||||
frames, tp->size, css);
|
||||
if (tp->props.ip) { /* IPv4 */
|
||||
if (props->ip) { /* IPv4 */
|
||||
stw_be_p(tp->data+css+2, tp->size - css);
|
||||
stw_be_p(tp->data+css+4,
|
||||
lduw_be_p(tp->data + css + 4) + frames);
|
||||
} else { /* IPv6 */
|
||||
stw_be_p(tp->data+css+4, tp->size - css);
|
||||
}
|
||||
css = tp->props.tucss;
|
||||
css = props->tucss;
|
||||
len = tp->size - css;
|
||||
DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->props.tcp, css, len);
|
||||
if (tp->props.tcp) {
|
||||
sofar = frames * tp->props.mss;
|
||||
DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", props->tcp, css, len);
|
||||
if (props->tcp) {
|
||||
sofar = frames * props->mss;
|
||||
stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */
|
||||
if (tp->props.paylen - sofar > tp->props.mss) {
|
||||
if (props->paylen - sofar > props->mss) {
|
||||
tp->data[css + 13] &= ~9; /* PSH, FIN */
|
||||
} else if (frames) {
|
||||
e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC);
|
||||
}
|
||||
} else /* UDP */
|
||||
} else { /* UDP */
|
||||
stw_be_p(tp->data+css+4, len);
|
||||
if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) {
|
||||
}
|
||||
if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
|
||||
unsigned int phsum;
|
||||
// add pseudo-header length before checksum calculation
|
||||
void *sp = tp->data + tp->props.tucso;
|
||||
void *sp = tp->data + props->tucso;
|
||||
|
||||
phsum = lduw_be_p(sp) + len;
|
||||
phsum = (phsum >> 16) + (phsum & 0xffff);
|
||||
@ -576,13 +581,11 @@ xmit_seg(E1000State *s)
|
||||
tp->tso_frames++;
|
||||
}
|
||||
|
||||
if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) {
|
||||
putsum(tp->data, tp->size, tp->props.tucso,
|
||||
tp->props.tucss, tp->props.tucse);
|
||||
if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
|
||||
putsum(tp->data, tp->size, props->tucso, props->tucss, props->tucse);
|
||||
}
|
||||
if (tp->props.sum_needed & E1000_TXD_POPTS_IXSM) {
|
||||
putsum(tp->data, tp->size, tp->props.ipcso,
|
||||
tp->props.ipcss, tp->props.ipcse);
|
||||
if (tp->sum_needed & E1000_TXD_POPTS_IXSM) {
|
||||
putsum(tp->data, tp->size, props->ipcso, props->ipcss, props->ipcse);
|
||||
}
|
||||
if (tp->vlan_needed) {
|
||||
memmove(tp->vlan, tp->data, 4);
|
||||
@ -614,27 +617,27 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
|
||||
s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
|
||||
if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
|
||||
e1000x_read_tx_ctx_descr(xp, &tp->props);
|
||||
tp->tso_frames = 0;
|
||||
if (tp->props.tucso == 0) { /* this is probably wrong */
|
||||
DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
|
||||
tp->props.tucso = tp->props.tucss + (tp->props.tcp ? 16 : 6);
|
||||
if (le32_to_cpu(xp->cmd_and_length) & E1000_TXD_CMD_TSE) {
|
||||
e1000x_read_tx_ctx_descr(xp, &tp->tso_props);
|
||||
tp->tso_frames = 0;
|
||||
} else {
|
||||
e1000x_read_tx_ctx_descr(xp, &tp->props);
|
||||
}
|
||||
return;
|
||||
} else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
|
||||
// data descriptor
|
||||
if (tp->size == 0) {
|
||||
tp->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8;
|
||||
tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
|
||||
}
|
||||
tp->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
|
||||
tp->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
|
||||
} else {
|
||||
// legacy descriptor
|
||||
tp->props.cptse = 0;
|
||||
tp->cptse = 0;
|
||||
}
|
||||
|
||||
if (e1000x_vlan_enabled(s->mac_reg) &&
|
||||
e1000x_is_vlan_txd(txd_lower) &&
|
||||
(tp->props.cptse || txd_lower & E1000_TXD_CMD_EOP)) {
|
||||
(tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
|
||||
tp->vlan_needed = 1;
|
||||
stw_be_p(tp->vlan_header,
|
||||
le16_to_cpu(s->mac_reg[VET]));
|
||||
@ -643,8 +646,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
}
|
||||
|
||||
addr = le64_to_cpu(dp->buffer_addr);
|
||||
if (tp->props.tse && tp->props.cptse) {
|
||||
msh = tp->props.hdr_len + tp->props.mss;
|
||||
if (tp->cptse) {
|
||||
msh = tp->tso_props.hdr_len + tp->tso_props.mss;
|
||||
do {
|
||||
bytes = split_size;
|
||||
if (tp->size + bytes > msh)
|
||||
@ -653,21 +656,19 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
bytes = MIN(sizeof(tp->data) - tp->size, bytes);
|
||||
pci_dma_read(d, addr, tp->data + tp->size, bytes);
|
||||
sz = tp->size + bytes;
|
||||
if (sz >= tp->props.hdr_len && tp->size < tp->props.hdr_len) {
|
||||
memmove(tp->header, tp->data, tp->props.hdr_len);
|
||||
if (sz >= tp->tso_props.hdr_len
|
||||
&& tp->size < tp->tso_props.hdr_len) {
|
||||
memmove(tp->header, tp->data, tp->tso_props.hdr_len);
|
||||
}
|
||||
tp->size = sz;
|
||||
addr += bytes;
|
||||
if (sz == msh) {
|
||||
xmit_seg(s);
|
||||
memmove(tp->data, tp->header, tp->props.hdr_len);
|
||||
tp->size = tp->props.hdr_len;
|
||||
memmove(tp->data, tp->header, tp->tso_props.hdr_len);
|
||||
tp->size = tp->tso_props.hdr_len;
|
||||
}
|
||||
split_size -= bytes;
|
||||
} while (bytes && split_size);
|
||||
} else if (!tp->props.tse && tp->props.cptse) {
|
||||
// context descriptor TSE is not set, while data descriptor TSE is set
|
||||
DBGOUT(TXERR, "TCP segmentation error\n");
|
||||
} else {
|
||||
split_size = MIN(sizeof(tp->data) - tp->size, split_size);
|
||||
pci_dma_read(d, addr, tp->data + tp->size, split_size);
|
||||
@ -676,14 +677,14 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
|
||||
if (!(txd_lower & E1000_TXD_CMD_EOP))
|
||||
return;
|
||||
if (!(tp->props.tse && tp->props.cptse && tp->size < tp->props.hdr_len)) {
|
||||
if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) {
|
||||
xmit_seg(s);
|
||||
}
|
||||
tp->tso_frames = 0;
|
||||
tp->props.sum_needed = 0;
|
||||
tp->sum_needed = 0;
|
||||
tp->vlan_needed = 0;
|
||||
tp->size = 0;
|
||||
tp->props.cptse = 0;
|
||||
tp->cptse = 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@ -1435,7 +1436,7 @@ static const VMStateDescription vmstate_e1000_full_mac_state = {
|
||||
|
||||
static const VMStateDescription vmstate_e1000 = {
|
||||
.name = "e1000",
|
||||
.version_id = 2,
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = e1000_pre_save,
|
||||
.post_load = e1000_post_load,
|
||||
@ -1461,7 +1462,7 @@ static const VMStateDescription vmstate_e1000 = {
|
||||
VMSTATE_UINT16(tx.props.mss, E1000State),
|
||||
VMSTATE_UINT16(tx.size, E1000State),
|
||||
VMSTATE_UINT16(tx.tso_frames, E1000State),
|
||||
VMSTATE_UINT8(tx.props.sum_needed, E1000State),
|
||||
VMSTATE_UINT8(tx.sum_needed, E1000State),
|
||||
VMSTATE_INT8(tx.props.ip, E1000State),
|
||||
VMSTATE_INT8(tx.props.tcp, E1000State),
|
||||
VMSTATE_BUFFER(tx.header, E1000State),
|
||||
@ -1508,6 +1509,17 @@ static const VMStateDescription vmstate_e1000 = {
|
||||
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
|
||||
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
|
||||
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
|
||||
VMSTATE_UINT8_V(tx.tso_props.ipcss, E1000State, 3),
|
||||
VMSTATE_UINT8_V(tx.tso_props.ipcso, E1000State, 3),
|
||||
VMSTATE_UINT16_V(tx.tso_props.ipcse, E1000State, 3),
|
||||
VMSTATE_UINT8_V(tx.tso_props.tucss, E1000State, 3),
|
||||
VMSTATE_UINT8_V(tx.tso_props.tucso, E1000State, 3),
|
||||
VMSTATE_UINT16_V(tx.tso_props.tucse, E1000State, 3),
|
||||
VMSTATE_UINT32_V(tx.tso_props.paylen, E1000State, 3),
|
||||
VMSTATE_UINT8_V(tx.tso_props.hdr_len, E1000State, 3),
|
||||
VMSTATE_UINT16_V(tx.tso_props.mss, E1000State, 3),
|
||||
VMSTATE_INT8_V(tx.tso_props.ip, E1000State, 3),
|
||||
VMSTATE_INT8_V(tx.tso_props.tcp, E1000State, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
|
@ -556,7 +556,7 @@ static const VMStateDescription e1000e_vmstate_tx = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(props.sum_needed, struct e1000e_tx),
|
||||
VMSTATE_UINT8(sum_needed, struct e1000e_tx),
|
||||
VMSTATE_UINT8(props.ipcss, struct e1000e_tx),
|
||||
VMSTATE_UINT8(props.ipcso, struct e1000e_tx),
|
||||
VMSTATE_UINT16(props.ipcse, struct e1000e_tx),
|
||||
@ -569,7 +569,7 @@ static const VMStateDescription e1000e_vmstate_tx = {
|
||||
VMSTATE_INT8(props.ip, struct e1000e_tx),
|
||||
VMSTATE_INT8(props.tcp, struct e1000e_tx),
|
||||
VMSTATE_BOOL(props.tse, struct e1000e_tx),
|
||||
VMSTATE_BOOL(props.cptse, struct e1000e_tx),
|
||||
VMSTATE_BOOL(cptse, struct e1000e_tx),
|
||||
VMSTATE_BOOL(skip_cp, struct e1000e_tx),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@ -632,18 +632,18 @@ e1000e_rss_parse_packet(E1000ECore *core,
|
||||
static void
|
||||
e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx)
|
||||
{
|
||||
if (tx->props.tse && tx->props.cptse) {
|
||||
if (tx->props.tse && tx->cptse) {
|
||||
net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss);
|
||||
net_tx_pkt_update_ip_checksums(tx->tx_pkt);
|
||||
e1000x_inc_reg_if_not_full(core->mac, TSCTC);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tx->props.sum_needed & E1000_TXD_POPTS_TXSM) {
|
||||
if (tx->sum_needed & E1000_TXD_POPTS_TXSM) {
|
||||
net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0);
|
||||
}
|
||||
|
||||
if (tx->props.sum_needed & E1000_TXD_POPTS_IXSM) {
|
||||
if (tx->sum_needed & E1000_TXD_POPTS_IXSM) {
|
||||
net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt);
|
||||
}
|
||||
}
|
||||
@ -715,13 +715,13 @@ e1000e_process_tx_desc(E1000ECore *core,
|
||||
return;
|
||||
} else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
|
||||
/* data descriptor */
|
||||
tx->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8;
|
||||
tx->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
|
||||
tx->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
|
||||
tx->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
|
||||
e1000e_process_ts_option(core, dp);
|
||||
} else {
|
||||
/* legacy descriptor */
|
||||
e1000e_process_ts_option(core, dp);
|
||||
tx->props.cptse = 0;
|
||||
tx->cptse = 0;
|
||||
}
|
||||
|
||||
addr = le64_to_cpu(dp->buffer_addr);
|
||||
@ -747,8 +747,8 @@ e1000e_process_tx_desc(E1000ECore *core,
|
||||
tx->skip_cp = false;
|
||||
net_tx_pkt_reset(tx->tx_pkt);
|
||||
|
||||
tx->props.sum_needed = 0;
|
||||
tx->props.cptse = 0;
|
||||
tx->sum_needed = 0;
|
||||
tx->cptse = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,8 @@ struct E1000Core {
|
||||
e1000x_txd_props props;
|
||||
|
||||
bool skip_cp;
|
||||
unsigned char sum_needed;
|
||||
bool cptse;
|
||||
struct NetTxPkt *tx_pkt;
|
||||
} tx[E1000E_NUM_QUEUES];
|
||||
|
||||
|
@ -193,7 +193,6 @@ void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy);
|
||||
void e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size);
|
||||
|
||||
typedef struct e1000x_txd_props {
|
||||
unsigned char sum_needed;
|
||||
uint8_t ipcss;
|
||||
uint8_t ipcso;
|
||||
uint16_t ipcse;
|
||||
@ -206,7 +205,6 @@ typedef struct e1000x_txd_props {
|
||||
int8_t ip;
|
||||
int8_t tcp;
|
||||
bool tse;
|
||||
bool cptse;
|
||||
} e1000x_txd_props;
|
||||
|
||||
void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "net/net.h"
|
||||
#include "net/eth.h"
|
||||
#include "hw/nvram/eeprom93xx.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/dma.h"
|
||||
@ -323,32 +324,8 @@ static const uint16_t eepro100_mdi_mask[] = {
|
||||
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
};
|
||||
|
||||
#define POLYNOMIAL 0x04c11db6
|
||||
|
||||
static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
|
||||
|
||||
/* From FreeBSD (locally modified). */
|
||||
static unsigned e100_compute_mcast_idx(const uint8_t *ep)
|
||||
{
|
||||
uint32_t crc;
|
||||
int carry, i, j;
|
||||
uint8_t b;
|
||||
|
||||
crc = 0xffffffff;
|
||||
for (i = 0; i < 6; i++) {
|
||||
b = *ep++;
|
||||
for (j = 0; j < 8; j++) {
|
||||
carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
|
||||
crc <<= 1;
|
||||
b >>= 1;
|
||||
if (carry) {
|
||||
crc = ((crc ^ POLYNOMIAL) | carry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (crc & BITS(7, 2)) >> 2;
|
||||
}
|
||||
|
||||
/* Read a 16 bit control/status (CSR) register. */
|
||||
static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
|
||||
{
|
||||
@ -845,7 +822,8 @@ static void set_multicast_list(EEPRO100State *s)
|
||||
uint8_t multicast_addr[6];
|
||||
pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
|
||||
TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
|
||||
unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr);
|
||||
unsigned mcast_idx = (net_crc32(multicast_addr, ETH_ALEN) &
|
||||
BITS(7, 2)) >> 2;
|
||||
assert(mcast_idx < 64);
|
||||
s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
|
||||
}
|
||||
@ -1681,7 +1659,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
||||
if (s->configuration[21] & BIT(3)) {
|
||||
/* Multicast all bit is set, receive all multicast frames. */
|
||||
} else {
|
||||
unsigned mcast_idx = e100_compute_mcast_idx(buf);
|
||||
unsigned mcast_idx = (net_crc32(buf, ETH_ALEN) & BITS(7, 2)) >> 2;
|
||||
assert(mcast_idx < 64);
|
||||
if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
|
||||
/* Multicast frame is allowed in hash table. */
|
||||
@ -1701,7 +1679,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
||||
rfd_status |= 0x0004;
|
||||
} else if (s->configuration[20] & BIT(6)) {
|
||||
/* Multiple IA bit set. */
|
||||
unsigned mcast_idx = compute_mcast_idx(buf);
|
||||
unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
|
||||
assert(mcast_idx < 64);
|
||||
if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
|
||||
TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
|
||||
|
@ -762,7 +762,7 @@ static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len)
|
||||
}
|
||||
|
||||
/* TODO: this does not seem to work for ftgmac100 */
|
||||
mcast_idx = compute_mcast_idx(buf);
|
||||
mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
|
||||
if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "net/net.h"
|
||||
#include "net/eth.h"
|
||||
#include "hw/devices.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/ptimer.h"
|
||||
@ -504,7 +505,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
|
||||
}
|
||||
} else {
|
||||
/* Hash matching */
|
||||
hash = compute_mcast_idx(addr);
|
||||
hash = net_crc32(addr, ETH_ALEN) >> 26;
|
||||
if (hash & 0x20) {
|
||||
return (s->mac_hashh >> (hash & 0x1f)) & 1;
|
||||
} else {
|
||||
|
@ -23,6 +23,8 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "net/net.h"
|
||||
#include "net/eth.h"
|
||||
#include "ne2000.h"
|
||||
#include "hw/loader.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@ -199,7 +201,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
|
||||
/* multicast */
|
||||
if (!(s->rxcr & 0x08))
|
||||
return size;
|
||||
mcast_idx = compute_mcast_idx(buf);
|
||||
mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
|
||||
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
|
||||
return size;
|
||||
} else if (s->mem[0] == buf[0] &&
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "hw/net/mii.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "net/net.h"
|
||||
#include "net/eth.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "trace.h"
|
||||
|
||||
@ -373,7 +374,7 @@ static ssize_t open_eth_receive(NetClientState *nc,
|
||||
if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) {
|
||||
miss = GET_REGBIT(s, MODER, BRO);
|
||||
} else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) {
|
||||
unsigned mcast_idx = compute_mcast_idx(buf);
|
||||
unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
|
||||
miss = !(s->regs[HASH0 + mcast_idx / 32] &
|
||||
(1 << (mcast_idx % 32)));
|
||||
trace_open_eth_receive_mcast(
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "net/net.h"
|
||||
#include "net/eth.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@ -522,25 +523,6 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
|
||||
be16_to_cpu(hdr->ether_type)); \
|
||||
} while (0)
|
||||
|
||||
#define MULTICAST_FILTER_LEN 8
|
||||
|
||||
static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
|
||||
{
|
||||
#define LNC_POLYNOMIAL 0xEDB88320UL
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
int idx, bit;
|
||||
uint8_t data;
|
||||
|
||||
for (idx = 0; idx < 6; idx++) {
|
||||
for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
|
||||
crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
|
||||
data >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
#undef LNC_POLYNOMIAL
|
||||
}
|
||||
|
||||
#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
|
||||
|
||||
/* generated using the AUTODIN II polynomial
|
||||
@ -656,7 +638,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
|
||||
s->csr[10] & 0xff, s->csr[10] >> 8,
|
||||
s->csr[11] & 0xff, s->csr[11] >> 8
|
||||
};
|
||||
int index = lnc_mchash(hdr->ether_dhost) >> 26;
|
||||
int index = net_crc32_le(hdr->ether_dhost, ETH_ALEN) >> 26;
|
||||
return !!(ladr[index >> 3] & (1 << (index & 7)));
|
||||
}
|
||||
return 0;
|
||||
|
@ -882,7 +882,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
|
||||
return size;
|
||||
}
|
||||
|
||||
int mcast_idx = compute_mcast_idx(buf);
|
||||
int mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
|
||||
|
||||
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
|
||||
{
|
||||
|
@ -11,12 +11,11 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qemu/log.h"
|
||||
#include "net/net.h"
|
||||
#include "net/eth.h"
|
||||
#include "net/checksum.h"
|
||||
#include "hw/net/mii.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "trace.h"
|
||||
/* For crc32 */
|
||||
#include <zlib.h>
|
||||
|
||||
#define TYPE_SUNGEM "sungem"
|
||||
|
||||
@ -595,7 +594,7 @@ static ssize_t sungem_receive(NetClientState *nc, const uint8_t *buf,
|
||||
}
|
||||
|
||||
/* Get MAC crc */
|
||||
mac_crc = crc32(~0, buf, 6);
|
||||
mac_crc = net_crc32_le(buf, ETH_ALEN);
|
||||
|
||||
/* Packet isn't for me ? */
|
||||
rx_cond = sungem_check_rx_mac(s, buf, mac_crc);
|
||||
|
@ -698,29 +698,6 @@ static inline void sunhme_set_rx_ring_nr(SunHMEState *s, int i)
|
||||
s->erxregs[HME_ERXI_RING >> 2] = ring;
|
||||
}
|
||||
|
||||
#define POLYNOMIAL_LE 0xedb88320
|
||||
static uint32_t sunhme_crc32_le(const uint8_t *p, int len)
|
||||
{
|
||||
uint32_t crc;
|
||||
int carry, i, j;
|
||||
uint8_t b;
|
||||
|
||||
crc = 0xffffffff;
|
||||
for (i = 0; i < len; i++) {
|
||||
b = *p++;
|
||||
for (j = 0; j < 8; j++) {
|
||||
carry = (crc & 0x1) ^ (b & 0x01);
|
||||
crc >>= 1;
|
||||
b >>= 1;
|
||||
if (carry) {
|
||||
crc = crc ^ POLYNOMIAL_LE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#define MIN_BUF_SIZE 60
|
||||
|
||||
static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf,
|
||||
@ -761,7 +738,7 @@ static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf,
|
||||
trace_sunhme_rx_filter_bcast_match();
|
||||
} else if (s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_HENABLE) {
|
||||
/* Didn't match local address, check hash filter */
|
||||
int mcast_idx = sunhme_crc32_le(buf, 6) >> 26;
|
||||
int mcast_idx = net_crc32_le(buf, ETH_ALEN) >> 26;
|
||||
if (!(s->macregs[(HME_MACI_HASHTAB0 >> 2) - (mcast_idx >> 4)] &
|
||||
(1 << (mcast_idx & 0xf)))) {
|
||||
/* Didn't match hash filter */
|
||||
|
@ -227,7 +227,10 @@ NetClientState *net_hub_port_find(int hub_id);
|
||||
|
||||
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
|
||||
|
||||
#define POLYNOMIAL 0x04c11db6
|
||||
#define POLYNOMIAL_BE 0x04c11db6
|
||||
#define POLYNOMIAL_LE 0xedb88320
|
||||
uint32_t net_crc32(const uint8_t *p, int len);
|
||||
uint32_t net_crc32_le(const uint8_t *p, int len);
|
||||
unsigned compute_mcast_idx(const uint8_t *ep);
|
||||
|
||||
#define vmstate_offset_macaddr(_state, _field) \
|
||||
|
@ -36,8 +36,6 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict);
|
||||
|
||||
int net_slirp_redir(const char *redir_str);
|
||||
|
||||
int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret);
|
||||
|
||||
int net_slirp_smb(const char *exported_dir);
|
||||
|
||||
void hmp_info_usernet(Monitor *mon, const QDict *qdict);
|
||||
|
40
net/net.c
40
net/net.c
@ -1565,13 +1565,6 @@ int net_init_clients(void)
|
||||
|
||||
int net_client_parse(QemuOptsList *opts_list, const char *optarg)
|
||||
{
|
||||
#if defined(CONFIG_SLIRP)
|
||||
int ret;
|
||||
if (net_slirp_parse_legacy(opts_list, optarg, &ret)) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!qemu_opts_parse_noisily(opts_list, optarg, true)) {
|
||||
return -1;
|
||||
}
|
||||
@ -1581,25 +1574,48 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg)
|
||||
|
||||
/* From FreeBSD */
|
||||
/* XXX: optimize */
|
||||
unsigned compute_mcast_idx(const uint8_t *ep)
|
||||
uint32_t net_crc32(const uint8_t *p, int len)
|
||||
{
|
||||
uint32_t crc;
|
||||
int carry, i, j;
|
||||
uint8_t b;
|
||||
|
||||
crc = 0xffffffff;
|
||||
for (i = 0; i < 6; i++) {
|
||||
b = *ep++;
|
||||
for (i = 0; i < len; i++) {
|
||||
b = *p++;
|
||||
for (j = 0; j < 8; j++) {
|
||||
carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
|
||||
crc <<= 1;
|
||||
b >>= 1;
|
||||
if (carry) {
|
||||
crc = ((crc ^ POLYNOMIAL) | carry);
|
||||
crc = ((crc ^ POLYNOMIAL_BE) | carry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc >> 26;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t net_crc32_le(const uint8_t *p, int len)
|
||||
{
|
||||
uint32_t crc;
|
||||
int carry, i, j;
|
||||
uint8_t b;
|
||||
|
||||
crc = 0xffffffff;
|
||||
for (i = 0; i < len; i++) {
|
||||
b = *p++;
|
||||
for (j = 0; j < 8; j++) {
|
||||
carry = (crc & 0x1) ^ (b & 0x01);
|
||||
crc >>= 1;
|
||||
b >>= 1;
|
||||
if (carry) {
|
||||
crc ^= POLYNOMIAL_LE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
QemuOptsList qemu_netdev_opts = {
|
||||
|
34
net/slirp.c
34
net/slirp.c
@ -956,37 +956,3 @@ int net_init_slirp(const Netdev *netdev, const char *name,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret)
|
||||
{
|
||||
if (strcmp(opts_list->name, "net") != 0 ||
|
||||
strncmp(optarg, "channel,", strlen("channel,")) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
error_report("The '-net channel' option is deprecated. "
|
||||
"Please use '-netdev user,guestfwd=...' instead.");
|
||||
|
||||
/* handle legacy -net channel,port:chr */
|
||||
optarg += strlen("channel,");
|
||||
|
||||
if (QTAILQ_EMPTY(&slirp_stacks)) {
|
||||
struct slirp_config_str *config;
|
||||
|
||||
config = g_malloc(sizeof(*config));
|
||||
pstrcpy(config->str, sizeof(config->str), optarg);
|
||||
config->flags = SLIRP_CFG_LEGACY;
|
||||
config->next = slirp_configs;
|
||||
slirp_configs = config;
|
||||
*ret = 0;
|
||||
} else {
|
||||
Error *err = NULL;
|
||||
*ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1, &err);
|
||||
if (*ret < 0) {
|
||||
error_report_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2648,32 +2648,36 @@ combined with ``-vnc tls-creds=tls0'
|
||||
|
||||
@subsection -tftp (since 2.6.0)
|
||||
|
||||
The ``-tftp /some/dir'' argument is now a synonym for setting
|
||||
the ``-netdev user,tftp=/some/dir' argument. The new syntax
|
||||
allows different settings to be provided per NIC.
|
||||
The ``-tftp /some/dir'' argument is replaced by
|
||||
``-netdev user,id=x,tftp=/some/dir'', either accompanied with
|
||||
``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x''
|
||||
(for embedded NICs). The new syntax allows different settings to be
|
||||
provided per NIC.
|
||||
|
||||
@subsection -bootp (since 2.6.0)
|
||||
|
||||
The ``-bootp /some/file'' argument is now a synonym for setting
|
||||
the ``-netdev user,bootp=/some/file' argument. The new syntax
|
||||
allows different settings to be provided per NIC.
|
||||
The ``-bootp /some/file'' argument is replaced by
|
||||
``-netdev user,id=x,bootp=/some/file'', either accompanied with
|
||||
``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x''
|
||||
(for embedded NICs). The new syntax allows different settings to be
|
||||
provided per NIC.
|
||||
|
||||
@subsection -redir (since 2.6.0)
|
||||
|
||||
The ``-redir ARGS'' argument is now a synonym for setting
|
||||
the ``-netdev user,hostfwd=ARGS'' argument instead. The new
|
||||
syntax allows different settings to be provided per NIC.
|
||||
The ``-redir [tcp|udp]:hostport:[guestaddr]:guestport'' argument is
|
||||
replaced by ``-netdev
|
||||
user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport'',
|
||||
either accompanied with ``-device ...,netdev=x'' (for pluggable NICs) or
|
||||
``-net nic,netdev=x'' (for embedded NICs). The new syntax allows different
|
||||
settings to be provided per NIC.
|
||||
|
||||
@subsection -smb (since 2.6.0)
|
||||
|
||||
The ``-smb /some/dir'' argument is now a synonym for setting
|
||||
the ``-netdev user,smb=/some/dir'' argument instead. The new
|
||||
syntax allows different settings to be provided per NIC.
|
||||
|
||||
@subsection -net channel (since 2.6.0)
|
||||
|
||||
The ``--net channel,ARGS'' argument is now a synonym for setting
|
||||
the ``-netdev user,guestfwd=ARGS'' argument instead.
|
||||
The ``-smb /some/dir'' argument is replaced by
|
||||
``-netdev user,id=x,smb=/some/dir'', either accompanied with
|
||||
``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x''
|
||||
(for embedded NICs). The new syntax allows different settings to be
|
||||
provided per NIC.
|
||||
|
||||
@subsection -net vlan (since 2.9.0)
|
||||
|
||||
|
@ -2035,9 +2035,10 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
|
||||
"-netdev hubport,id=str,hubid=n\n"
|
||||
" configure a hub port on QEMU VLAN 'n'\n", QEMU_ARCH_ALL)
|
||||
DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||||
"-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
|
||||
" old way to create a new NIC and connect it to VLAN 'n'\n"
|
||||
" (use the '-device devtype,netdev=str' option if possible instead)\n"
|
||||
"-net nic[,vlan=n][,netdev=nd][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
|
||||
" configure or create an on-board (or machine default) NIC and\n"
|
||||
" connect it either to VLAN 'n' or the netdev 'nd' (for pluggable\n"
|
||||
" NICs please use '-device devtype,netdev=nd' instead)\n"
|
||||
"-net dump[,vlan=n][,file=f][,len=n]\n"
|
||||
" dump traffic on vlan 'n' to file 'f' (max n bytes per packet)\n"
|
||||
"-net none use it alone to have zero network devices. If no -net option\n"
|
||||
@ -2058,10 +2059,11 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
|
||||
" old way to initialize a host network interface\n"
|
||||
" (use the -netdev option if possible instead)\n", QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
|
||||
@item -net nic[,vlan=@var{n}][,netdev=@var{nd}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
|
||||
@findex -net
|
||||
Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
|
||||
= 0 is the default). The NIC is an e1000 by default on the PC
|
||||
Configure or create an on-board (or machine default) Network Interface Card
|
||||
(NIC) and connect it either to VLAN @var{n} (@var{n} = 0 is the default), or
|
||||
to the netdev @var{nd}. The NIC is an e1000 by default on the PC
|
||||
target. Optionally, the MAC address can be changed to @var{mac}, the
|
||||
device address set to @var{addr} (PCI cards only),
|
||||
and a @var{name} can be assigned for use in monitor commands.
|
||||
|
Loading…
Reference in New Issue
Block a user