Revision 718da2b9 hw/rtl8139.c
b/hw/rtl8139.c | ||
---|---|---|
33 | 33 |
* Implemented PCI timer interrupt (disabled by default) |
34 | 34 |
* Implemented Tally Counters, increased VM load/save version |
35 | 35 |
* Implemented IP/TCP/UDP checksum task offloading |
36 |
* |
|
37 |
* 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading |
|
38 |
* Fixed MTU=1500 for produced ethernet frames |
|
39 |
* |
|
40 |
* 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing |
|
41 |
* segmentation offloading |
|
42 |
* Removed slirp.h dependency |
|
43 |
* Added rx/tx buffer reset when enabling rx/tx operation |
|
36 | 44 |
*/ |
37 | 45 |
|
38 | 46 |
#include "vl.h" |
39 | 47 |
|
40 |
/* XXX: such dependency must be suppressed */ |
|
41 |
#include <slirp/slirp.h> |
|
42 |
|
|
43 | 48 |
/* debug RTL8139 card */ |
44 | 49 |
//#define DEBUG_RTL8139 1 |
45 | 50 |
|
... | ... | |
1364 | 1369 |
if (val & CmdRxEnb) |
1365 | 1370 |
{ |
1366 | 1371 |
DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); |
1372 |
|
|
1373 |
s->currCPlusRxDesc = 0; |
|
1367 | 1374 |
} |
1368 | 1375 |
if (val & CmdTxEnb) |
1369 | 1376 |
{ |
1370 | 1377 |
DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); |
1378 |
|
|
1379 |
s->currCPlusTxDesc = 0; |
|
1371 | 1380 |
} |
1372 | 1381 |
|
1373 | 1382 |
/* mask unwriteable bits */ |
... | ... | |
1732 | 1741 |
return ret; |
1733 | 1742 |
} |
1734 | 1743 |
|
1744 |
static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt) |
|
1745 |
{ |
|
1746 |
if (!size) |
|
1747 |
{ |
|
1748 |
DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n")); |
|
1749 |
return; |
|
1750 |
} |
|
1751 |
|
|
1752 |
if (TxLoopBack == (s->TxConfig & TxLoopBack)) |
|
1753 |
{ |
|
1754 |
DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); |
|
1755 |
rtl8139_do_receive(s, buf, size, do_interrupt); |
|
1756 |
} |
|
1757 |
else |
|
1758 |
{ |
|
1759 |
qemu_send_packet(s->vc, buf, size); |
|
1760 |
} |
|
1761 |
} |
|
1762 |
|
|
1735 | 1763 |
static int rtl8139_transmit_one(RTL8139State *s, int descriptor) |
1736 | 1764 |
{ |
1737 | 1765 |
if (!rtl8139_transmitter_enabled(s)) |
... | ... | |
1762 | 1790 |
s->TxStatus[descriptor] |= TxHostOwns; |
1763 | 1791 |
s->TxStatus[descriptor] |= TxStatOK; |
1764 | 1792 |
|
1765 |
if (TxLoopBack == (s->TxConfig & TxLoopBack)) |
|
1766 |
{ |
|
1767 |
DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); |
|
1768 |
rtl8139_do_receive(s, txbuffer, txsize, 0); |
|
1769 |
} |
|
1770 |
else |
|
1771 |
{ |
|
1772 |
qemu_send_packet(s->vc, txbuffer, txsize); |
|
1773 |
} |
|
1793 |
rtl8139_transfer_frame(s, txbuffer, txsize, 0); |
|
1774 | 1794 |
|
1775 | 1795 |
DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); |
1776 | 1796 |
|
... | ... | |
1781 | 1801 |
return 1; |
1782 | 1802 |
} |
1783 | 1803 |
|
1804 |
/* structures and macros for task offloading */ |
|
1805 |
typedef struct ip_header |
|
1806 |
{ |
|
1807 |
uint8_t ip_ver_len; /* version and header length */ |
|
1808 |
uint8_t ip_tos; /* type of service */ |
|
1809 |
uint16_t ip_len; /* total length */ |
|
1810 |
uint16_t ip_id; /* identification */ |
|
1811 |
uint16_t ip_off; /* fragment offset field */ |
|
1812 |
uint8_t ip_ttl; /* time to live */ |
|
1813 |
uint8_t ip_p; /* protocol */ |
|
1814 |
uint16_t ip_sum; /* checksum */ |
|
1815 |
uint32_t ip_src,ip_dst; /* source and dest address */ |
|
1816 |
} ip_header; |
|
1817 |
|
|
1818 |
#define IP_HEADER_VERSION_4 4 |
|
1819 |
#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf) |
|
1820 |
#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2) |
|
1821 |
|
|
1822 |
typedef struct tcp_header |
|
1823 |
{ |
|
1824 |
uint16_t th_sport; /* source port */ |
|
1825 |
uint16_t th_dport; /* destination port */ |
|
1826 |
uint32_t th_seq; /* sequence number */ |
|
1827 |
uint32_t th_ack; /* acknowledgement number */ |
|
1828 |
uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */ |
|
1829 |
uint16_t th_win; /* window */ |
|
1830 |
uint16_t th_sum; /* checksum */ |
|
1831 |
uint16_t th_urp; /* urgent pointer */ |
|
1832 |
} tcp_header; |
|
1833 |
|
|
1834 |
typedef struct udp_header |
|
1835 |
{ |
|
1836 |
uint16_t uh_sport; /* source port */ |
|
1837 |
uint16_t uh_dport; /* destination port */ |
|
1838 |
uint16_t uh_ulen; /* udp length */ |
|
1839 |
uint16_t uh_sum; /* udp checksum */ |
|
1840 |
} udp_header; |
|
1841 |
|
|
1842 |
typedef struct ip_pseudo_header |
|
1843 |
{ |
|
1844 |
uint32_t ip_src; |
|
1845 |
uint32_t ip_dst; |
|
1846 |
uint8_t zeros; |
|
1847 |
uint8_t ip_proto; |
|
1848 |
uint16_t ip_payload; |
|
1849 |
} ip_pseudo_header; |
|
1850 |
|
|
1851 |
#define IP_PROTO_TCP 6 |
|
1852 |
#define IP_PROTO_UDP 17 |
|
1853 |
|
|
1854 |
#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2) |
|
1855 |
#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f) |
|
1856 |
#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags)) |
|
1857 |
|
|
1858 |
#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off))) |
|
1859 |
|
|
1860 |
#define TCP_FLAG_FIN 0x01 |
|
1861 |
#define TCP_FLAG_PUSH 0x08 |
|
1862 |
|
|
1863 |
/* produces ones' complement sum of data */ |
|
1864 |
static uint16_t ones_complement_sum(uint8_t *data, size_t len) |
|
1865 |
{ |
|
1866 |
uint32_t result = 0; |
|
1867 |
|
|
1868 |
for (; len > 1; data+=2, len-=2) |
|
1869 |
{ |
|
1870 |
result += *(uint16_t*)data; |
|
1871 |
} |
|
1872 |
|
|
1873 |
/* add the remainder byte */ |
|
1874 |
if (len) |
|
1875 |
{ |
|
1876 |
uint8_t odd[2] = {*data, 0}; |
|
1877 |
result += *(uint16_t*)odd; |
|
1878 |
} |
|
1879 |
|
|
1880 |
while (result>>16) |
|
1881 |
result = (result & 0xffff) + (result >> 16); |
|
1882 |
|
|
1883 |
return result; |
|
1884 |
} |
|
1885 |
|
|
1886 |
static uint16_t ip_checksum(void *data, size_t len) |
|
1887 |
{ |
|
1888 |
return ~ones_complement_sum((uint8_t*)data, len); |
|
1889 |
} |
|
1890 |
|
|
1784 | 1891 |
static int rtl8139_cplus_transmit_one(RTL8139State *s) |
1785 | 1892 |
{ |
1786 | 1893 |
if (!rtl8139_transmitter_enabled(s)) |
... | ... | |
1831 | 1938 |
#define CP_TX_LS (1<<28) |
1832 | 1939 |
/* large send packet flag */ |
1833 | 1940 |
#define CP_TX_LGSEN (1<<27) |
1941 |
/* large send MSS mask, bits 16...25 */ |
|
1942 |
#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1) |
|
1943 |
|
|
1834 | 1944 |
/* IP checksum offload flag */ |
1835 | 1945 |
#define CP_TX_IPCS (1<<18) |
1836 | 1946 |
/* UDP checksum offload flag */ |
... | ... | |
1885 | 1995 |
s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE; |
1886 | 1996 |
s->cplus_txbuffer = malloc(s->cplus_txbuffer_len); |
1887 | 1997 |
s->cplus_txbuffer_offset = 0; |
1998 |
|
|
1999 |
DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len)); |
|
1888 | 2000 |
} |
1889 | 2001 |
|
1890 | 2002 |
while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) |
... | ... | |
1960 | 2072 |
s->cplus_txbuffer_offset = 0; |
1961 | 2073 |
s->cplus_txbuffer_len = 0; |
1962 | 2074 |
|
1963 |
if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS)) |
|
2075 |
if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
|
|
1964 | 2076 |
{ |
1965 | 2077 |
DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); |
1966 | 2078 |
|
1967 | 2079 |
#define ETH_P_IP 0x0800 /* Internet Protocol packet */ |
1968 | 2080 |
#define ETH_HLEN 14 |
2081 |
#define ETH_MTU 1500 |
|
1969 | 2082 |
|
1970 | 2083 |
/* ip packet header */ |
1971 |
register struct ip *ip = 0;
|
|
2084 |
ip_header *ip = 0;
|
|
1972 | 2085 |
int hlen = 0; |
2086 |
uint8_t ip_protocol = 0; |
|
2087 |
uint16_t ip_data_len = 0; |
|
1973 | 2088 |
|
1974 |
struct mbuf local_m; |
|
2089 |
uint8_t *eth_payload_data = 0; |
|
2090 |
size_t eth_payload_len = 0; |
|
1975 | 2091 |
|
1976 |
int proto = ntohs(*(uint16_t *)(saved_buffer + 12));
|
|
2092 |
int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
|
|
1977 | 2093 |
if (proto == ETH_P_IP) |
1978 | 2094 |
{ |
1979 | 2095 |
DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); |
1980 | 2096 |
|
1981 | 2097 |
/* not aligned */ |
1982 |
local_m.m_data = saved_buffer + ETH_HLEN;
|
|
1983 |
local_m.m_len = saved_size - ETH_HLEN;
|
|
2098 |
eth_payload_data = saved_buffer + ETH_HLEN;
|
|
2099 |
eth_payload_len = saved_size - ETH_HLEN;
|
|
1984 | 2100 |
|
1985 |
ip = mtod(&local_m, struct ip *);
|
|
2101 |
ip = (ip_header*)eth_payload_data;
|
|
1986 | 2102 |
|
1987 |
if (ip->ip_v != IPVERSION) {
|
|
1988 |
DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", ip->ip_v, IPVERSION));
|
|
2103 |
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
|
|
2104 |
DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4));
|
|
1989 | 2105 |
ip = NULL; |
1990 | 2106 |
} else { |
1991 |
hlen = ip->ip_hl << 2; |
|
2107 |
hlen = IP_HEADER_LENGTH(ip); |
|
2108 |
ip_protocol = ip->ip_p; |
|
2109 |
ip_data_len = be16_to_cpu(ip->ip_len) - hlen; |
|
1992 | 2110 |
} |
1993 | 2111 |
} |
1994 | 2112 |
|
... | ... | |
1998 | 2116 |
{ |
1999 | 2117 |
DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); |
2000 | 2118 |
|
2001 |
if (hlen<sizeof(struct ip ) || hlen>local_m.m_len) {/* min header length */
|
|
2119 |
if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
|
|
2002 | 2120 |
/* bad packet header len */ |
2003 | 2121 |
/* or packet too short */ |
2004 | 2122 |
} |
2005 | 2123 |
else |
2006 | 2124 |
{ |
2007 | 2125 |
ip->ip_sum = 0; |
2008 |
ip->ip_sum = cksum(&local_m, hlen);
|
|
2126 |
ip->ip_sum = ip_checksum(ip, hlen);
|
|
2009 | 2127 |
DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); |
2010 | 2128 |
} |
2011 | 2129 |
} |
2012 | 2130 |
|
2013 |
if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
|
2131 |
if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
|
2014 | 2132 |
{ |
2015 |
DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); |
|
2133 |
#if defined (DEBUG_RTL8139) |
|
2134 |
int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; |
|
2135 |
#endif |
|
2136 |
DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n", |
|
2137 |
ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss)); |
|
2016 | 2138 |
|
2017 |
u_int8_t ip_protocol = ip->ip_p;
|
|
2018 |
u_int16_t ip_data_len = ntohs(ip->ip_len) - hlen;
|
|
2139 |
int tcp_send_offset = 0;
|
|
2140 |
int send_count = 0;
|
|
2019 | 2141 |
|
2020 | 2142 |
/* maximum IP header length is 60 bytes */ |
2021 | 2143 |
uint8_t saved_ip_header[60]; |
2022 |
memcpy(saved_ip_header, local_m.m_data, hlen); |
|
2023 | 2144 |
|
2024 |
struct mbuf local_checksum_m; |
|
2145 |
/* save IP header template; data area is used in tcp checksum calculation */ |
|
2146 |
memcpy(saved_ip_header, eth_payload_data, hlen); |
|
2147 |
|
|
2148 |
/* a placeholder for checksum calculation routine in tcp case */ |
|
2149 |
uint8_t *data_to_checksum = eth_payload_data + hlen - 12; |
|
2150 |
// size_t data_to_checksum_len = eth_payload_len - hlen + 12; |
|
2151 |
|
|
2152 |
/* pointer to TCP header */ |
|
2153 |
tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); |
|
2154 |
|
|
2155 |
int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); |
|
2156 |
|
|
2157 |
/* ETH_MTU = ip header len + tcp header len + payload */ |
|
2158 |
int tcp_data_len = ip_data_len - tcp_hlen; |
|
2159 |
int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; |
|
2160 |
|
|
2161 |
DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n", |
|
2162 |
ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size)); |
|
2163 |
|
|
2164 |
/* note the cycle below overwrites IP header data, |
|
2165 |
but restores it from saved_ip_header before sending packet */ |
|
2166 |
|
|
2167 |
int is_last_frame = 0; |
|
2168 |
|
|
2169 |
for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) |
|
2170 |
{ |
|
2171 |
uint16_t chunk_size = tcp_chunk_size; |
|
2172 |
|
|
2173 |
/* check if this is the last frame */ |
|
2174 |
if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) |
|
2175 |
{ |
|
2176 |
is_last_frame = 1; |
|
2177 |
chunk_size = tcp_data_len - tcp_send_offset; |
|
2178 |
} |
|
2179 |
|
|
2180 |
DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); |
|
2181 |
|
|
2182 |
/* add 4 TCP pseudoheader fields */ |
|
2183 |
/* copy IP source and destination fields */ |
|
2184 |
memcpy(data_to_checksum, saved_ip_header + 12, 8); |
|
2185 |
|
|
2186 |
DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); |
|
2187 |
|
|
2188 |
if (tcp_send_offset) |
|
2189 |
{ |
|
2190 |
memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); |
|
2191 |
} |
|
2192 |
|
|
2193 |
/* keep PUSH and FIN flags only for the last frame */ |
|
2194 |
if (!is_last_frame) |
|
2195 |
{ |
|
2196 |
TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); |
|
2197 |
} |
|
2025 | 2198 |
|
2026 |
local_checksum_m.m_data = local_m.m_data + hlen - 12; |
|
2027 |
local_checksum_m.m_len = local_m.m_len - hlen + 12; |
|
2199 |
/* recalculate TCP checksum */ |
|
2200 |
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; |
|
2201 |
p_tcpip_hdr->zeros = 0; |
|
2202 |
p_tcpip_hdr->ip_proto = IP_PROTO_TCP; |
|
2203 |
p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); |
|
2204 |
|
|
2205 |
p_tcp_hdr->th_sum = 0; |
|
2206 |
|
|
2207 |
int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); |
|
2208 |
DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); |
|
2209 |
|
|
2210 |
p_tcp_hdr->th_sum = tcp_checksum; |
|
2211 |
|
|
2212 |
/* restore IP header */ |
|
2213 |
memcpy(eth_payload_data, saved_ip_header, hlen); |
|
2214 |
|
|
2215 |
/* set IP data length and recalculate IP checksum */ |
|
2216 |
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); |
|
2217 |
|
|
2218 |
/* increment IP id for subsequent frames */ |
|
2219 |
ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); |
|
2220 |
|
|
2221 |
ip->ip_sum = 0; |
|
2222 |
ip->ip_sum = ip_checksum(eth_payload_data, hlen); |
|
2223 |
DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); |
|
2224 |
|
|
2225 |
int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; |
|
2226 |
DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); |
|
2227 |
rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0); |
|
2228 |
|
|
2229 |
/* add transferred count to TCP sequence number */ |
|
2230 |
p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); |
|
2231 |
++send_count; |
|
2232 |
} |
|
2233 |
|
|
2234 |
/* Stop sending this frame */ |
|
2235 |
saved_size = 0; |
|
2236 |
} |
|
2237 |
else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) |
|
2238 |
{ |
|
2239 |
DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); |
|
2240 |
|
|
2241 |
/* maximum IP header length is 60 bytes */ |
|
2242 |
uint8_t saved_ip_header[60]; |
|
2243 |
memcpy(saved_ip_header, eth_payload_data, hlen); |
|
2244 |
|
|
2245 |
uint8_t *data_to_checksum = eth_payload_data + hlen - 12; |
|
2246 |
// size_t data_to_checksum_len = eth_payload_len - hlen + 12; |
|
2028 | 2247 |
|
2029 | 2248 |
/* add 4 TCP pseudoheader fields */ |
2030 | 2249 |
/* copy IP source and destination fields */ |
2031 |
memcpy(local_checksum_m.m_data, saved_ip_header + 12, 8);
|
|
2250 |
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
|
2032 | 2251 |
|
2033 |
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IPPROTO_TCP) |
|
2252 |
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
|
2034 | 2253 |
{ |
2035 | 2254 |
DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); |
2036 | 2255 |
|
2037 |
struct tcpiphdr * p_tcpip_hdr = (struct tcpiphdr *)local_checksum_m.m_data;
|
|
2038 |
p_tcpip_hdr->ti_x1 = 0;
|
|
2039 |
p_tcpip_hdr->ti_pr = IPPROTO_TCP;
|
|
2040 |
p_tcpip_hdr->ti_len = htons(ip_data_len);
|
|
2256 |
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
2257 |
p_tcpip_hdr->zeros = 0;
|
|
2258 |
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
|
2259 |
p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
|
2041 | 2260 |
|
2042 |
struct tcphdr* p_tcp_hdr = (struct tcphdr*) (local_checksum_m.m_data+12);
|
|
2261 |
tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
|
2043 | 2262 |
|
2044 | 2263 |
p_tcp_hdr->th_sum = 0; |
2045 | 2264 |
|
2046 |
int tcp_checksum = cksum(&local_checksum_m, ip_data_len + 12);
|
|
2265 |
int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
|
2047 | 2266 |
DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); |
2048 | 2267 |
|
2049 | 2268 |
p_tcp_hdr->th_sum = tcp_checksum; |
2050 | 2269 |
} |
2051 |
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IPPROTO_UDP) |
|
2270 |
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
|
2052 | 2271 |
{ |
2053 | 2272 |
DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); |
2054 | 2273 |
|
2055 |
struct udpiphdr * p_udpip_hdr = (struct udpiphdr *)local_checksum_m.m_data;
|
|
2056 |
p_udpip_hdr->ui_x1 = 0;
|
|
2057 |
p_udpip_hdr->ui_pr = IPPROTO_UDP;
|
|
2058 |
p_udpip_hdr->ui_len = htons(ip_data_len);
|
|
2274 |
ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
2275 |
p_udpip_hdr->zeros = 0;
|
|
2276 |
p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
|
2277 |
p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
|
2059 | 2278 |
|
2060 |
struct udphdr* p_udp_hdr = (struct udphdr*) (local_checksum_m.m_data+12);
|
|
2279 |
udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
|
2061 | 2280 |
|
2062 |
int old_csum = p_udp_hdr->uh_sum; |
|
2063 | 2281 |
p_udp_hdr->uh_sum = 0; |
2064 | 2282 |
|
2065 |
int udp_checksum = cksum(&local_checksum_m, ip_data_len + 12);
|
|
2283 |
int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
|
2066 | 2284 |
DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); |
2067 | 2285 |
|
2068 |
if (old_csum != udp_checksum) |
|
2069 |
{ |
|
2070 |
DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum mismatch old=%04x new=%04x\n", |
|
2071 |
old_csum, udp_checksum)); |
|
2072 |
} |
|
2073 |
|
|
2074 | 2286 |
p_udp_hdr->uh_sum = udp_checksum; |
2075 | 2287 |
} |
2076 | 2288 |
|
2077 | 2289 |
/* restore IP header */ |
2078 |
memcpy(local_m.m_data, saved_ip_header, hlen);
|
|
2290 |
memcpy(eth_payload_data, saved_ip_header, hlen);
|
|
2079 | 2291 |
} |
2080 | 2292 |
} |
2081 | 2293 |
} |
... | ... | |
2085 | 2297 |
|
2086 | 2298 |
DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); |
2087 | 2299 |
|
2088 |
if (TxLoopBack == (s->TxConfig & TxLoopBack)) |
|
2089 |
{ |
|
2090 |
DEBUG_PRINT(("RTL8139: +++ C+ transmit loopback mode\n")); |
|
2091 |
rtl8139_receive(s, saved_buffer, saved_size); |
|
2092 |
} |
|
2093 |
else |
|
2094 |
{ |
|
2095 |
/* transmit the packet */ |
|
2096 |
qemu_send_packet(s->vc, saved_buffer, saved_size); |
|
2097 |
} |
|
2300 |
rtl8139_transfer_frame(s, saved_buffer, saved_size, 1); |
|
2098 | 2301 |
|
2099 | 2302 |
/* restore card space if there was no recursion and reset offset */ |
2100 | 2303 |
if (!s->cplus_txbuffer) |
... | ... | |
2253 | 2456 |
DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); |
2254 | 2457 |
|
2255 | 2458 |
s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); |
2256 |
|
|
2257 |
s->currCPlusTxDesc = 0; |
|
2258 | 2459 |
} |
2259 | 2460 |
|
2260 | 2461 |
static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) |
Also available in: Unified diff