aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Goff <thomas.goff@boeing.com>2009-01-28 01:39:59 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-28 01:39:59 -0500
commit1d6e55f195128813f96458203a9fa14204f9251e (patch)
tree8fb8d332a9d5a0df98401f0b49a86173a0c3f25a
parent6c06a478c9e59d1584a5dc1b2b3519bae5d6546a (diff)
IPv6: Fix multicast routing bugs.
This patch addresses the IPv6 multicast routing issues described below. It was tested with XORP 1.4/1.5 as the IPv6 PIM-SM routing daemon against FreeBSD peers. net/ipv6/ip6_input.c: - Don't try to forward link-local multicast packets. - Don't reset skb2->dev before calling ip6_mr_input() so packets can be identified as coming from the PIM register vif properly. net/ipv6/ip6mr.c: - Fix incoming PIM register messages processing: * The IPv6 pseudo-header should be included when checksumming PIM messages (RFC 4601 section 4.9; RFC 3973 section 4.7.1). * Packets decapsulated from PIM register messages should have skb->protocol ETH_P_IPV6. - Enable/disable IPv6 multicast forwarding on the corresponding interface when a routing daemon adds/removes a multicast virtual interface. - Remove incorrect skb_pull() to fix userspace signaling. - Enable/disable global IPv6 multicast forwarding when an IPv6 multicast routing socket is opened/closed. net/ipv6/route.c: - Don't use strict routing logic for packets decapsulated from PIM register messages (similar to disabling rp_filter for the IPv4 case). Signed-off-by: Thomas Goff <thomas.goff@boeing.com> Reviewed-by: Fred Templin <fred.l.templin@boeing.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/ip6_input.c2
-rw-r--r--net/ipv6/ip6mr.c23
-rw-r--r--net/ipv6/route.c2
3 files changed, 20 insertions, 7 deletions
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 936f48946e20..f171e8dbac91 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -255,6 +255,7 @@ int ip6_mc_input(struct sk_buff *skb)
255 * IPv6 multicast router mode is now supported ;) 255 * IPv6 multicast router mode is now supported ;)
256 */ 256 */
257 if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding && 257 if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding &&
258 !(ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) &&
258 likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { 259 likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
259 /* 260 /*
260 * Okay, we try to forward - split and duplicate 261 * Okay, we try to forward - split and duplicate
@@ -316,7 +317,6 @@ int ip6_mc_input(struct sk_buff *skb)
316 } 317 }
317 318
318 if (skb2) { 319 if (skb2) {
319 skb2->dev = skb2->dst->dev;
320 ip6_mr_input(skb2); 320 ip6_mr_input(skb2);
321 } 321 }
322 } 322 }
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 3c51b2d827f4..d19a84b79503 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -365,7 +365,9 @@ static int pim6_rcv(struct sk_buff *skb)
365 pim = (struct pimreghdr *)skb_transport_header(skb); 365 pim = (struct pimreghdr *)skb_transport_header(skb);
366 if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) || 366 if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) ||
367 (pim->flags & PIM_NULL_REGISTER) || 367 (pim->flags & PIM_NULL_REGISTER) ||
368 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && 368 (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
369 sizeof(*pim), IPPROTO_PIM,
370 csum_partial((void *)pim, sizeof(*pim), 0)) &&
369 csum_fold(skb_checksum(skb, 0, skb->len, 0)))) 371 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
370 goto drop; 372 goto drop;
371 373
@@ -392,7 +394,7 @@ static int pim6_rcv(struct sk_buff *skb)
392 skb_pull(skb, (u8 *)encap - skb->data); 394 skb_pull(skb, (u8 *)encap - skb->data);
393 skb_reset_network_header(skb); 395 skb_reset_network_header(skb);
394 skb->dev = reg_dev; 396 skb->dev = reg_dev;
395 skb->protocol = htons(ETH_P_IP); 397 skb->protocol = htons(ETH_P_IPV6);
396 skb->ip_summed = 0; 398 skb->ip_summed = 0;
397 skb->pkt_type = PACKET_HOST; 399 skb->pkt_type = PACKET_HOST;
398 dst_release(skb->dst); 400 dst_release(skb->dst);
@@ -481,6 +483,7 @@ static int mif6_delete(struct net *net, int vifi)
481{ 483{
482 struct mif_device *v; 484 struct mif_device *v;
483 struct net_device *dev; 485 struct net_device *dev;
486 struct inet6_dev *in6_dev;
484 if (vifi < 0 || vifi >= net->ipv6.maxvif) 487 if (vifi < 0 || vifi >= net->ipv6.maxvif)
485 return -EADDRNOTAVAIL; 488 return -EADDRNOTAVAIL;
486 489
@@ -513,6 +516,10 @@ static int mif6_delete(struct net *net, int vifi)
513 516
514 dev_set_allmulti(dev, -1); 517 dev_set_allmulti(dev, -1);
515 518
519 in6_dev = __in6_dev_get(dev);
520 if (in6_dev)
521 in6_dev->cnf.mc_forwarding--;
522
516 if (v->flags & MIFF_REGISTER) 523 if (v->flags & MIFF_REGISTER)
517 unregister_netdevice(dev); 524 unregister_netdevice(dev);
518 525
@@ -622,6 +629,7 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
622 int vifi = vifc->mif6c_mifi; 629 int vifi = vifc->mif6c_mifi;
623 struct mif_device *v = &net->ipv6.vif6_table[vifi]; 630 struct mif_device *v = &net->ipv6.vif6_table[vifi];
624 struct net_device *dev; 631 struct net_device *dev;
632 struct inet6_dev *in6_dev;
625 int err; 633 int err;
626 634
627 /* Is vif busy ? */ 635 /* Is vif busy ? */
@@ -662,6 +670,10 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
662 return -EINVAL; 670 return -EINVAL;
663 } 671 }
664 672
673 in6_dev = __in6_dev_get(dev);
674 if (in6_dev)
675 in6_dev->cnf.mc_forwarding++;
676
665 /* 677 /*
666 * Fill in the VIF structures 678 * Fill in the VIF structures
667 */ 679 */
@@ -838,8 +850,6 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
838 850
839 skb->dst = dst_clone(pkt->dst); 851 skb->dst = dst_clone(pkt->dst);
840 skb->ip_summed = CHECKSUM_UNNECESSARY; 852 skb->ip_summed = CHECKSUM_UNNECESSARY;
841
842 skb_pull(skb, sizeof(struct ipv6hdr));
843 } 853 }
844 854
845 if (net->ipv6.mroute6_sk == NULL) { 855 if (net->ipv6.mroute6_sk == NULL) {
@@ -1222,8 +1232,10 @@ static int ip6mr_sk_init(struct sock *sk)
1222 1232
1223 rtnl_lock(); 1233 rtnl_lock();
1224 write_lock_bh(&mrt_lock); 1234 write_lock_bh(&mrt_lock);
1225 if (likely(net->ipv6.mroute6_sk == NULL)) 1235 if (likely(net->ipv6.mroute6_sk == NULL)) {
1226 net->ipv6.mroute6_sk = sk; 1236 net->ipv6.mroute6_sk = sk;
1237 net->ipv6.devconf_all->mc_forwarding++;
1238 }
1227 else 1239 else
1228 err = -EADDRINUSE; 1240 err = -EADDRINUSE;
1229 write_unlock_bh(&mrt_lock); 1241 write_unlock_bh(&mrt_lock);
@@ -1242,6 +1254,7 @@ int ip6mr_sk_done(struct sock *sk)
1242 if (sk == net->ipv6.mroute6_sk) { 1254 if (sk == net->ipv6.mroute6_sk) {
1243 write_lock_bh(&mrt_lock); 1255 write_lock_bh(&mrt_lock);
1244 net->ipv6.mroute6_sk = NULL; 1256 net->ipv6.mroute6_sk = NULL;
1257 net->ipv6.devconf_all->mc_forwarding--;
1245 write_unlock_bh(&mrt_lock); 1258 write_unlock_bh(&mrt_lock);
1246 1259
1247 mroute_clean_tables(net); 1260 mroute_clean_tables(net);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c4a59824ac2c..9c574235c905 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -794,7 +794,7 @@ void ip6_route_input(struct sk_buff *skb)
794 .proto = iph->nexthdr, 794 .proto = iph->nexthdr,
795 }; 795 };
796 796
797 if (rt6_need_strict(&iph->daddr)) 797 if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG)
798 flags |= RT6_LOOKUP_F_IFACE; 798 flags |= RT6_LOOKUP_F_IFACE;
799 799
800 skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); 800 skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);