Re: mbuf_outbound_finalize() reports packet length is less than mbuf length
Re: mbuf_outbound_finalize() reports packet length is less than mbuf length
- Subject: Re: mbuf_outbound_finalize() reports packet length is less than mbuf length
- From: Brendan Creane <email@hidden>
- Date: Mon, 27 Jul 2009 12:49:05 -0700
I tested a new xnu kernel with a fix for the problem I'm seeing in
in_delayed_cksum_offset(), and everything seems to work. The problem
with mbuf_outbound_finalize() happens when you pass in a packet that
has the eth or dlt information in the first mbuf, and then the ip
struct and other payload in subsequent mbufs. The change is to
substitute "m" for "m0" when examining the ip length:
ip_len = ip->ip_len;
if (ip_len != (m->m_pkthdr.len - ip_offset)) {
ip_len = SWAP16(ip_len);
if (ip_len != (m->m_pkthdr.len - ip_offset)) {
printf("in_delayed_cksum_offset: ip_len %d (%d) "
"doesn't match actual length %d\n", ip->ip_len,
ip_len, (m->m_pkthdr.len - ip_offset));
return;
}
}
This problem combined with mbuf_outbound_finalize() inability to
handle host-order ip length field in earlier versions (xnu-792.13.8 or
older) means the function is pretty much useless.
At this point, I'm going to file a radar bug and (reluctantly) do my
own checksum finalizing.
Thanks to everyone for your questions and comments.
cheers, Brendan Creane
ps This problem underscores the need for an errno_t return from
mbuf_outbound_finalize() -- when it fails, the checksum is
uncalculated, but the client nke doesn't know this until it does it's
own checksum calculations.
On Mon, Jul 27, 2009 at 10:37 AM, Brendan Creane<email@hidden> wrote:
> I think the host order ip_len bug is fixed in xnu-1228.12.14, at line
> 1682 of ip_output.c, it's trying both the network and host order of
> ip_len:
>
> /*
> * We could be in the context of an IP or interface filter; in the
> * former case, ip_len would be in host (correct) order while for
> * the latter it would be in network order. Because of this, we
> * attempt to interpret the length field by comparing it against
> * the actual packet length. If the comparison fails, byte swap
> * the length and check again. If it still fails, then the packet
> * is bogus and we give up.
> */
> ip_len = ip->ip_len;
> if (ip_len != (m0->m_pkthdr.len - ip_offset)) {
> ip_len = SWAP16(ip_len);
> if (ip_len != (m0->m_pkthdr.len - ip_offset)) {
> printf("in_delayed_cksum_offset: ip_len %d (%d) "
> "doesn't match actual length %d\n", ip->ip_len,
> ip_len, (m0->m_pkthdr.len - ip_offset));
> return;
> }
> }
>
> regards, Brendan
>
> On Mon, Jul 27, 2009 at 10:25 AM, Kevin Brock<email@hidden> wrote:
>> Brendan Creane wrote:
>>>
>>> Thanks for your response Drew. My code fragment is:
>>>
>>> /*============================================*/
>>> errno_t
>>> drv::Filter::enet_output_func(ifnet_t interface, protocol_family_t
>>> protocol, mbuf_t *first_buf)
>>> {
>>> if (protocol != AF_INET && protocol != AF_UNSPEC)
>>> return KERN_SUCCESS;
>>>
>>> mbuf_t m = *first_buf;
>>>
>>> // check whether we've seen this packet previously
>>> if (check_mbuf_tag(m, OUTBOUND_DONE))
>>> return KERN_SUCCESS;
>>>
>>> mbuf_outbound_finalize(m, protocol, ifnet_hdrlen(interface));
>>> // process the packet ...
>>> /*============================================*/
>>>
>>> The exact message from in_delayed_cksum_offset() is:
>>> "in_delayed_cksum_offset: ip_len 49408 (193) doesn't match actual length
>>> 207"
>>>
>>>
>>
>> You need to byte swap the IP length field. mbuf_outbound_finalize does its
>> length calculations in host byte order, not network byte order.
>> This bug's been in there for a *long* time, and they still haven't bothered
>> to document or fix it...
>>
>> Here's the code that works for me (I've cut out error checking for brevity):
>>
>> struct ip* ip_hdr = get_ip_ptr(mbuf, ip_offset);
>> ip_hdr->ip_len = htons(ip_hdr->ip_len);
>> mbuf_outbound_finalize(mbuf, AF_INET, ip_offset);
>> // Get it again in case things were reorganized?
>> ip_hdr = get_ip_ptr(mbuf, ip_offset);
>> ip_hdr->ip_len = htons(ip_hdr->ip_len);
>>
>> Where get_ip_ptr is my own function that gets the pointer to the IP header,
>> and the protocol in my case is always AF_INET...
>>
>> Kevin
>>
>>
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden