Commit 09c6bbf0 authored by Ville Nuorvala's avatar Ville Nuorvala Committed by David S. Miller

[IPV6]: Do mandatory IPv6 tunnel endpoint checks in realtime

Doing the mandatory tunnel endpoint checks when the tunnel is set up
isn't enough as interfaces can go up or down and addresses can be
added or deleted after this. The checks need to be done realtime when
the tunnel is processing a packet.
Signed-off-by: default avatarVille Nuorvala <vnuorval@tcs.hut.fi>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 567131a7
...@@ -494,6 +494,27 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph, ...@@ -494,6 +494,27 @@ static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
IP6_ECN_set_ce(inner_iph); IP6_ECN_set_ce(inner_iph);
} }
static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
{
struct ip6_tnl_parm *p = &t->parms;
int ret = 0;
if (p->flags & IP6_TNL_F_CAP_RCV) {
struct net_device *ldev = NULL;
if (p->link)
ldev = dev_get_by_index(p->link);
if ((ipv6_addr_is_multicast(&p->laddr) ||
likely(ipv6_chk_addr(&p->laddr, ldev, 0))) &&
likely(!ipv6_chk_addr(&p->raddr, NULL, 0)))
ret = 1;
if (ldev)
dev_put(ldev);
}
return ret;
}
/** /**
* ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
...@@ -518,7 +539,7 @@ ip6ip6_rcv(struct sk_buff *skb) ...@@ -518,7 +539,7 @@ ip6ip6_rcv(struct sk_buff *skb)
goto discard; goto discard;
} }
if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) { if (!ip6_tnl_rcv_ctl(t)) {
t->stat.rx_dropped++; t->stat.rx_dropped++;
read_unlock(&ip6ip6_lock); read_unlock(&ip6ip6_lock);
goto discard; goto discard;
...@@ -597,6 +618,34 @@ ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr) ...@@ -597,6 +618,34 @@ ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
} }
static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
{
struct ip6_tnl_parm *p = &t->parms;
int ret = 0;
if (p->flags & IP6_TNL_F_CAP_XMIT) {
struct net_device *ldev = NULL;
if (p->link)
ldev = dev_get_by_index(p->link);
if (unlikely(!ipv6_chk_addr(&p->laddr, ldev, 0)))
printk(KERN_WARNING
"%s xmit: Local address not yet configured!\n",
p->name);
else if (!ipv6_addr_is_multicast(&p->raddr) &&
unlikely(ipv6_chk_addr(&p->raddr, NULL, 0)))
printk(KERN_WARNING
"%s xmit: Routing loop! "
"Remote address found on this node!\n",
p->name);
else
ret = 1;
if (ldev)
dev_put(ldev);
}
return ret;
}
/** /**
* ip6ip6_tnl_xmit - encapsulate packet and send * ip6ip6_tnl_xmit - encapsulate packet and send
* @skb: the outgoing socket buffer * @skb: the outgoing socket buffer
...@@ -634,10 +683,9 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -634,10 +683,9 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_err; goto tx_err;
} }
if (skb->protocol != htons(ETH_P_IPV6) || if (skb->protocol != htons(ETH_P_IPV6) ||
!(t->parms.flags & IP6_TNL_F_CAP_XMIT) || !ip6_tnl_xmit_ctl(t) || ip6ip6_tnl_addr_conflict(t, ipv6h))
ip6ip6_tnl_addr_conflict(t, ipv6h)) {
goto tx_err; goto tx_err;
}
if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) { if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
struct ipv6_tlv_tnl_enc_lim *tel; struct ipv6_tlv_tnl_enc_lim *tel;
tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset]; tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
...@@ -768,40 +816,20 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -768,40 +816,20 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
static void ip6_tnl_set_cap(struct ip6_tnl *t) static void ip6_tnl_set_cap(struct ip6_tnl *t)
{ {
struct ip6_tnl_parm *p = &t->parms; struct ip6_tnl_parm *p = &t->parms;
struct in6_addr *laddr = &p->laddr; int ltype = ipv6_addr_type(&p->laddr);
struct in6_addr *raddr = &p->raddr; int rtype = ipv6_addr_type(&p->raddr);
int ltype = ipv6_addr_type(laddr);
int rtype = ipv6_addr_type(raddr);
p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV); p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY && if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
((ltype|rtype) & rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
(IPV6_ADDR_UNICAST| !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL| !((ltype|rtype) & IPV6_ADDR_LINKLOCAL)) {
IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
struct net_device *ldev = NULL;
int l_ok = 1;
int r_ok = 1;
if (p->link)
ldev = dev_get_by_index(p->link);
if (ltype&IPV6_ADDR_UNICAST && !ipv6_chk_addr(laddr, ldev, 0))
l_ok = 0;
if (rtype&IPV6_ADDR_UNICAST && ipv6_chk_addr(raddr, NULL, 0))
r_ok = 0;
if (l_ok && r_ok) {
if (ltype&IPV6_ADDR_UNICAST) if (ltype&IPV6_ADDR_UNICAST)
p->flags |= IP6_TNL_F_CAP_XMIT; p->flags |= IP6_TNL_F_CAP_XMIT;
if (rtype&IPV6_ADDR_UNICAST) if (rtype&IPV6_ADDR_UNICAST)
p->flags |= IP6_TNL_F_CAP_RCV; p->flags |= IP6_TNL_F_CAP_RCV;
} }
if (ldev)
dev_put(ldev);
}
} }
static void ip6ip6_tnl_link_config(struct ip6_tnl *t) static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
......
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