[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
(usagi-users 02675) transmitting a packet without the IPv6 header
- To: usagi-users@xxxxxxxxxxxxxx
- Subject: (usagi-users 02675) transmitting a packet without the IPv6 header
- From: Hiroaki Kago <kago@xxxxxxxxxxxxxx>
- Date: Mon, 08 Dec 2003 11:15:47 +0900
- Reply-to: kago@xxxxxxxxxxxxxx
- User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)
Hello,
I am using the USAGI snap usagi-linux24-s20031013 as a router box.
I met the problem of transmitting a packet without the IPv6 header.
When a router receives a packet with a Routing header and replaces
the destination address with contents of a Routing header,
it sends a packet without the IPv6 header.
Conditions show below:
1. When a valid Neighbor Advertisement is received, the target's
IPv6 address is recorded to the Destination Cache.
2. When the Destination Cache entry is valid, a packet
with a Routing header is received.
3. A router tries to replace the destination address with contents
of a Routing header, and sends a packet without the IPv6 header.
I think that skb->data should point out the head of IPv6 header
in the packet. But it points out the head of the Routing header.
So memcpy() copies the data at the wrong place.
----------
net/ipv6/ip6_output.c
static inline int ip6_output_finish(struct sk_buff *skb)
{
...
if (hh) {
int hh_alen;
read_lock_bh(&hh->hh_lock);
hh_alen = HH_DATA_ALIGN(hh->hh_len);
here ---> memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
read_unlock_bh(&hh->hh_lock);
skb_push(skb, hh->hh_len);
return hh->hh_output(skb);
} else if (dst->neighbour)
return dst->neighbour->output(skb);
kfree_skb(skb);
return -EINVAL;
}
----------
It is caused by the patch(*1) which deletes the ipv6_parse_exthdr()
function.
(*1) http://marc.theaimsgroup.com/?l=linux-kernel&m=104801278332604&w=2
Before the patch is applyed, ipv6_parse_exthdrs() is called
and returns the value "-1". So ip6_input_finish() is ended
and pskb_pull() isn't called.
But after the patch is applyed, pskb_pull() is called each time
and changes skb->data pointer.
----------
<before the patch is applyed>
static inline int ip6_input_finish(struct sk_buff *skb)
{
...
/* Skip hop-by-hop options, they are already parsed. */
if (nexthdr == NEXTHDR_HOP) {
nhoff = sizeof(struct ipv6hdr);
nexthdr = skb->h.raw[0];
skb->h.raw += (skb->h.raw[1]+1)<<3;
}
+- /* This check is sort of optimization.
| It would be stupid to detect for optional headers,
| which are missing with probability of 200%
| */
| if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
| nhoff = ipv6_parse_exthdrs(&skb, nhoff);
| if (nhoff < 0)
| return 0;
| nexthdr = skb->nh.raw[nhoff];
| hdr = skb->nh.ipv6h;
+- }
here---> if (!pskb_pull(skb, skb->h.raw - skb->data))
goto discard;
...
}
----------
----------
<after the patch is applyed>
static inline int ip6_input_finish(struct sk_buff *skb)
{
...
/* Skip hop-by-hop options, they are already parsed. */
if (nexthdr == NEXTHDR_HOP) {
nhoff = sizeof(struct ipv6hdr);
nexthdr = skb->h.raw[0];
skb->h.raw += (skb->h.raw[1]+1)<<3;
}
resubmit:
here---> if (!pskb_pull(skb, skb->h.raw - skb->data))
goto discard;
nexthdr = skb->nh.raw[nhoff];
...
}
----------
<before called pskb_pull()> <after called pskb_pull()>
skb->head=>+------------------+ skb->head=>+------------------+
|Header | |Header |
| (0x20=32) | | (0x20=32) |
+------------------+-+- +------------------+
|Ether Header |hh_alen |Ether Header |
| (0x10=16) |(0x10=16) | (0x10=16) |
skb->data=>+------------------+-+- +------------------+-+-
^^^^^^^^^ |IPv6 Header | | |IPv6 Header | |hh_alen
| (0x28=40) | | | (0x28=40) | |(0x10=16)
+------------------+ | skb->data=>+------------------+-+-
|Routing Header | | ^^^^^^^^^ |Routing Header | |
| (0x38=56) |skb_len | (0x38=56) | |skb_len
+------------------+(0x70=112) +------------------+ |(0x48=72)
|ICMPv6 EchoRequest| | |ICMPv6 EchoRequest| |
| (0x10=16) | | | (0x10=16) | |
skb->tail=>+------------------+-+- skb->tail=>+------------------+-+-
| | | |
skb->end =>+------------------+ skb->end =>+------------------+