Revision 18dabfd1 hw/rtl8139.c
b/hw/rtl8139.c | ||
---|---|---|
72 | 72 |
#define MOD2(input, size) \ |
73 | 73 |
( ( input ) & ( size - 1 ) ) |
74 | 74 |
|
75 |
#define ETHER_ADDR_LEN 6 |
|
76 |
#define ETHER_TYPE_LEN 2 |
|
77 |
#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) |
|
78 |
#define ETH_P_IP 0x0800 /* Internet Protocol packet */ |
|
79 |
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ |
|
80 |
#define ETH_MTU 1500 |
|
81 |
|
|
82 |
#define VLAN_TCI_LEN 2 |
|
83 |
#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN) |
|
84 |
|
|
75 | 85 |
#if defined (DEBUG_RTL8139) |
76 | 86 |
# define DEBUG_PRINT(x) do { printf x ; } while (0) |
77 | 87 |
#else |
... | ... | |
812 | 822 |
static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt) |
813 | 823 |
{ |
814 | 824 |
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; |
825 |
/* size is the length of the buffer passed to the driver */ |
|
815 | 826 |
int size = size_; |
827 |
const uint8_t *dot1q_buf = NULL; |
|
816 | 828 |
|
817 | 829 |
uint32_t packet_header = 0; |
818 | 830 |
|
819 |
uint8_t buf1[60];
|
|
831 |
uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
|
|
820 | 832 |
static const uint8_t broadcast_macaddr[6] = |
821 | 833 |
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
822 | 834 |
|
... | ... | |
928 | 940 |
} |
929 | 941 |
} |
930 | 942 |
|
931 |
/* if too small buffer, then expand it */ |
|
932 |
if (size < MIN_BUF_SIZE) { |
|
943 |
/* if too small buffer, then expand it |
|
944 |
* Include some tailroom in case a vlan tag is later removed. */ |
|
945 |
if (size < MIN_BUF_SIZE + VLAN_HLEN) { |
|
933 | 946 |
memcpy(buf1, buf, size); |
934 |
memset(buf1 + size, 0, MIN_BUF_SIZE - size); |
|
947 |
memset(buf1 + size, 0, MIN_BUF_SIZE + VLAN_HLEN - size);
|
|
935 | 948 |
buf = buf1; |
936 |
size = MIN_BUF_SIZE; |
|
949 |
if (size < MIN_BUF_SIZE) { |
|
950 |
size = MIN_BUF_SIZE; |
|
951 |
} |
|
937 | 952 |
} |
938 | 953 |
|
939 | 954 |
if (rtl8139_cp_receiver_enabled(s)) |
... | ... | |
996 | 1011 |
|
997 | 1012 |
uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; |
998 | 1013 |
|
1014 |
/* write VLAN info to descriptor variables. */ |
|
1015 |
if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *) |
|
1016 |
&buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) { |
|
1017 |
dot1q_buf = &buf[ETHER_ADDR_LEN * 2]; |
|
1018 |
size -= VLAN_HLEN; |
|
1019 |
/* if too small buffer, use the tailroom added duing expansion */ |
|
1020 |
if (size < MIN_BUF_SIZE) { |
|
1021 |
size = MIN_BUF_SIZE; |
|
1022 |
} |
|
1023 |
|
|
1024 |
rxdw1 &= ~CP_RX_VLAN_TAG_MASK; |
|
1025 |
/* BE + ~le_to_cpu()~ + cpu_to_le() = BE */ |
|
1026 |
rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *) |
|
1027 |
&dot1q_buf[ETHER_TYPE_LEN]); |
|
1028 |
|
|
1029 |
DEBUG_PRINT(("RTL8139: C+ Rx mode : extracted vlan tag with tci: " |
|
1030 |
"%u\n", be16_to_cpup((uint16_t *) |
|
1031 |
&dot1q_buf[ETHER_TYPE_LEN]))); |
|
1032 |
} else { |
|
1033 |
/* reset VLAN tag flag */ |
|
1034 |
rxdw1 &= ~CP_RX_TAVA; |
|
1035 |
} |
|
1036 |
|
|
999 | 1037 |
/* TODO: scatter the packet over available receive ring descriptors space */ |
1000 | 1038 |
|
1001 | 1039 |
if (size+4 > rx_space) |
... | ... | |
1017 | 1055 |
target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); |
1018 | 1056 |
|
1019 | 1057 |
/* receive/copy to target memory */ |
1020 |
cpu_physical_memory_write( rx_addr, buf, size ); |
|
1058 |
if (dot1q_buf) { |
|
1059 |
cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN); |
|
1060 |
cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN, |
|
1061 |
buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN, |
|
1062 |
size - 2 * ETHER_ADDR_LEN); |
|
1063 |
} else { |
|
1064 |
cpu_physical_memory_write(rx_addr, buf, size); |
|
1065 |
} |
|
1021 | 1066 |
|
1022 | 1067 |
if (s->CpCmd & CPlusRxChkSum) |
1023 | 1068 |
{ |
... | ... | |
1025 | 1070 |
} |
1026 | 1071 |
|
1027 | 1072 |
/* write checksum */ |
1028 |
val = cpu_to_le32(crc32(0, buf, size)); |
|
1073 |
val = cpu_to_le32(crc32(0, buf, size_));
|
|
1029 | 1074 |
cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4); |
1030 | 1075 |
|
1031 | 1076 |
/* first segment of received packet flag */ |
... | ... | |
1070 | 1115 |
rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK; |
1071 | 1116 |
rxdw0 |= (size+4); |
1072 | 1117 |
|
1073 |
/* reset VLAN tag flag */ |
|
1074 |
rxdw1 &= ~CP_RX_TAVA; |
|
1075 |
|
|
1076 | 1118 |
/* update ring data */ |
1077 | 1119 |
val = cpu_to_le32(rxdw0); |
1078 | 1120 |
cpu_physical_memory_write(cplus_rx_ring_desc, (uint8_t *)&val, 4); |
... | ... | |
2054 | 2096 |
{ |
2055 | 2097 |
DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); |
2056 | 2098 |
|
2057 |
#define ETH_P_IP 0x0800 /* Internet Protocol packet */ |
|
2058 |
#define ETH_HLEN 14 |
|
2059 |
#define ETH_MTU 1500 |
|
2060 |
|
|
2061 | 2099 |
/* ip packet header */ |
2062 | 2100 |
ip_header *ip = NULL; |
2063 | 2101 |
int hlen = 0; |
Also available in: Unified diff