Commit 65d4ed92 authored by Masahide NAKAMURA's avatar Masahide NAKAMURA Committed by David S. Miller

[IPV6] MIP6: Add inbound interface of routing header type 2.

Add inbound interface of routing header type 2 for Mobile IPv6.
Based on MIPL2 kernel patch.

This patch was also written by: Ville Nuorvala <vnuorval@tcs.hut.fi>
Signed-off-by: default avatarMasahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 642ec62e
...@@ -61,6 +61,13 @@ extern int addrconf_set_dstaddr(void __user *arg); ...@@ -61,6 +61,13 @@ extern int addrconf_set_dstaddr(void __user *arg);
extern int ipv6_chk_addr(struct in6_addr *addr, extern int ipv6_chk_addr(struct in6_addr *addr,
struct net_device *dev, struct net_device *dev,
int strict); int strict);
/* XXX: this is a placeholder till addrconf supports */
#ifdef CONFIG_IPV6_MIP6
static inline int ipv6_chk_home_addr(struct in6_addr *addr)
{
return 0;
}
#endif
extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr,
struct net_device *dev, struct net_device *dev,
int strict); int strict);
......
...@@ -43,6 +43,9 @@ ...@@ -43,6 +43,9 @@
#include <net/ndisc.h> #include <net/ndisc.h>
#include <net/ip6_route.h> #include <net/ip6_route.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#ifdef CONFIG_IPV6_MIP6
#include <net/xfrm.h>
#endif
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -219,7 +222,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) ...@@ -219,7 +222,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
{ {
struct sk_buff *skb = *skbp; struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb); struct inet6_skb_parm *opt = IP6CB(skb);
struct in6_addr *addr; struct in6_addr *addr = NULL;
struct in6_addr daddr; struct in6_addr daddr;
int n, i; int n, i;
...@@ -244,6 +247,23 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) ...@@ -244,6 +247,23 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
looped_back: looped_back:
if (hdr->segments_left == 0) { if (hdr->segments_left == 0) {
switch (hdr->type) {
#ifdef CONFIG_IPV6_MIP6
case IPV6_SRCRT_TYPE_2:
/* Silently discard type 2 header unless it was
* processed by own
*/
if (!addr) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
break;
#endif
default:
break;
}
opt->lastopt = skb->h.raw - skb->nh.raw; opt->lastopt = skb->h.raw - skb->nh.raw;
opt->srcrt = skb->h.raw - skb->nh.raw; opt->srcrt = skb->h.raw - skb->nh.raw;
skb->h.raw += (hdr->hdrlen + 1) << 3; skb->h.raw += (hdr->hdrlen + 1) << 3;
...@@ -253,15 +273,27 @@ looped_back: ...@@ -253,15 +273,27 @@ looped_back:
return 1; return 1;
} }
if (hdr->type != IPV6_SRCRT_TYPE_0) { switch (hdr->type) {
case IPV6_SRCRT_TYPE_0:
if (hdr->hdrlen & 0x01) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
return -1; return -1;
} }
break;
if (hdr->hdrlen & 0x01) { #ifdef CONFIG_IPV6_MIP6
case IPV6_SRCRT_TYPE_2:
/* Silently discard invalid RTH type 2 */
if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); kfree_skb(skb);
return -1;
}
break;
#endif
default:
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
return -1; return -1;
} }
...@@ -303,6 +335,27 @@ looped_back: ...@@ -303,6 +335,27 @@ looped_back:
addr = rthdr->addr; addr = rthdr->addr;
addr += i - 1; addr += i - 1;
switch (hdr->type) {
#ifdef CONFIG_IPV6_MIP6
case IPV6_SRCRT_TYPE_2:
if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
(xfrm_address_t *)&skb->nh.ipv6h->saddr,
IPPROTO_ROUTING) < 0) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
if (!ipv6_chk_home_addr(addr)) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
break;
#endif
default:
break;
}
if (ipv6_addr_is_multicast(addr)) { if (ipv6_addr_is_multicast(addr)) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb); kfree_skb(skb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment