Skip to content

Commit

Permalink
IPv6: Fix multicast routing bugs.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Fred Templin <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Thomas Goff authored and davem330 committed Jan 28, 2009
1 parent 6c06a47 commit 1d6e55f
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 7 deletions.
2 changes: 1 addition & 1 deletion net/ipv6/ip6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ int ip6_mc_input(struct sk_buff *skb)
* IPv6 multicast router mode is now supported ;)
*/
if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding &&
!(ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) &&
likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
/*
* Okay, we try to forward - split and duplicate
Expand Down Expand Up @@ -316,7 +317,6 @@ int ip6_mc_input(struct sk_buff *skb)
}

if (skb2) {
skb2->dev = skb2->dst->dev;
ip6_mr_input(skb2);
}
}
Expand Down
23 changes: 18 additions & 5 deletions net/ipv6/ip6mr.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,9 @@ static int pim6_rcv(struct sk_buff *skb)
pim = (struct pimreghdr *)skb_transport_header(skb);
if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) ||
(pim->flags & PIM_NULL_REGISTER) ||
(ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
sizeof(*pim), IPPROTO_PIM,
csum_partial((void *)pim, sizeof(*pim), 0)) &&
csum_fold(skb_checksum(skb, 0, skb->len, 0))))
goto drop;

Expand All @@ -392,7 +394,7 @@ static int pim6_rcv(struct sk_buff *skb)
skb_pull(skb, (u8 *)encap - skb->data);
skb_reset_network_header(skb);
skb->dev = reg_dev;
skb->protocol = htons(ETH_P_IP);
skb->protocol = htons(ETH_P_IPV6);
skb->ip_summed = 0;
skb->pkt_type = PACKET_HOST;
dst_release(skb->dst);
Expand Down Expand Up @@ -481,6 +483,7 @@ static int mif6_delete(struct net *net, int vifi)
{
struct mif_device *v;
struct net_device *dev;
struct inet6_dev *in6_dev;
if (vifi < 0 || vifi >= net->ipv6.maxvif)
return -EADDRNOTAVAIL;

Expand Down Expand Up @@ -513,6 +516,10 @@ static int mif6_delete(struct net *net, int vifi)

dev_set_allmulti(dev, -1);

in6_dev = __in6_dev_get(dev);
if (in6_dev)
in6_dev->cnf.mc_forwarding--;

if (v->flags & MIFF_REGISTER)
unregister_netdevice(dev);

Expand Down Expand Up @@ -622,6 +629,7 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
int vifi = vifc->mif6c_mifi;
struct mif_device *v = &net->ipv6.vif6_table[vifi];
struct net_device *dev;
struct inet6_dev *in6_dev;
int err;

/* Is vif busy ? */
Expand Down Expand Up @@ -662,6 +670,10 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
return -EINVAL;
}

in6_dev = __in6_dev_get(dev);
if (in6_dev)
in6_dev->cnf.mc_forwarding++;

/*
* Fill in the VIF structures
*/
Expand Down Expand Up @@ -838,8 +850,6 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,

skb->dst = dst_clone(pkt->dst);
skb->ip_summed = CHECKSUM_UNNECESSARY;

skb_pull(skb, sizeof(struct ipv6hdr));
}

if (net->ipv6.mroute6_sk == NULL) {
Expand Down Expand Up @@ -1222,8 +1232,10 @@ static int ip6mr_sk_init(struct sock *sk)

rtnl_lock();
write_lock_bh(&mrt_lock);
if (likely(net->ipv6.mroute6_sk == NULL))
if (likely(net->ipv6.mroute6_sk == NULL)) {
net->ipv6.mroute6_sk = sk;
net->ipv6.devconf_all->mc_forwarding++;
}
else
err = -EADDRINUSE;
write_unlock_bh(&mrt_lock);
Expand All @@ -1242,6 +1254,7 @@ int ip6mr_sk_done(struct sock *sk)
if (sk == net->ipv6.mroute6_sk) {
write_lock_bh(&mrt_lock);
net->ipv6.mroute6_sk = NULL;
net->ipv6.devconf_all->mc_forwarding--;
write_unlock_bh(&mrt_lock);

mroute_clean_tables(net);
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ void ip6_route_input(struct sk_buff *skb)
.proto = iph->nexthdr,
};

if (rt6_need_strict(&iph->daddr))
if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG)
flags |= RT6_LOOKUP_F_IFACE;

skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
Expand Down

0 comments on commit 1d6e55f

Please sign in to comment.