Bluetooth: bnep: bnep_add_connection() should verify that it's dealing with l2cap...
[pandora-kernel.git] / net / bridge / br_multicast.c
index a5f4e57..5f21e53 100644 (file)
@@ -36,6 +36,9 @@
 #define mlock_dereference(X, br) \
        rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
 
+static void br_multicast_add_router(struct net_bridge *br,
+                                   struct net_bridge_port *port);
+
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 static inline int ipv6_is_transient_multicast(const struct in6_addr *addr)
 {
@@ -241,7 +244,6 @@ static void br_multicast_group_expired(unsigned long data)
        hlist_del_rcu(&mp->hlist[mdb->ver]);
        mdb->size--;
 
-       del_timer(&mp->query_timer);
        call_rcu_bh(&mp->rcu, br_multicast_free_group);
 
 out:
@@ -271,7 +273,6 @@ static void br_multicast_del_pg(struct net_bridge *br,
                rcu_assign_pointer(*pp, p->next);
                hlist_del_init(&p->mglist);
                del_timer(&p->timer);
-               del_timer(&p->query_timer);
                call_rcu_bh(&p->rcu, br_multicast_free_pg);
 
                if (!mp->ports && !mp->mglist &&
@@ -446,8 +447,11 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        ip6h->nexthdr = IPPROTO_HOPOPTS;
        ip6h->hop_limit = 1;
        ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1));
-       ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
-                          &ip6h->saddr);
+       if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
+                              &ip6h->saddr)) {
+               kfree_skb(skb);
+               return NULL;
+       }
        ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
 
        hopopt = (u8 *)(ip6h + 1);
@@ -466,8 +470,9 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        skb_set_transport_header(skb, skb->len);
        mldq = (struct mld_msg *) icmp6_hdr(skb);
 
-       interval = ipv6_addr_any(group) ? br->multicast_last_member_interval :
-                                         br->multicast_query_response_interval;
+       interval = ipv6_addr_any(group) ?
+                       br->multicast_query_response_interval :
+                       br->multicast_last_member_interval;
 
        mldq->mld_type = ICMPV6_MGM_QUERY;
        mldq->mld_code = 0;
@@ -504,74 +509,6 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
        return NULL;
 }
 
-static void br_multicast_send_group_query(struct net_bridge_mdb_entry *mp)
-{
-       struct net_bridge *br = mp->br;
-       struct sk_buff *skb;
-
-       skb = br_multicast_alloc_query(br, &mp->addr);
-       if (!skb)
-               goto timer;
-
-       netif_rx(skb);
-
-timer:
-       if (++mp->queries_sent < br->multicast_last_member_count)
-               mod_timer(&mp->query_timer,
-                         jiffies + br->multicast_last_member_interval);
-}
-
-static void br_multicast_group_query_expired(unsigned long data)
-{
-       struct net_bridge_mdb_entry *mp = (void *)data;
-       struct net_bridge *br = mp->br;
-
-       spin_lock(&br->multicast_lock);
-       if (!netif_running(br->dev) || !mp->mglist ||
-           mp->queries_sent >= br->multicast_last_member_count)
-               goto out;
-
-       br_multicast_send_group_query(mp);
-
-out:
-       spin_unlock(&br->multicast_lock);
-}
-
-static void br_multicast_send_port_group_query(struct net_bridge_port_group *pg)
-{
-       struct net_bridge_port *port = pg->port;
-       struct net_bridge *br = port->br;
-       struct sk_buff *skb;
-
-       skb = br_multicast_alloc_query(br, &pg->addr);
-       if (!skb)
-               goto timer;
-
-       br_deliver(port, skb);
-
-timer:
-       if (++pg->queries_sent < br->multicast_last_member_count)
-               mod_timer(&pg->query_timer,
-                         jiffies + br->multicast_last_member_interval);
-}
-
-static void br_multicast_port_group_query_expired(unsigned long data)
-{
-       struct net_bridge_port_group *pg = (void *)data;
-       struct net_bridge_port *port = pg->port;
-       struct net_bridge *br = port->br;
-
-       spin_lock(&br->multicast_lock);
-       if (!netif_running(br->dev) || hlist_unhashed(&pg->mglist) ||
-           pg->queries_sent >= br->multicast_last_member_count)
-               goto out;
-
-       br_multicast_send_port_group_query(pg);
-
-out:
-       spin_unlock(&br->multicast_lock);
-}
-
 static struct net_bridge_mdb_entry *br_multicast_get_group(
        struct net_bridge *br, struct net_bridge_port *port,
        struct br_ip *group, int hash)
@@ -687,8 +624,6 @@ rehash:
        mp->addr = *group;
        setup_timer(&mp->timer, br_multicast_group_expired,
                    (unsigned long)mp);
-       setup_timer(&mp->query_timer, br_multicast_group_query_expired,
-                   (unsigned long)mp);
 
        hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
        mdb->size++;
@@ -743,8 +678,6 @@ static int br_multicast_add_group(struct net_bridge *br,
        hlist_add_head(&p->mglist, &port->mglist);
        setup_timer(&p->timer, br_multicast_port_group_expired,
                    (unsigned long)p);
-       setup_timer(&p->query_timer, br_multicast_port_group_query_expired,
-                   (unsigned long)p);
 
        rcu_assign_pointer(*pp, p);
 
@@ -912,6 +845,8 @@ void br_multicast_enable_port(struct net_bridge_port *port)
                goto out;
 
        __br_multicast_enable_port(port);
+       if (port->multicast_router == 2 && hlist_unhashed(&port->rlist))
+               br_multicast_add_router(br, port);
 
 out:
        spin_unlock(&br->multicast_lock);
@@ -1042,7 +977,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
                }
 
                err = br_ip6_multicast_add_group(br, port, &grec->grec_mca);
-               if (!err)
+               if (err)
                        break;
        }
 
@@ -1061,6 +996,9 @@ static void br_multicast_add_router(struct net_bridge *br,
        struct net_bridge_port *p;
        struct hlist_node *n, *slot = NULL;
 
+       if (!hlist_unhashed(&port->rlist))
+               return;
+
        hlist_for_each_entry(p, n, &br->router_list, rlist) {
                if ((unsigned long) port >= (unsigned long) p)
                        break;
@@ -1088,12 +1026,8 @@ static void br_multicast_mark_router(struct net_bridge *br,
        if (port->multicast_router != 1)
                return;
 
-       if (!hlist_unhashed(&port->rlist))
-               goto timer;
-
        br_multicast_add_router(br, port);
 
-timer:
        mod_timer(&port->multicast_router_timer,
                  now + br->multicast_querier_interval);
 }
@@ -1208,6 +1142,12 @@ static int br_ip6_multicast_query(struct net_bridge *br,
 
        br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
 
+       /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
+       if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1225,7 +1165,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                mld2q = (struct mld2_query *)icmp6_hdr(skb);
                if (!mld2q->mld2q_nsrcs)
                        group = &mld2q->mld2q_mca;
-               max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(mld2q->mld2q_mrc) : 1;
+
+               max_delay = max(msecs_to_jiffies(MLDV2_MRC(ntohs(mld2q->mld2q_mrc))), 1UL);
        }
 
        if (!group)
@@ -1288,9 +1229,6 @@ static void br_multicast_leave_group(struct net_bridge *br,
                     time_after(mp->timer.expires, time) :
                     try_to_del_timer_sync(&mp->timer) >= 0)) {
                        mod_timer(&mp->timer, time);
-
-                       mp->queries_sent = 0;
-                       mod_timer(&mp->query_timer, now);
                }
 
                goto out;
@@ -1307,9 +1245,6 @@ static void br_multicast_leave_group(struct net_bridge *br,
                     time_after(p->timer.expires, time) :
                     try_to_del_timer_sync(&p->timer) >= 0)) {
                        mod_timer(&p->timer, time);
-
-                       p->queries_sent = 0;
-                       mod_timer(&p->query_timer, now);
                }
 
                break;
@@ -1677,7 +1612,6 @@ void br_multicast_stop(struct net_bridge *br)
                hlist_for_each_entry_safe(mp, p, n, &mdb->mhash[i],
                                          hlist[ver]) {
                        del_timer(&mp->timer);
-                       del_timer(&mp->query_timer);
                        call_rcu_bh(&mp->rcu, br_multicast_free_group);
                }
        }
@@ -1819,7 +1753,7 @@ int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val)
        u32 old;
        struct net_bridge_mdb_htable *mdb;
 
-       spin_lock(&br->multicast_lock);
+       spin_lock_bh(&br->multicast_lock);
        if (!netif_running(br->dev))
                goto unlock;
 
@@ -1851,7 +1785,7 @@ rollback:
        }
 
 unlock:
-       spin_unlock(&br->multicast_lock);
+       spin_unlock_bh(&br->multicast_lock);
 
        return err;
 }