|
|
05bba0 |
From fc8f8c54749bfeb7a4320875dc2bfd3565cf5ebe Mon Sep 17 00:00:00 2001
|
|
|
b2d9fb |
From: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
b2d9fb |
Date: Fri, 31 Jul 2015 15:59:43 +0200
|
|
|
05bba0 |
Subject: [PATCH 08/13] rtl8139: drop tautologous if (ip) {...} statement
|
|
|
b2d9fb |
(CVE-2015-5165)
|
|
|
b2d9fb |
|
|
|
b2d9fb |
Message-id: <1438358388-10575-3-git-send-email-stefanha@redhat.com>
|
|
|
b2d9fb |
Patchwork-id: 67238
|
|
|
b2d9fb |
O-Subject: [RHEL-7.1.z qemu-kvm EMBARGOED PATCH 2/7] rtl8139: drop tautologous if (ip) {...} statement (CVE-2015-5165)
|
|
|
05bba0 |
Bugzilla: 1248766
|
|
|
b2d9fb |
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
|
|
b2d9fb |
RH-Acked-by: Xiao Wang <jasowang@redhat.com>
|
|
|
b2d9fb |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
b2d9fb |
|
|
|
b2d9fb |
The previous patch stopped using the ip pointer as an indicator that the
|
|
|
b2d9fb |
IP header is present. When we reach the if (ip) {...} statement we know
|
|
|
b2d9fb |
ip is always non-NULL.
|
|
|
b2d9fb |
|
|
|
b2d9fb |
Remove the if statement to reduce nesting.
|
|
|
b2d9fb |
|
|
|
b2d9fb |
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
b2d9fb |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
b2d9fb |
---
|
|
|
b2d9fb |
hw/net/rtl8139.c | 305 +++++++++++++++++++++++++++----------------------------
|
|
|
b2d9fb |
1 file changed, 151 insertions(+), 154 deletions(-)
|
|
|
b2d9fb |
|
|
|
b2d9fb |
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
|
|
|
b2d9fb |
index e3b594f..ab32714 100644
|
|
|
b2d9fb |
--- a/hw/net/rtl8139.c
|
|
|
b2d9fb |
+++ b/hw/net/rtl8139.c
|
|
|
b2d9fb |
@@ -2176,198 +2176,195 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
|
|
b2d9fb |
ip_protocol = ip->ip_p;
|
|
|
b2d9fb |
ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- if (ip)
|
|
|
b2d9fb |
+ if (txdw0 & CP_TX_IPCS)
|
|
|
b2d9fb |
{
|
|
|
b2d9fb |
- if (txdw0 & CP_TX_IPCS)
|
|
|
b2d9fb |
- {
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode need IP checksum\n");
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode need IP checksum\n");
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
|
|
|
b2d9fb |
- /* bad packet header len */
|
|
|
b2d9fb |
- /* or packet too short */
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
- else
|
|
|
b2d9fb |
- {
|
|
|
b2d9fb |
- ip->ip_sum = 0;
|
|
|
b2d9fb |
- ip->ip_sum = ip_checksum(ip, hlen);
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
|
|
b2d9fb |
- hlen, ip->ip_sum);
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
+ if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
|
|
|
b2d9fb |
+ /* bad packet header len */
|
|
|
b2d9fb |
+ /* or packet too short */
|
|
|
b2d9fb |
}
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
|
|
b2d9fb |
+ else
|
|
|
b2d9fb |
{
|
|
|
b2d9fb |
- int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
|
|
b2d9fb |
+ ip->ip_sum = 0;
|
|
|
b2d9fb |
+ ip->ip_sum = ip_checksum(ip, hlen);
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
|
|
b2d9fb |
+ hlen, ip->ip_sum);
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
|
|
b2d9fb |
- "frame data %d specified MSS=%d\n", ETH_MTU,
|
|
|
b2d9fb |
- ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
|
|
b2d9fb |
+ if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
|
|
b2d9fb |
+ {
|
|
|
b2d9fb |
+ int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- int tcp_send_offset = 0;
|
|
|
b2d9fb |
- int send_count = 0;
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
|
|
b2d9fb |
+ "frame data %d specified MSS=%d\n", ETH_MTU,
|
|
|
b2d9fb |
+ ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* maximum IP header length is 60 bytes */
|
|
|
b2d9fb |
- uint8_t saved_ip_header[60];
|
|
|
b2d9fb |
+ int tcp_send_offset = 0;
|
|
|
b2d9fb |
+ int send_count = 0;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* save IP header template; data area is used in tcp checksum calculation */
|
|
|
b2d9fb |
- memcpy(saved_ip_header, eth_payload_data, hlen);
|
|
|
b2d9fb |
+ /* maximum IP header length is 60 bytes */
|
|
|
b2d9fb |
+ uint8_t saved_ip_header[60];
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* a placeholder for checksum calculation routine in tcp case */
|
|
|
b2d9fb |
- uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
|
|
b2d9fb |
- // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
|
|
b2d9fb |
+ /* save IP header template; data area is used in tcp checksum calculation */
|
|
|
b2d9fb |
+ memcpy(saved_ip_header, eth_payload_data, hlen);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* pointer to TCP header */
|
|
|
b2d9fb |
- tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
|
|
b2d9fb |
+ /* a placeholder for checksum calculation routine in tcp case */
|
|
|
b2d9fb |
+ uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
|
|
b2d9fb |
+ // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
|
|
b2d9fb |
+ /* pointer to TCP header */
|
|
|
b2d9fb |
+ tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* ETH_MTU = ip header len + tcp header len + payload */
|
|
|
b2d9fb |
- int tcp_data_len = ip_data_len - tcp_hlen;
|
|
|
b2d9fb |
- int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
|
|
b2d9fb |
+ int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
|
|
b2d9fb |
- "data len %d TCP chunk size %d\n", ip_data_len,
|
|
|
b2d9fb |
- tcp_hlen, tcp_data_len, tcp_chunk_size);
|
|
|
b2d9fb |
+ /* ETH_MTU = ip header len + tcp header len + payload */
|
|
|
b2d9fb |
+ int tcp_data_len = ip_data_len - tcp_hlen;
|
|
|
b2d9fb |
+ int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* note the cycle below overwrites IP header data,
|
|
|
b2d9fb |
- but restores it from saved_ip_header before sending packet */
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
|
|
b2d9fb |
+ "data len %d TCP chunk size %d\n", ip_data_len,
|
|
|
b2d9fb |
+ tcp_hlen, tcp_data_len, tcp_chunk_size);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- int is_last_frame = 0;
|
|
|
b2d9fb |
+ /* note the cycle below overwrites IP header data,
|
|
|
b2d9fb |
+ but restores it from saved_ip_header before sending packet */
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
|
|
b2d9fb |
- {
|
|
|
b2d9fb |
- uint16_t chunk_size = tcp_chunk_size;
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* check if this is the last frame */
|
|
|
b2d9fb |
- if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
|
|
b2d9fb |
- {
|
|
|
b2d9fb |
- is_last_frame = 1;
|
|
|
b2d9fb |
- chunk_size = tcp_data_len - tcp_send_offset;
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
|
|
b2d9fb |
- be32_to_cpu(p_tcp_hdr->th_seq));
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* add 4 TCP pseudoheader fields */
|
|
|
b2d9fb |
- /* copy IP source and destination fields */
|
|
|
b2d9fb |
- memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
|
|
b2d9fb |
- "packet with %d bytes data\n", tcp_hlen +
|
|
|
b2d9fb |
- chunk_size);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- if (tcp_send_offset)
|
|
|
b2d9fb |
- {
|
|
|
b2d9fb |
- memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* keep PUSH and FIN flags only for the last frame */
|
|
|
b2d9fb |
- if (!is_last_frame)
|
|
|
b2d9fb |
- {
|
|
|
b2d9fb |
- TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* recalculate TCP checksum */
|
|
|
b2d9fb |
- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
|
b2d9fb |
- p_tcpip_hdr->zeros = 0;
|
|
|
b2d9fb |
- p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
|
|
b2d9fb |
- p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- p_tcp_hdr->th_sum = 0;
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
|
|
b2d9fb |
- tcp_checksum);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- p_tcp_hdr->th_sum = tcp_checksum;
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* restore IP header */
|
|
|
b2d9fb |
- memcpy(eth_payload_data, saved_ip_header, hlen);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* set IP data length and recalculate IP checksum */
|
|
|
b2d9fb |
- ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* increment IP id for subsequent frames */
|
|
|
b2d9fb |
- ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- ip->ip_sum = 0;
|
|
|
b2d9fb |
- ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode TSO IP header len=%d "
|
|
|
b2d9fb |
- "checksum=%04x\n", hlen, ip->ip_sum);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode TSO transferring packet size "
|
|
|
b2d9fb |
- "%d\n", tso_send_size);
|
|
|
b2d9fb |
- rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
|
|
b2d9fb |
- 0, (uint8_t *) dot1q_buffer);
|
|
|
b2d9fb |
-
|
|
|
b2d9fb |
- /* add transferred count to TCP sequence number */
|
|
|
b2d9fb |
- p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
|
|
b2d9fb |
- ++send_count;
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
+ int is_last_frame = 0;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* Stop sending this frame */
|
|
|
b2d9fb |
- saved_size = 0;
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
- else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
|
|
b2d9fb |
+ for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
|
|
b2d9fb |
{
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
|
|
b2d9fb |
+ uint16_t chunk_size = tcp_chunk_size;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* maximum IP header length is 60 bytes */
|
|
|
b2d9fb |
- uint8_t saved_ip_header[60];
|
|
|
b2d9fb |
- memcpy(saved_ip_header, eth_payload_data, hlen);
|
|
|
b2d9fb |
+ /* check if this is the last frame */
|
|
|
b2d9fb |
+ if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
|
|
b2d9fb |
+ {
|
|
|
b2d9fb |
+ is_last_frame = 1;
|
|
|
b2d9fb |
+ chunk_size = tcp_data_len - tcp_send_offset;
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
|
|
b2d9fb |
- // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
|
|
b2d9fb |
+ be32_to_cpu(p_tcp_hdr->th_seq));
|
|
|
b2d9fb |
|
|
|
b2d9fb |
/* add 4 TCP pseudoheader fields */
|
|
|
b2d9fb |
/* copy IP source and destination fields */
|
|
|
b2d9fb |
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
|
|
b2d9fb |
+ "packet with %d bytes data\n", tcp_hlen +
|
|
|
b2d9fb |
+ chunk_size);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ if (tcp_send_offset)
|
|
|
b2d9fb |
{
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode calculating TCP checksum for "
|
|
|
b2d9fb |
- "packet with %d bytes data\n", ip_data_len);
|
|
|
b2d9fb |
+ memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
|
b2d9fb |
- p_tcpip_hdr->zeros = 0;
|
|
|
b2d9fb |
- p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
|
|
b2d9fb |
- p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
|
|
b2d9fb |
+ /* keep PUSH and FIN flags only for the last frame */
|
|
|
b2d9fb |
+ if (!is_last_frame)
|
|
|
b2d9fb |
+ {
|
|
|
b2d9fb |
+ TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
|
|
b2d9fb |
+ /* recalculate TCP checksum */
|
|
|
b2d9fb |
+ ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
|
b2d9fb |
+ p_tcpip_hdr->zeros = 0;
|
|
|
b2d9fb |
+ p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
|
|
b2d9fb |
+ p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- p_tcp_hdr->th_sum = 0;
|
|
|
b2d9fb |
+ p_tcp_hdr->th_sum = 0;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
|
|
b2d9fb |
- tcp_checksum);
|
|
|
b2d9fb |
+ int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
|
|
b2d9fb |
+ tcp_checksum);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- p_tcp_hdr->th_sum = tcp_checksum;
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
- else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
|
|
b2d9fb |
- {
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode calculating UDP checksum for "
|
|
|
b2d9fb |
- "packet with %d bytes data\n", ip_data_len);
|
|
|
b2d9fb |
+ p_tcp_hdr->th_sum = tcp_checksum;
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
|
b2d9fb |
- p_udpip_hdr->zeros = 0;
|
|
|
b2d9fb |
- p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
|
|
b2d9fb |
- p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
|
|
b2d9fb |
+ /* restore IP header */
|
|
|
b2d9fb |
+ memcpy(eth_payload_data, saved_ip_header, hlen);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
|
|
b2d9fb |
+ /* set IP data length and recalculate IP checksum */
|
|
|
b2d9fb |
+ ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- p_udp_hdr->uh_sum = 0;
|
|
|
b2d9fb |
+ /* increment IP id for subsequent frames */
|
|
|
b2d9fb |
+ ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
|
|
b2d9fb |
- DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
|
|
b2d9fb |
- udp_checksum);
|
|
|
b2d9fb |
+ ip->ip_sum = 0;
|
|
|
b2d9fb |
+ ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode TSO IP header len=%d "
|
|
|
b2d9fb |
+ "checksum=%04x\n", hlen, ip->ip_sum);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- p_udp_hdr->uh_sum = udp_checksum;
|
|
|
b2d9fb |
- }
|
|
|
b2d9fb |
+ int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode TSO transferring packet size "
|
|
|
b2d9fb |
+ "%d\n", tso_send_size);
|
|
|
b2d9fb |
+ rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
|
|
b2d9fb |
+ 0, (uint8_t *) dot1q_buffer);
|
|
|
b2d9fb |
|
|
|
b2d9fb |
- /* restore IP header */
|
|
|
b2d9fb |
- memcpy(eth_payload_data, saved_ip_header, hlen);
|
|
|
b2d9fb |
+ /* add transferred count to TCP sequence number */
|
|
|
b2d9fb |
+ p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
|
|
b2d9fb |
+ ++send_count;
|
|
|
b2d9fb |
}
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ /* Stop sending this frame */
|
|
|
b2d9fb |
+ saved_size = 0;
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
+ else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
|
|
b2d9fb |
+ {
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ /* maximum IP header length is 60 bytes */
|
|
|
b2d9fb |
+ uint8_t saved_ip_header[60];
|
|
|
b2d9fb |
+ memcpy(saved_ip_header, eth_payload_data, hlen);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
|
|
b2d9fb |
+ // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ /* add 4 TCP pseudoheader fields */
|
|
|
b2d9fb |
+ /* copy IP source and destination fields */
|
|
|
b2d9fb |
+ memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
|
|
b2d9fb |
+ {
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode calculating TCP checksum for "
|
|
|
b2d9fb |
+ "packet with %d bytes data\n", ip_data_len);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
|
b2d9fb |
+ p_tcpip_hdr->zeros = 0;
|
|
|
b2d9fb |
+ p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
|
|
b2d9fb |
+ p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ p_tcp_hdr->th_sum = 0;
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
|
|
b2d9fb |
+ tcp_checksum);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ p_tcp_hdr->th_sum = tcp_checksum;
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
+ else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
|
|
b2d9fb |
+ {
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode calculating UDP checksum for "
|
|
|
b2d9fb |
+ "packet with %d bytes data\n", ip_data_len);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
|
|
b2d9fb |
+ p_udpip_hdr->zeros = 0;
|
|
|
b2d9fb |
+ p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
|
|
b2d9fb |
+ p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ p_udp_hdr->uh_sum = 0;
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
|
|
b2d9fb |
+ DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
|
|
b2d9fb |
+ udp_checksum);
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ p_udp_hdr->uh_sum = udp_checksum;
|
|
|
b2d9fb |
+ }
|
|
|
b2d9fb |
+
|
|
|
b2d9fb |
+ /* restore IP header */
|
|
|
b2d9fb |
+ memcpy(eth_payload_data, saved_ip_header, hlen);
|
|
|
b2d9fb |
}
|
|
|
b2d9fb |
}
|
|
|
b2d9fb |
|
|
|
b2d9fb |
--
|
|
|
b2d9fb |
1.8.3.1
|
|
|
b2d9fb |
|