Merge tag 'nfsd-4.6-1' of git://linux-nfs.org/~bfields/linux
[deliverable/linux.git] / net / bridge / br_multicast.c
index 03661d97463c0a185b6c688ee281309682209528..a4c15df2b7920301f7d12918dc21a1d6f2474352 100644 (file)
@@ -283,8 +283,7 @@ 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);
-               br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB,
-                             p->state);
+               br_mdb_notify(br->dev, p, RTM_DELMDB);
                call_rcu_bh(&p->rcu, br_multicast_free_pg);
 
                if (!mp->ports && !mp->mglist &&
@@ -304,7 +303,7 @@ static void br_multicast_port_group_expired(unsigned long data)
 
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) || timer_pending(&pg->timer) ||
-           hlist_unhashed(&pg->mglist) || pg->state & MDB_PERMANENT)
+           hlist_unhashed(&pg->mglist) || pg->flags & MDB_PG_FLAGS_PERMANENT)
                goto out;
 
        br_multicast_del_pg(br, pg);
@@ -649,7 +648,7 @@ struct net_bridge_port_group *br_multicast_new_port_group(
                        struct net_bridge_port *port,
                        struct br_ip *group,
                        struct net_bridge_port_group __rcu *next,
-                       unsigned char state)
+                       unsigned char flags)
 {
        struct net_bridge_port_group *p;
 
@@ -659,7 +658,7 @@ struct net_bridge_port_group *br_multicast_new_port_group(
 
        p->addr = *group;
        p->port = port;
-       p->state = state;
+       p->flags = flags;
        rcu_assign_pointer(p->next, next);
        hlist_add_head(&p->mglist, &port->mglist);
        setup_timer(&p->timer, br_multicast_port_group_expired,
@@ -702,11 +701,11 @@ static int br_multicast_add_group(struct net_bridge *br,
                        break;
        }
 
-       p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
+       p = br_multicast_new_port_group(port, group, *pp, 0);
        if (unlikely(!p))
                goto err;
        rcu_assign_pointer(*pp, p);
-       br_mdb_notify(br->dev, port, group, RTM_NEWMDB, MDB_TEMPORARY);
+       br_mdb_notify(br->dev, p, RTM_NEWMDB);
 
 found:
        mod_timer(&p->timer, now + br->multicast_membership_interval);
@@ -760,13 +759,17 @@ static void br_multicast_router_expired(unsigned long data)
        struct net_bridge *br = port->br;
 
        spin_lock(&br->multicast_lock);
-       if (port->multicast_router != 1 ||
+       if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+           port->multicast_router == MDB_RTR_TYPE_PERM ||
            timer_pending(&port->multicast_router_timer) ||
            hlist_unhashed(&port->rlist))
                goto out;
 
        hlist_del_init_rcu(&port->rlist);
        br_rtr_notify(br->dev, port, RTM_DELMDB);
+       /* Don't allow timer refresh if the router expired */
+       if (port->multicast_router == MDB_RTR_TYPE_TEMP)
+               port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
 
 out:
        spin_unlock(&br->multicast_lock);
@@ -913,7 +916,7 @@ static void br_ip6_multicast_port_query_expired(unsigned long data)
 
 void br_multicast_add_port(struct net_bridge_port *port)
 {
-       port->multicast_router = 1;
+       port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
 
        setup_timer(&port->multicast_router_timer, br_multicast_router_expired,
                    (unsigned long)port);
@@ -960,7 +963,8 @@ void br_multicast_enable_port(struct net_bridge_port *port)
 #if IS_ENABLED(CONFIG_IPV6)
        br_multicast_enable(&port->ip6_own_query);
 #endif
-       if (port->multicast_router == 2 && hlist_unhashed(&port->rlist))
+       if (port->multicast_router == MDB_RTR_TYPE_PERM &&
+           hlist_unhashed(&port->rlist))
                br_multicast_add_router(br, port);
 
 out:
@@ -975,12 +979,15 @@ void br_multicast_disable_port(struct net_bridge_port *port)
 
        spin_lock(&br->multicast_lock);
        hlist_for_each_entry_safe(pg, n, &port->mglist, mglist)
-               if (pg->state == MDB_TEMPORARY)
+               if (!(pg->flags & MDB_PG_FLAGS_PERMANENT))
                        br_multicast_del_pg(br, pg);
 
        if (!hlist_unhashed(&port->rlist)) {
                hlist_del_init_rcu(&port->rlist);
                br_rtr_notify(br->dev, port, RTM_DELMDB);
+               /* Don't allow timer refresh if disabling */
+               if (port->multicast_router == MDB_RTR_TYPE_TEMP)
+                       port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
        }
        del_timer(&port->multicast_router_timer);
        del_timer(&port->ip4_own_query.timer);
@@ -1228,13 +1235,14 @@ static void br_multicast_mark_router(struct net_bridge *br,
        unsigned long now = jiffies;
 
        if (!port) {
-               if (br->multicast_router == 1)
+               if (br->multicast_router == MDB_RTR_TYPE_TEMP_QUERY)
                        mod_timer(&br->multicast_router_timer,
                                  now + br->multicast_querier_interval);
                return;
        }
 
-       if (port->multicast_router != 1)
+       if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+           port->multicast_router == MDB_RTR_TYPE_PERM)
                return;
 
        br_multicast_add_router(br, port);
@@ -1453,8 +1461,7 @@ br_multicast_leave_group(struct net_bridge *br,
                        hlist_del_init(&p->mglist);
                        del_timer(&p->timer);
                        call_rcu_bh(&p->rcu, br_multicast_free_pg);
-                       br_mdb_notify(br->dev, port, group, RTM_DELMDB,
-                                     p->state);
+                       br_mdb_notify(br->dev, p, RTM_DELMDB);
 
                        if (!mp->ports && !mp->mglist &&
                            netif_running(br->dev))
@@ -1715,7 +1722,7 @@ void br_multicast_init(struct net_bridge *br)
        br->hash_elasticity = 4;
        br->hash_max = 512;
 
-       br->multicast_router = 1;
+       br->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
        br->multicast_querier = 0;
        br->multicast_query_use_ifaddr = 0;
        br->multicast_last_member_count = 2;
@@ -1825,11 +1832,11 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
        spin_lock_bh(&br->multicast_lock);
 
        switch (val) {
-       case 0:
-       case 2:
+       case MDB_RTR_TYPE_DISABLED:
+       case MDB_RTR_TYPE_PERM:
                del_timer(&br->multicast_router_timer);
                /* fall through */
-       case 1:
+       case MDB_RTR_TYPE_TEMP_QUERY:
                br->multicast_router = val;
                err = 0;
                break;
@@ -1840,37 +1847,53 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
        return err;
 }
 
+static void __del_port_router(struct net_bridge_port *p)
+{
+       if (hlist_unhashed(&p->rlist))
+               return;
+       hlist_del_init_rcu(&p->rlist);
+       br_rtr_notify(p->br->dev, p, RTM_DELMDB);
+}
+
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
 {
        struct net_bridge *br = p->br;
+       unsigned long now = jiffies;
        int err = -EINVAL;
 
        spin_lock(&br->multicast_lock);
-
-       switch (val) {
-       case 0:
-       case 1:
-       case 2:
-               p->multicast_router = val;
+       if (p->multicast_router == val) {
+               /* Refresh the temp router port timer */
+               if (p->multicast_router == MDB_RTR_TYPE_TEMP)
+                       mod_timer(&p->multicast_router_timer,
+                                 now + br->multicast_querier_interval);
                err = 0;
-
-               if (val < 2 && !hlist_unhashed(&p->rlist)) {
-                       hlist_del_init_rcu(&p->rlist);
-                       br_rtr_notify(br->dev, p, RTM_DELMDB);
-               }
-
-               if (val == 1)
-                       break;
-
+               goto unlock;
+       }
+       switch (val) {
+       case MDB_RTR_TYPE_DISABLED:
+               p->multicast_router = MDB_RTR_TYPE_DISABLED;
+               __del_port_router(p);
+               del_timer(&p->multicast_router_timer);
+               break;
+       case MDB_RTR_TYPE_TEMP_QUERY:
+               p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
+               __del_port_router(p);
+               break;
+       case MDB_RTR_TYPE_PERM:
+               p->multicast_router = MDB_RTR_TYPE_PERM;
                del_timer(&p->multicast_router_timer);
-
-               if (val == 0)
-                       break;
-
                br_multicast_add_router(br, p);
                break;
+       case MDB_RTR_TYPE_TEMP:
+               p->multicast_router = MDB_RTR_TYPE_TEMP;
+               br_multicast_mark_router(br, p);
+               break;
+       default:
+               goto unlock;
        }
-
+       err = 0;
+unlock:
        spin_unlock(&br->multicast_lock);
 
        return err;
This page took 0.027729 seconds and 5 git commands to generate.