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