Skip to content

Commit

Permalink
[IPV6] MIP6: Add inbound interface of home address option.
Browse files Browse the repository at this point in the history
Add inbound function of home address option by registering it to TLV
table for destination options header.

Based on MIPL2 kernel patch.

This patch was also written by: Ville Nuorvala <vnuorval@tcs.hut.fi>

Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Masahide NAKAMURA authored and David S. Miller committed Sep 22, 2006
1 parent 842426e commit a831f5b
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 1 deletion.
3 changes: 3 additions & 0 deletions include/linux/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ struct inet6_skb_parm {
__u16 dst0;
__u16 srcrt;
__u16 dst1;
#ifdef CONFIG_IPV6_MIP6
__u16 dsthao;
#endif
__u16 lastopt;
__u32 nhoff;
__u16 flags;
Expand Down
84 changes: 83 additions & 1 deletion net/ipv6/exthdrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,90 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
Destination options header.
*****************************/

#ifdef CONFIG_IPV6_MIP6
static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
{
struct sk_buff *skb = *skbp;
struct ipv6_destopt_hao *hao;
struct inet6_skb_parm *opt = IP6CB(skb);
struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw;
struct in6_addr tmp_addr;
int ret;

if (opt->dsthao) {
LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
goto discard;
}
opt->dsthao = opt->dst1;
opt->dst1 = 0;

hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);

if (hao->length != 16) {
LIMIT_NETDEBUG(
KERN_DEBUG "hao invalid option length = %d\n", hao->length);
goto discard;
}

if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
LIMIT_NETDEBUG(
KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
goto discard;
}

ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
(xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
if (unlikely(ret < 0))
goto discard;

if (skb_cloned(skb)) {
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
if (skb2 == NULL)
goto discard;

kfree_skb(skb);

/* update all variable using below by copied skbuff */
*skbp = skb = skb2;
hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff);
ipv6h = (struct ipv6hdr *)skb2->nh.raw;
}

if (skb->ip_summed == CHECKSUM_COMPLETE)
skb->ip_summed = CHECKSUM_NONE;

ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
ipv6_addr_copy(&hao->addr, &tmp_addr);

if (skb->tstamp.off_sec == 0)
__net_timestamp(skb);

return 1;

discard:
kfree_skb(skb);
return 0;
}
#endif

static struct tlvtype_proc tlvprocdestopt_lst[] = {
/* No destination options are defined now */
#ifdef CONFIG_IPV6_MIP6
{
.type = IPV6_TLV_HAO,
.func = ipv6_dest_hao,
},
#endif
{-1, NULL}
};

static int ipv6_destopt_rcv(struct sk_buff **skbp)
{
struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb);
#ifdef CONFIG_IPV6_MIP6
__u16 dstbuf;
#endif

if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
Expand All @@ -215,11 +290,18 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)

opt->lastopt = skb->h.raw - skb->nh.raw;
opt->dst1 = skb->h.raw - skb->nh.raw;
#ifdef CONFIG_IPV6_MIP6
dstbuf = opt->dst1;
#endif

if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
skb = *skbp;
skb->h.raw += ((skb->h.raw[1]+1)<<3);
#ifdef CONFIG_IPV6_MIP6
opt->nhoff = dstbuf;
#else
opt->nhoff = opt->dst1;
#endif
return 1;
}

Expand Down

0 comments on commit a831f5b

Please sign in to comment.