aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6mr.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6mr.c')
-rw-r--r--net/ipv6/ip6mr.c139
1 files changed, 121 insertions, 18 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 26dcdec9e3a5..96bfb4e4b820 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1017,6 +1017,50 @@ static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
1017 return NULL; 1017 return NULL;
1018} 1018}
1019 1019
1020/* Look for a (*,*,oif) entry */
1021static struct mfc6_cache *ip6mr_cache_find_any_parent(struct mr6_table *mrt,
1022 mifi_t mifi)
1023{
1024 int line = MFC6_HASH(&in6addr_any, &in6addr_any);
1025 struct mfc6_cache *c;
1026
1027 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1028 if (ipv6_addr_any(&c->mf6c_origin) &&
1029 ipv6_addr_any(&c->mf6c_mcastgrp) &&
1030 (c->mfc_un.res.ttls[mifi] < 255))
1031 return c;
1032
1033 return NULL;
1034}
1035
1036/* Look for a (*,G) entry */
1037static struct mfc6_cache *ip6mr_cache_find_any(struct mr6_table *mrt,
1038 struct in6_addr *mcastgrp,
1039 mifi_t mifi)
1040{
1041 int line = MFC6_HASH(mcastgrp, &in6addr_any);
1042 struct mfc6_cache *c, *proxy;
1043
1044 if (ipv6_addr_any(mcastgrp))
1045 goto skip;
1046
1047 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1048 if (ipv6_addr_any(&c->mf6c_origin) &&
1049 ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) {
1050 if (c->mfc_un.res.ttls[mifi] < 255)
1051 return c;
1052
1053 /* It's ok if the mifi is part of the static tree */
1054 proxy = ip6mr_cache_find_any_parent(mrt,
1055 c->mf6c_parent);
1056 if (proxy && proxy->mfc_un.res.ttls[mifi] < 255)
1057 return c;
1058 }
1059
1060skip:
1061 return ip6mr_cache_find_any_parent(mrt, mifi);
1062}
1063
1020/* 1064/*
1021 * Allocate a multicast cache entry 1065 * Allocate a multicast cache entry
1022 */ 1066 */
@@ -1247,7 +1291,8 @@ ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
1247 * MFC6 cache manipulation by user space 1291 * MFC6 cache manipulation by user space
1248 */ 1292 */
1249 1293
1250static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) 1294static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc,
1295 int parent)
1251{ 1296{
1252 int line; 1297 int line;
1253 struct mfc6_cache *c, *next; 1298 struct mfc6_cache *c, *next;
@@ -1256,7 +1301,9 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
1256 1301
1257 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) { 1302 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
1258 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && 1303 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
1259 ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { 1304 ipv6_addr_equal(&c->mf6c_mcastgrp,
1305 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1306 (parent == -1 || parent == c->mf6c_parent)) {
1260 write_lock_bh(&mrt_lock); 1307 write_lock_bh(&mrt_lock);
1261 list_del(&c->list); 1308 list_del(&c->list);
1262 write_unlock_bh(&mrt_lock); 1309 write_unlock_bh(&mrt_lock);
@@ -1312,9 +1359,9 @@ static int __net_init ip6mr_net_init(struct net *net)
1312 1359
1313#ifdef CONFIG_PROC_FS 1360#ifdef CONFIG_PROC_FS
1314 err = -ENOMEM; 1361 err = -ENOMEM;
1315 if (!proc_net_fops_create(net, "ip6_mr_vif", 0, &ip6mr_vif_fops)) 1362 if (!proc_create("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_fops))
1316 goto proc_vif_fail; 1363 goto proc_vif_fail;
1317 if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops)) 1364 if (!proc_create("ip6_mr_cache", 0, net->proc_net, &ip6mr_mfc_fops))
1318 goto proc_cache_fail; 1365 goto proc_cache_fail;
1319#endif 1366#endif
1320 1367
@@ -1322,7 +1369,7 @@ static int __net_init ip6mr_net_init(struct net *net)
1322 1369
1323#ifdef CONFIG_PROC_FS 1370#ifdef CONFIG_PROC_FS
1324proc_cache_fail: 1371proc_cache_fail:
1325 proc_net_remove(net, "ip6_mr_vif"); 1372 remove_proc_entry("ip6_mr_vif", net->proc_net);
1326proc_vif_fail: 1373proc_vif_fail:
1327 ip6mr_rules_exit(net); 1374 ip6mr_rules_exit(net);
1328#endif 1375#endif
@@ -1333,8 +1380,8 @@ fail:
1333static void __net_exit ip6mr_net_exit(struct net *net) 1380static void __net_exit ip6mr_net_exit(struct net *net)
1334{ 1381{
1335#ifdef CONFIG_PROC_FS 1382#ifdef CONFIG_PROC_FS
1336 proc_net_remove(net, "ip6_mr_cache"); 1383 remove_proc_entry("ip6_mr_cache", net->proc_net);
1337 proc_net_remove(net, "ip6_mr_vif"); 1384 remove_proc_entry("ip6_mr_vif", net->proc_net);
1338#endif 1385#endif
1339 ip6mr_rules_exit(net); 1386 ip6mr_rules_exit(net);
1340} 1387}
@@ -1391,7 +1438,7 @@ void ip6_mr_cleanup(void)
1391} 1438}
1392 1439
1393static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, 1440static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1394 struct mf6cctl *mfc, int mrtsock) 1441 struct mf6cctl *mfc, int mrtsock, int parent)
1395{ 1442{
1396 bool found = false; 1443 bool found = false;
1397 int line; 1444 int line;
@@ -1413,7 +1460,9 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1413 1460
1414 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { 1461 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
1415 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && 1462 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
1416 ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { 1463 ipv6_addr_equal(&c->mf6c_mcastgrp,
1464 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1465 (parent == -1 || parent == mfc->mf6cc_parent)) {
1417 found = true; 1466 found = true;
1418 break; 1467 break;
1419 } 1468 }
@@ -1430,7 +1479,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1430 return 0; 1479 return 0;
1431 } 1480 }
1432 1481
1433 if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) 1482 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1483 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
1434 return -EINVAL; 1484 return -EINVAL;
1435 1485
1436 c = ip6mr_cache_alloc(); 1486 c = ip6mr_cache_alloc();
@@ -1596,7 +1646,7 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
1596 1646
1597int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) 1647int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
1598{ 1648{
1599 int ret; 1649 int ret, parent = 0;
1600 struct mif6ctl vif; 1650 struct mif6ctl vif;
1601 struct mf6cctl mfc; 1651 struct mf6cctl mfc;
1602 mifi_t mifi; 1652 mifi_t mifi;
@@ -1653,15 +1703,21 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1653 */ 1703 */
1654 case MRT6_ADD_MFC: 1704 case MRT6_ADD_MFC:
1655 case MRT6_DEL_MFC: 1705 case MRT6_DEL_MFC:
1706 parent = -1;
1707 case MRT6_ADD_MFC_PROXY:
1708 case MRT6_DEL_MFC_PROXY:
1656 if (optlen < sizeof(mfc)) 1709 if (optlen < sizeof(mfc))
1657 return -EINVAL; 1710 return -EINVAL;
1658 if (copy_from_user(&mfc, optval, sizeof(mfc))) 1711 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1659 return -EFAULT; 1712 return -EFAULT;
1713 if (parent == 0)
1714 parent = mfc.mf6cc_parent;
1660 rtnl_lock(); 1715 rtnl_lock();
1661 if (optname == MRT6_DEL_MFC) 1716 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1662 ret = ip6mr_mfc_delete(mrt, &mfc); 1717 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
1663 else 1718 else
1664 ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk); 1719 ret = ip6mr_mfc_add(net, mrt, &mfc,
1720 sk == mrt->mroute6_sk, parent);
1665 rtnl_unlock(); 1721 rtnl_unlock();
1666 return ret; 1722 return ret;
1667 1723
@@ -1710,6 +1766,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1710 return -EINVAL; 1766 return -EINVAL;
1711 if (get_user(v, (u32 __user *)optval)) 1767 if (get_user(v, (u32 __user *)optval))
1712 return -EFAULT; 1768 return -EFAULT;
1769 /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1770 if (v != RT_TABLE_DEFAULT && v >= 100000000)
1771 return -EINVAL;
1713 if (sk == mrt->mroute6_sk) 1772 if (sk == mrt->mroute6_sk)
1714 return -EBUSY; 1773 return -EBUSY;
1715 1774
@@ -2015,19 +2074,29 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2015{ 2074{
2016 int psend = -1; 2075 int psend = -1;
2017 int vif, ct; 2076 int vif, ct;
2077 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
2018 2078
2019 vif = cache->mf6c_parent; 2079 vif = cache->mf6c_parent;
2020 cache->mfc_un.res.pkt++; 2080 cache->mfc_un.res.pkt++;
2021 cache->mfc_un.res.bytes += skb->len; 2081 cache->mfc_un.res.bytes += skb->len;
2022 2082
2083 if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) {
2084 struct mfc6_cache *cache_proxy;
2085
2086 /* For an (*,G) entry, we only check that the incomming
2087 * interface is part of the static tree.
2088 */
2089 cache_proxy = ip6mr_cache_find_any_parent(mrt, vif);
2090 if (cache_proxy &&
2091 cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
2092 goto forward;
2093 }
2094
2023 /* 2095 /*
2024 * Wrong interface: drop packet and (maybe) send PIM assert. 2096 * Wrong interface: drop packet and (maybe) send PIM assert.
2025 */ 2097 */
2026 if (mrt->vif6_table[vif].dev != skb->dev) { 2098 if (mrt->vif6_table[vif].dev != skb->dev) {
2027 int true_vifi;
2028
2029 cache->mfc_un.res.wrong_if++; 2099 cache->mfc_un.res.wrong_if++;
2030 true_vifi = ip6mr_find_vif(mrt, skb->dev);
2031 2100
2032 if (true_vifi >= 0 && mrt->mroute_do_assert && 2101 if (true_vifi >= 0 && mrt->mroute_do_assert &&
2033 /* pimsm uses asserts, when switching from RPT to SPT, 2102 /* pimsm uses asserts, when switching from RPT to SPT,
@@ -2045,14 +2114,32 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2045 goto dont_forward; 2114 goto dont_forward;
2046 } 2115 }
2047 2116
2117forward:
2048 mrt->vif6_table[vif].pkt_in++; 2118 mrt->vif6_table[vif].pkt_in++;
2049 mrt->vif6_table[vif].bytes_in += skb->len; 2119 mrt->vif6_table[vif].bytes_in += skb->len;
2050 2120
2051 /* 2121 /*
2052 * Forward the frame 2122 * Forward the frame
2053 */ 2123 */
2124 if (ipv6_addr_any(&cache->mf6c_origin) &&
2125 ipv6_addr_any(&cache->mf6c_mcastgrp)) {
2126 if (true_vifi >= 0 &&
2127 true_vifi != cache->mf6c_parent &&
2128 ipv6_hdr(skb)->hop_limit >
2129 cache->mfc_un.res.ttls[cache->mf6c_parent]) {
2130 /* It's an (*,*) entry and the packet is not coming from
2131 * the upstream: forward the packet to the upstream
2132 * only.
2133 */
2134 psend = cache->mf6c_parent;
2135 goto last_forward;
2136 }
2137 goto dont_forward;
2138 }
2054 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { 2139 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) {
2055 if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { 2140 /* For (*,G) entry, don't forward to the incoming interface */
2141 if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) &&
2142 ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
2056 if (psend != -1) { 2143 if (psend != -1) {
2057 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); 2144 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2058 if (skb2) 2145 if (skb2)
@@ -2061,6 +2148,7 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2061 psend = ct; 2148 psend = ct;
2062 } 2149 }
2063 } 2150 }
2151last_forward:
2064 if (psend != -1) { 2152 if (psend != -1) {
2065 ip6mr_forward2(net, mrt, skb, cache, psend); 2153 ip6mr_forward2(net, mrt, skb, cache, psend);
2066 return 0; 2154 return 0;
@@ -2096,6 +2184,14 @@ int ip6_mr_input(struct sk_buff *skb)
2096 read_lock(&mrt_lock); 2184 read_lock(&mrt_lock);
2097 cache = ip6mr_cache_find(mrt, 2185 cache = ip6mr_cache_find(mrt,
2098 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); 2186 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
2187 if (cache == NULL) {
2188 int vif = ip6mr_find_vif(mrt, skb->dev);
2189
2190 if (vif >= 0)
2191 cache = ip6mr_cache_find_any(mrt,
2192 &ipv6_hdr(skb)->daddr,
2193 vif);
2194 }
2099 2195
2100 /* 2196 /*
2101 * No usable cache entry 2197 * No usable cache entry
@@ -2183,6 +2279,13 @@ int ip6mr_get_route(struct net *net,
2183 2279
2184 read_lock(&mrt_lock); 2280 read_lock(&mrt_lock);
2185 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); 2281 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
2282 if (!cache && skb->dev) {
2283 int vif = ip6mr_find_vif(mrt, skb->dev);
2284
2285 if (vif >= 0)
2286 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2287 vif);
2288 }
2186 2289
2187 if (!cache) { 2290 if (!cache) {
2188 struct sk_buff *skb2; 2291 struct sk_buff *skb2;