diff options
-rw-r--r-- | include/net/ip6_tunnel.h | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 65 |
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 | ||
687 | static __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() */ |
688 | static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) | 711 | static 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 | ||
1117 | static 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 | |||
1136 | static void ip6_tnl_link_config(struct ip6_tnl *t) | 1143 | static 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 | } |