diff options
Diffstat (limited to 'net/ipv6/ip6mr.c')
-rw-r--r-- | net/ipv6/ip6mr.c | 139 |
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 */ | ||
1021 | static 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 */ | ||
1037 | static 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 | |||
1060 | skip: | ||
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 | ||
1250 | static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) | 1294 | static 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 |
1324 | proc_cache_fail: | 1371 | proc_cache_fail: |
1325 | proc_net_remove(net, "ip6_mr_vif"); | 1372 | remove_proc_entry("ip6_mr_vif", net->proc_net); |
1326 | proc_vif_fail: | 1373 | proc_vif_fail: |
1327 | ip6mr_rules_exit(net); | 1374 | ip6mr_rules_exit(net); |
1328 | #endif | 1375 | #endif |
@@ -1333,8 +1380,8 @@ fail: | |||
1333 | static void __net_exit ip6mr_net_exit(struct net *net) | 1380 | static 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 | ||
1393 | static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | 1440 | static 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 | ||
1597 | int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) | 1647 | int 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 | ||
2117 | forward: | ||
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 | } |
2151 | last_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; |