aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_multicast.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/br_multicast.c')
-rw-r--r--net/bridge/br_multicast.c105
1 files changed, 91 insertions, 14 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 746b5a611aae..674224b6729d 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -746,12 +746,30 @@ static int br_multicast_igmp3_report(struct net_bridge *br,
746 return err; 746 return err;
747} 747}
748 748
749static void br_multicast_add_router(struct net_bridge *br,
750 struct net_bridge_port *port)
751{
752 struct hlist_node *p;
753 struct hlist_node **h;
754
755 for (h = &br->router_list.first;
756 (p = *h) &&
757 (unsigned long)container_of(p, struct net_bridge_port, rlist) >
758 (unsigned long)port;
759 h = &p->next)
760 ;
761
762 port->rlist.pprev = h;
763 port->rlist.next = p;
764 rcu_assign_pointer(*h, &port->rlist);
765 if (p)
766 p->pprev = &port->rlist.next;
767}
768
749static void br_multicast_mark_router(struct net_bridge *br, 769static void br_multicast_mark_router(struct net_bridge *br,
750 struct net_bridge_port *port) 770 struct net_bridge_port *port)
751{ 771{
752 unsigned long now = jiffies; 772 unsigned long now = jiffies;
753 struct hlist_node *p;
754 struct hlist_node **h;
755 773
756 if (!port) { 774 if (!port) {
757 if (br->multicast_router == 1) 775 if (br->multicast_router == 1)
@@ -766,18 +784,7 @@ static void br_multicast_mark_router(struct net_bridge *br,
766 if (!hlist_unhashed(&port->rlist)) 784 if (!hlist_unhashed(&port->rlist))
767 goto timer; 785 goto timer;
768 786
769 for (h = &br->router_list.first; 787 br_multicast_add_router(br, port);
770 (p = *h) &&
771 (unsigned long)container_of(p, struct net_bridge_port, rlist) >
772 (unsigned long)port;
773 h = &p->next)
774 ;
775
776 port->rlist.pprev = h;
777 port->rlist.next = p;
778 rcu_assign_pointer(*h, &port->rlist);
779 if (p)
780 p->pprev = &port->rlist.next;
781 788
782timer: 789timer:
783 mod_timer(&port->multicast_router_timer, 790 mod_timer(&port->multicast_router_timer,
@@ -1133,3 +1140,73 @@ void br_multicast_stop(struct net_bridge *br)
1133out: 1140out:
1134 spin_unlock_bh(&br->multicast_lock); 1141 spin_unlock_bh(&br->multicast_lock);
1135} 1142}
1143
1144int br_multicast_set_router(struct net_bridge *br, unsigned long val)
1145{
1146 int err = -ENOENT;
1147
1148 spin_lock_bh(&br->multicast_lock);
1149 if (!netif_running(br->dev))
1150 goto unlock;
1151
1152 switch (val) {
1153 case 0:
1154 case 2:
1155 del_timer(&br->multicast_router_timer);
1156 /* fall through */
1157 case 1:
1158 br->multicast_router = val;
1159 err = 0;
1160 break;
1161
1162 default:
1163 err = -EINVAL;
1164 break;
1165 }
1166
1167unlock:
1168 spin_unlock_bh(&br->multicast_lock);
1169
1170 return err;
1171}
1172
1173int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
1174{
1175 struct net_bridge *br = p->br;
1176 int err = -ENOENT;
1177
1178 spin_lock(&br->multicast_lock);
1179 if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED)
1180 goto unlock;
1181
1182 switch (val) {
1183 case 0:
1184 case 1:
1185 case 2:
1186 p->multicast_router = val;
1187 err = 0;
1188
1189 if (val < 2 && !hlist_unhashed(&p->rlist))
1190 hlist_del_init_rcu(&p->rlist);
1191
1192 if (val == 1)
1193 break;
1194
1195 del_timer(&p->multicast_router_timer);
1196
1197 if (val == 0)
1198 break;
1199
1200 br_multicast_add_router(br, p);
1201 break;
1202
1203 default:
1204 err = -EINVAL;
1205 break;
1206 }
1207
1208unlock:
1209 spin_unlock(&br->multicast_lock);
1210
1211 return err;
1212}