diff options
author | Thomas Goff <thomas.goff@boeing.com> | 2009-01-28 01:39:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-28 01:39:59 -0500 |
commit | 1d6e55f195128813f96458203a9fa14204f9251e (patch) | |
tree | 8fb8d332a9d5a0df98401f0b49a86173a0c3f25a | |
parent | 6c06a478c9e59d1584a5dc1b2b3519bae5d6546a (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.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 23 | ||||
-rw-r--r-- | net/ipv6/route.c | 2 |
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); |