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 | 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,10 +1369,14 @@ static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) |
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,6 +1741,25 @@ static uint32_t rtl8139_RxConfig_read(RTL8139State *s) |
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,15 +1790,7 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) |
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,6 +1801,93 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) |
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,6 +1938,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *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,6 +1995,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) |
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,35 +2072,41 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) |
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,84 +2116,178 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) |
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,16 +2297,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) |
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,8 +2456,6 @@ static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_ |
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) | ... | ... |