aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip6_tunnel.h2
-rw-r--r--net/ipv6/ip6_tunnel.c65
2 files changed, 40 insertions, 27 deletions
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index fc73e667b50e..358fb86f57eb 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -9,6 +9,8 @@
9#define IP6_TNL_F_CAP_XMIT 0x10000 9#define IP6_TNL_F_CAP_XMIT 0x10000
10/* capable of receiving packets */ 10/* capable of receiving packets */
11#define IP6_TNL_F_CAP_RCV 0x20000 11#define IP6_TNL_F_CAP_RCV 0x20000
12/* determine capability on a per-packet basis */
13#define IP6_TNL_F_CAP_PER_PACKET 0x40000
12 14
13/* IPv6 tunnel */ 15/* IPv6 tunnel */
14 16
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c9015fad8d65..04a3cba2c123 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -684,24 +684,50 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
684 IP6_ECN_set_ce(ipv6_hdr(skb)); 684 IP6_ECN_set_ce(ipv6_hdr(skb));
685} 685}
686 686
687static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
688 const struct in6_addr *laddr,
689 const struct in6_addr *raddr)
690{
691 struct ip6_tnl_parm *p = &t->parms;
692 int ltype = ipv6_addr_type(laddr);
693 int rtype = ipv6_addr_type(raddr);
694 __u32 flags = 0;
695
696 if (ltype == IPV6_ADDR_ANY || rtype == IPV6_ADDR_ANY) {
697 flags = IP6_TNL_F_CAP_PER_PACKET;
698 } else if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
699 rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
700 !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
701 (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) {
702 if (ltype&IPV6_ADDR_UNICAST)
703 flags |= IP6_TNL_F_CAP_XMIT;
704 if (rtype&IPV6_ADDR_UNICAST)
705 flags |= IP6_TNL_F_CAP_RCV;
706 }
707 return flags;
708}
709
687/* called with rcu_read_lock() */ 710/* called with rcu_read_lock() */
688static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) 711static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
712 const struct in6_addr *laddr,
713 const struct in6_addr *raddr)
689{ 714{
690 struct ip6_tnl_parm *p = &t->parms; 715 struct ip6_tnl_parm *p = &t->parms;
691 int ret = 0; 716 int ret = 0;
692 struct net *net = dev_net(t->dev); 717 struct net *net = dev_net(t->dev);
693 718
694 if (p->flags & IP6_TNL_F_CAP_RCV) { 719 if ((p->flags & IP6_TNL_F_CAP_RCV) ||
720 ((p->flags & IP6_TNL_F_CAP_PER_PACKET) &&
721 (ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_RCV))) {
695 struct net_device *ldev = NULL; 722 struct net_device *ldev = NULL;
696 723
697 if (p->link) 724 if (p->link)
698 ldev = dev_get_by_index_rcu(net, p->link); 725 ldev = dev_get_by_index_rcu(net, p->link);
699 726
700 if ((ipv6_addr_is_multicast(&p->laddr) || 727 if ((ipv6_addr_is_multicast(laddr) ||
701 likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && 728 likely(ipv6_chk_addr(net, laddr, ldev, 0))) &&
702 likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) 729 likely(!ipv6_chk_addr(net, raddr, NULL, 0)))
703 ret = 1; 730 ret = 1;
704
705 } 731 }
706 return ret; 732 return ret;
707} 733}
@@ -740,7 +766,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
740 goto discard; 766 goto discard;
741 } 767 }
742 768
743 if (!ip6_tnl_rcv_ctl(t)) { 769 if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
744 t->dev->stats.rx_dropped++; 770 t->dev->stats.rx_dropped++;
745 rcu_read_unlock(); 771 rcu_read_unlock();
746 goto discard; 772 goto discard;
@@ -1114,25 +1140,6 @@ tx_err:
1114 return NETDEV_TX_OK; 1140 return NETDEV_TX_OK;
1115} 1141}
1116 1142
1117static void ip6_tnl_set_cap(struct ip6_tnl *t)
1118{
1119 struct ip6_tnl_parm *p = &t->parms;
1120 int ltype = ipv6_addr_type(&p->laddr);
1121 int rtype = ipv6_addr_type(&p->raddr);
1122
1123 p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
1124
1125 if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
1126 rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) &&
1127 !((ltype|rtype) & IPV6_ADDR_LOOPBACK) &&
1128 (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) {
1129 if (ltype&IPV6_ADDR_UNICAST)
1130 p->flags |= IP6_TNL_F_CAP_XMIT;
1131 if (rtype&IPV6_ADDR_UNICAST)
1132 p->flags |= IP6_TNL_F_CAP_RCV;
1133 }
1134}
1135
1136static void ip6_tnl_link_config(struct ip6_tnl *t) 1143static void ip6_tnl_link_config(struct ip6_tnl *t)
1137{ 1144{
1138 struct net_device *dev = t->dev; 1145 struct net_device *dev = t->dev;
@@ -1153,7 +1160,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
1153 if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) 1160 if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
1154 fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo; 1161 fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
1155 1162
1156 ip6_tnl_set_cap(t); 1163 p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
1164 p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
1157 1165
1158 if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV) 1166 if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
1159 dev->flags |= IFF_POINTOPOINT; 1167 dev->flags |= IFF_POINTOPOINT;
@@ -1438,6 +1446,9 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
1438 1446
1439 t->parms.proto = IPPROTO_IPV6; 1447 t->parms.proto = IPPROTO_IPV6;
1440 dev_hold(dev); 1448 dev_hold(dev);
1449
1450 ip6_tnl_link_config(t);
1451
1441 rcu_assign_pointer(ip6n->tnls_wc[0], t); 1452 rcu_assign_pointer(ip6n->tnls_wc[0], t);
1442 return 0; 1453 return 0;
1443} 1454}