Commit 718da2b9b0243bd180db9079b98d7d88ee96aa7a
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) |