On 1/29/02 8:10 AM, "Andrew Gallatin" <gallatin@cs.duke.edu> wrote:
Also, why does darwin not allow csum offloading for received ip
fragments using the CSUM_TCP_SUM16 method?
The CSUM_TCP_SUM16 flag is used to indicate that the GMAC's checksum is
being used. The GMAC hardware checksum has some limitations. There are a lot
of checks for the various limitations to avoid cases where the hardware does
the wrong thing. I believe IP fragments may be one of the cases where the
chipset does the wrong thing.
Hehe.. Yes, but all the world's not a GMAC. It appears that the GMAC
specific code has replaced the general code. Eg, if you set
CSUM_DATA_VALID without setting CSUM_TCP_SUM16, you're ignored. The
only to not be ignored is to set either CSUM_PSEUDO_HDR or
CSUM_TCP_SUM16. Setting CSUM_PSEUDO_HDR gives me the same problem --
no frags can be dealt with unless I want to implement reassembly in my
driver (I don't). So I'm screwed either way.
CSUM_TCP_SUM16 is only for the GMAC hardware, you shouldn't need to set it for your hardware. It only causes some weird special case code to be executed. Ideally, you should be able to get things working with the other flags. The hardware checksum support in the kernel is still new, so it may contain some rough edges you'll get snagged on, as you're noticing. Some of this is addressed on a branch we're working on. I don't recall what the psuedo header does. Perhaps someone else can help out there. I do know that you can't perform hardware udp/tcp checksums on fragmented packets unless you're going to handle reassembly in your hardware. The UDP or TCP checksum is in the first fragment that contains the UDP or TCP header. All other fragments of the packet contain the IP header followed by UDP or TCP data. You can't calculate the UDP/TCP checksum until you've collected all fragments. I believe most stacks avoid TCP fragmentation, so I doubt you'll see much if any of that. This will still be a problem from UDP though.
There should be a 3rd case. Eg:
--- tcp_input.c Sun Dec 16 10:59:16 2001
+++ tcp_input.c.new Tue Jan 29 11:06:45 2002
@@ -520,7 +520,10 @@
else {
if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
th->th_sum = m->m_pkthdr.csum_data;
- else goto dotcpcksum;
+ else
+ th->th_sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htonl(m->m_pkthdr.csum_data +
+ ip->ip_len + IPPROTO_TCP));
}
th->th_sum ^= 0xffff;
I believe you're right. In fact, something very similar to this is done in FreeBSD 4.4. We have these changes on a branch that we're hoping to get in to xnu some time soon. If you'd like to be able to track the progress, you're welcome to file a bug. -josh