Commit 718da2b9b0243bd180db9079b98d7d88ee96aa7a

Authored by bellard
1 parent 0de6bb73

fixed for TCP segmentation offloading - removed dependency on slirp.h (Igor Kovalenko)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2046 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 268 additions and 67 deletions
hw/rtl8139.c
@@ -33,13 +33,18 @@ @@ -33,13 +33,18 @@
33 * Implemented PCI timer interrupt (disabled by default) 33 * Implemented PCI timer interrupt (disabled by default)
34 * Implemented Tally Counters, increased VM load/save version 34 * Implemented Tally Counters, increased VM load/save version
35 * Implemented IP/TCP/UDP checksum task offloading 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 #include "vl.h" 46 #include "vl.h"
39 47
40 -/* XXX: such dependency must be suppressed */  
41 -#include <slirp/slirp.h>  
42 -  
43 /* debug RTL8139 card */ 48 /* debug RTL8139 card */
44 //#define DEBUG_RTL8139 1 49 //#define DEBUG_RTL8139 1
45 50
@@ -1364,10 +1369,14 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) @@ -1364,10 +1369,14 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
1364 if (val & CmdRxEnb) 1369 if (val & CmdRxEnb)
1365 { 1370 {
1366 DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); 1371 DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n"));
  1372 +
  1373 + s->currCPlusRxDesc = 0;
1367 } 1374 }
1368 if (val & CmdTxEnb) 1375 if (val & CmdTxEnb)
1369 { 1376 {
1370 DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); 1377 DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n"));
  1378 +
  1379 + s->currCPlusTxDesc = 0;
1371 } 1380 }
1372 1381
1373 /* mask unwriteable bits */ 1382 /* mask unwriteable bits */
@@ -1732,6 +1741,25 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s) @@ -1732,6 +1741,25 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
1732 return ret; 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 static int rtl8139_transmit_one(RTL8139State *s, int descriptor) 1763 static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
1736 { 1764 {
1737 if (!rtl8139_transmitter_enabled(s)) 1765 if (!rtl8139_transmitter_enabled(s))
@@ -1762,15 +1790,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) @@ -1762,15 +1790,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
1762 s->TxStatus[descriptor] |= TxHostOwns; 1790 s->TxStatus[descriptor] |= TxHostOwns;
1763 s->TxStatus[descriptor] |= TxStatOK; 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 DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); 1795 DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor));
1776 1796
@@ -1781,6 +1801,93 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) @@ -1781,6 +1801,93 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
1781 return 1; 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 static int rtl8139_cplus_transmit_one(RTL8139State *s) 1891 static int rtl8139_cplus_transmit_one(RTL8139State *s)
1785 { 1892 {
1786 if (!rtl8139_transmitter_enabled(s)) 1893 if (!rtl8139_transmitter_enabled(s))
@@ -1831,6 +1938,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) @@ -1831,6 +1938,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
1831 #define CP_TX_LS (1<<28) 1938 #define CP_TX_LS (1<<28)
1832 /* large send packet flag */ 1939 /* large send packet flag */
1833 #define CP_TX_LGSEN (1<<27) 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 /* IP checksum offload flag */ 1944 /* IP checksum offload flag */
1835 #define CP_TX_IPCS (1<<18) 1945 #define CP_TX_IPCS (1<<18)
1836 /* UDP checksum offload flag */ 1946 /* UDP checksum offload flag */
@@ -1885,6 +1995,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) @@ -1885,6 +1995,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
1885 s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE; 1995 s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
1886 s->cplus_txbuffer = malloc(s->cplus_txbuffer_len); 1996 s->cplus_txbuffer = malloc(s->cplus_txbuffer_len);
1887 s->cplus_txbuffer_offset = 0; 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 while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) 2002 while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
@@ -1960,35 +2072,41 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) @@ -1960,35 +2072,41 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
1960 s->cplus_txbuffer_offset = 0; 2072 s->cplus_txbuffer_offset = 0;
1961 s->cplus_txbuffer_len = 0; 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 DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); 2077 DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n"));
1966 2078
1967 #define ETH_P_IP 0x0800 /* Internet Protocol packet */ 2079 #define ETH_P_IP 0x0800 /* Internet Protocol packet */
1968 #define ETH_HLEN 14 2080 #define ETH_HLEN 14
  2081 + #define ETH_MTU 1500
1969 2082
1970 /* ip packet header */ 2083 /* ip packet header */
1971 - register struct ip *ip = 0; 2084 + ip_header *ip = 0;
1972 int hlen = 0; 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 if (proto == ETH_P_IP) 2093 if (proto == ETH_P_IP)
1978 { 2094 {
1979 DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); 2095 DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n"));
1980 2096
1981 /* not aligned */ 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 ip = NULL; 2105 ip = NULL;
1990 } else { 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,84 +2116,178 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) @@ -1998,84 +2116,178 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
1998 { 2116 {
1999 DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); 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 /* bad packet header len */ 2120 /* bad packet header len */
2003 /* or packet too short */ 2121 /* or packet too short */
2004 } 2122 }
2005 else 2123 else
2006 { 2124 {
2007 ip->ip_sum = 0; 2125 ip->ip_sum = 0;
2008 - ip->ip_sum = cksum(&local_m, hlen); 2126 + ip->ip_sum = ip_checksum(ip, hlen);
2009 DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); 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 /* maximum IP header length is 60 bytes */ 2142 /* maximum IP header length is 60 bytes */
2021 uint8_t saved_ip_header[60]; 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 /* add 4 TCP pseudoheader fields */ 2248 /* add 4 TCP pseudoheader fields */
2030 /* copy IP source and destination fields */ 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 DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); 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 p_tcp_hdr->th_sum = 0; 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 DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); 2266 DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum));
2048 2267
2049 p_tcp_hdr->th_sum = tcp_checksum; 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 DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); 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 p_udp_hdr->uh_sum = 0; 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 DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); 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 p_udp_hdr->uh_sum = udp_checksum; 2286 p_udp_hdr->uh_sum = udp_checksum;
2075 } 2287 }
2076 2288
2077 /* restore IP header */ 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,16 +2297,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) @@ -2085,16 +2297,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
2085 2297
2086 DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); 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 /* restore card space if there was no recursion and reset offset */ 2302 /* restore card space if there was no recursion and reset offset */
2100 if (!s->cplus_txbuffer) 2303 if (!s->cplus_txbuffer)
@@ -2253,8 +2456,6 @@ static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_ @@ -2253,8 +2456,6 @@ static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_
2253 DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); 2456 DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val));
2254 2457
2255 s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); 2458 s->TxAddr[txAddrOffset/4] = le32_to_cpu(val);
2256 -  
2257 - s->currCPlusTxDesc = 0;  
2258 } 2459 }
2259 2460
2260 static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) 2461 static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)