aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_multicast.c105
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/bridge/br_sysfs_br.c21
-rw-r--r--net/bridge/br_sysfs_if.c18
4 files changed, 133 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}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c85943c2b23f..dcdfafbe4b17 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -297,6 +297,9 @@ extern void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
297 struct sk_buff *skb); 297 struct sk_buff *skb);
298extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst, 298extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
299 struct sk_buff *skb, struct sk_buff *skb2); 299 struct sk_buff *skb, struct sk_buff *skb2);
300extern int br_multicast_set_router(struct net_bridge *br, unsigned long val);
301extern int br_multicast_set_port_router(struct net_bridge_port *p,
302 unsigned long val);
300#else 303#else
301static inline int br_multicast_rcv(struct net_bridge *br, 304static inline int br_multicast_rcv(struct net_bridge *br,
302 struct net_bridge_port *port, 305 struct net_bridge_port *port,
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index bee4f300d0c8..cb742016db21 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -345,6 +345,24 @@ static ssize_t store_flush(struct device *d,
345} 345}
346static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush); 346static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
347 347
348#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
349static ssize_t show_multicast_router(struct device *d,
350 struct device_attribute *attr, char *buf)
351{
352 struct net_bridge *br = to_bridge(d);
353 return sprintf(buf, "%d\n", br->multicast_router);
354}
355
356static ssize_t store_multicast_router(struct device *d,
357 struct device_attribute *attr,
358 const char *buf, size_t len)
359{
360 return store_bridge_parm(d, buf, len, br_multicast_set_router);
361}
362static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
363 store_multicast_router);
364#endif
365
348static struct attribute *bridge_attrs[] = { 366static struct attribute *bridge_attrs[] = {
349 &dev_attr_forward_delay.attr, 367 &dev_attr_forward_delay.attr,
350 &dev_attr_hello_time.attr, 368 &dev_attr_hello_time.attr,
@@ -364,6 +382,9 @@ static struct attribute *bridge_attrs[] = {
364 &dev_attr_gc_timer.attr, 382 &dev_attr_gc_timer.attr,
365 &dev_attr_group_addr.attr, 383 &dev_attr_group_addr.attr,
366 &dev_attr_flush.attr, 384 &dev_attr_flush.attr,
385#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
386 &dev_attr_multicast_router.attr,
387#endif
367 NULL 388 NULL
368}; 389};
369 390
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 820643a3ba9c..696596cd3384 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -159,6 +159,21 @@ static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
159static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR, 159static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
160 show_hairpin_mode, store_hairpin_mode); 160 show_hairpin_mode, store_hairpin_mode);
161 161
162#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
163static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
164{
165 return sprintf(buf, "%d\n", p->multicast_router);
166}
167
168static ssize_t store_multicast_router(struct net_bridge_port *p,
169 unsigned long v)
170{
171 return br_multicast_set_port_router(p, v);
172}
173static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
174 store_multicast_router);
175#endif
176
162static struct brport_attribute *brport_attrs[] = { 177static struct brport_attribute *brport_attrs[] = {
163 &brport_attr_path_cost, 178 &brport_attr_path_cost,
164 &brport_attr_priority, 179 &brport_attr_priority,
@@ -176,6 +191,9 @@ static struct brport_attribute *brport_attrs[] = {
176 &brport_attr_hold_timer, 191 &brport_attr_hold_timer,
177 &brport_attr_flush, 192 &brport_attr_flush,
178 &brport_attr_hairpin_mode, 193 &brport_attr_hairpin_mode,
194#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
195 &brport_attr_multicast_router,
196#endif
179 NULL 197 NULL
180}; 198};
181 199