Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 34583
b: refs/heads/master
c: 27637df
h: refs/heads/master
i:
  34581: 1b802dc
  34579: 9c98c72
  34575: 1f35f1b
v: v3
  • Loading branch information
Masahide NAKAMURA authored and David S. Miller committed Sep 22, 2006
1 parent c237a06 commit 778db9d
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 793832361fe7e9c3fcae2edd1d293c583a0a095c
refs/heads/master: 27637df92e25dfb45dd71a93a2f4bf9c080fa627
109 changes: 109 additions & 0 deletions trunk/net/ipv6/ah6.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,68 @@ static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
return 0;
}

#ifdef CONFIG_IPV6_MIP6
/**
* ipv6_rearrange_destopt - rearrange IPv6 destination options header
* @iph: IPv6 header
* @destopt: destionation options header
*/
static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt)
{
u8 *opt = (u8 *)destopt;
int len = ipv6_optlen(destopt);
int off = 0;
int optlen = 0;

off += 2;
len -= 2;

while (len > 0) {

switch (opt[off]) {

case IPV6_TLV_PAD0:
optlen = 1;
break;
default:
if (len < 2)
goto bad;
optlen = opt[off+1]+2;
if (len < optlen)
goto bad;

/* Rearrange the source address in @iph and the
* addresses in home address option for final source.
* See 11.3.2 of RFC 3775 for details.
*/
if (opt[off] == IPV6_TLV_HAO) {
struct in6_addr final_addr;
struct ipv6_destopt_hao *hao;

hao = (struct ipv6_destopt_hao *)&opt[off];
if (hao->length != sizeof(hao->addr)) {
if (net_ratelimit())
printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length);
goto bad;
}
ipv6_addr_copy(&final_addr, &hao->addr);
ipv6_addr_copy(&hao->addr, &iph->saddr);
ipv6_addr_copy(&iph->saddr, &final_addr);
}
break;
}

off += optlen;
len -= optlen;
}
if (len == 0)
return;

bad:
return;
}
#endif

/**
* ipv6_rearrange_rthdr - rearrange IPv6 routing header
* @iph: IPv6 header
Expand Down Expand Up @@ -113,7 +175,11 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
ipv6_addr_copy(&iph->daddr, &final_addr);
}

#ifdef CONFIG_IPV6_MIP6
static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
#else
static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)
#endif
{
union {
struct ipv6hdr *iph;
Expand All @@ -128,6 +194,28 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)

while (exthdr.raw < end) {
switch (nexthdr) {
#ifdef CONFIG_IPV6_MIP6
case NEXTHDR_HOP:
if (!zero_out_mutable_opts(exthdr.opth)) {
LIMIT_NETDEBUG(
KERN_WARNING "overrun %sopts\n",
nexthdr == NEXTHDR_HOP ?
"hop" : "dest");
return -EINVAL;
}
break;
case NEXTHDR_DEST:
if (dir == XFRM_POLICY_OUT)
ipv6_rearrange_destopt(iph, exthdr.opth);
if (!zero_out_mutable_opts(exthdr.opth)) {
LIMIT_NETDEBUG(
KERN_WARNING "overrun %sopts\n",
nexthdr == NEXTHDR_HOP ?
"hop" : "dest");
return -EINVAL;
}
break;
#else
case NEXTHDR_HOP:
case NEXTHDR_DEST:
if (!zero_out_mutable_opts(exthdr.opth)) {
Expand All @@ -138,6 +226,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len)
return -EINVAL;
}
break;
#endif

case NEXTHDR_ROUTING:
ipv6_rearrange_rthdr(iph, exthdr.rth);
Expand All @@ -164,6 +253,9 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
u8 nexthdr;
char tmp_base[8];
struct {
#ifdef CONFIG_IPV6_MIP6
struct in6_addr saddr;
#endif
struct in6_addr daddr;
char hdrs[0];
} *tmp_ext;
Expand All @@ -188,10 +280,18 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
err = -ENOMEM;
goto error;
}
#ifdef CONFIG_IPV6_MIP6
memcpy(tmp_ext, &top_iph->saddr, extlen);
err = ipv6_clear_mutable_options(top_iph,
extlen - sizeof(*tmp_ext) +
sizeof(*top_iph),
XFRM_POLICY_OUT);
#else
memcpy(tmp_ext, &top_iph->daddr, extlen);
err = ipv6_clear_mutable_options(top_iph,
extlen - sizeof(*tmp_ext) +
sizeof(*top_iph));
#endif
if (err)
goto error_free_iph;
}
Expand Down Expand Up @@ -222,7 +322,11 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)

memcpy(top_iph, tmp_base, sizeof(tmp_base));
if (tmp_ext) {
#ifdef CONFIG_IPV6_MIP6
memcpy(&top_iph->saddr, tmp_ext, extlen);
#else
memcpy(&top_iph->daddr, tmp_ext, extlen);
#endif
error_free_iph:
kfree(tmp_ext);
}
Expand Down Expand Up @@ -282,8 +386,13 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
if (!tmp_hdr)
goto out;
memcpy(tmp_hdr, skb->nh.raw, hdr_len);
#ifdef CONFIG_IPV6_MIP6
if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len, XFRM_POLICY_IN))
goto free_out;
#else
if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len))
goto free_out;
#endif
skb->nh.ipv6h->priority = 0;
skb->nh.ipv6h->flow_lbl[0] = 0;
skb->nh.ipv6h->flow_lbl[1] = 0;
Expand Down
18 changes: 13 additions & 5 deletions trunk/net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,17 +475,25 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
switch (**nexthdr) {

case NEXTHDR_HOP:
break;
case NEXTHDR_ROUTING:
found_rhdr = 1;
break;
case NEXTHDR_DEST:
if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1;
if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset;
offset += ipv6_optlen(exthdr);
*nexthdr = &exthdr->nexthdr;
exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
#ifdef CONFIG_IPV6_MIP6
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
break;
#endif
if (found_rhdr)
return offset;
break;
default :
return offset;
}

offset += ipv6_optlen(exthdr);
*nexthdr = &exthdr->nexthdr;
exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
}

return offset;
Expand Down

0 comments on commit 778db9d

Please sign in to comment.