aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/br_input.c7
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/bridge/br_stp_bpdu.c4
-rw-r--r--net/bridge/br_sysfs_br.c49
4 files changed, 57 insertions, 6 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index dad409489753..a9feb2015425 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -19,7 +19,8 @@
19#include <linux/netfilter_bridge.h> 19#include <linux/netfilter_bridge.h>
20#include "br_private.h" 20#include "br_private.h"
21 21
22const unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; 22/* Bridge group multicast address 802.1d (pg 51). */
23const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
23 24
24static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) 25static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
25{ 26{
@@ -108,9 +109,9 @@ static int br_handle_local_finish(struct sk_buff *skb)
108/* Does address match the link local multicast address. 109/* Does address match the link local multicast address.
109 * 01:80:c2:00:00:0X 110 * 01:80:c2:00:00:0X
110 */ 111 */
111static inline int is_link_local(const unsigned char *dest) 112static inline int is_link_local(const const unsigned char *dest)
112{ 113{
113 return memcmp(dest, bridge_ula, 5) == 0 && (dest[5] & 0xf0) == 0; 114 return memcmp(dest, br_group_address, 5) == 0 && (dest[5] & 0xf0) == 0;
114} 115}
115 116
116/* 117/*
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 3bc9ad483473..86ecea7ed372 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -109,6 +109,7 @@ struct net_bridge
109 unsigned long bridge_hello_time; 109 unsigned long bridge_hello_time;
110 unsigned long bridge_forward_delay; 110 unsigned long bridge_forward_delay;
111 111
112 u8 group_addr[ETH_ALEN];
112 u16 root_port; 113 u16 root_port;
113 unsigned char stp_enabled; 114 unsigned char stp_enabled;
114 unsigned char topology_change; 115 unsigned char topology_change;
@@ -122,7 +123,7 @@ struct net_bridge
122}; 123};
123 124
124extern struct notifier_block br_device_notifier; 125extern struct notifier_block br_device_notifier;
125extern const unsigned char bridge_ula[6]; 126extern const u8 br_group_address[ETH_ALEN];
126 127
127/* called under bridge lock */ 128/* called under bridge lock */
128static inline int br_is_root_bridge(const struct net_bridge *br) 129static inline int br_is_root_bridge(const struct net_bridge *br)
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index a99e90e20952..ed3a5441a47e 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -47,7 +47,7 @@ static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int len
47 skb->dev = dev; 47 skb->dev = dev;
48 skb->protocol = htons(ETH_P_802_2); 48 skb->protocol = htons(ETH_P_802_2);
49 skb->mac.raw = skb_put(skb, size); 49 skb->mac.raw = skb_put(skb, size);
50 memcpy(skb->mac.raw, bridge_ula, ETH_ALEN); 50 memcpy(skb->mac.raw, p->br->group_addr, ETH_ALEN);
51 memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN); 51 memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN);
52 skb->mac.raw[2*ETH_ALEN] = 0; 52 skb->mac.raw[2*ETH_ALEN] = 0;
53 skb->mac.raw[2*ETH_ALEN+1] = length; 53 skb->mac.raw[2*ETH_ALEN+1] = length;
@@ -171,7 +171,7 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
171 || !(br->dev->flags & IFF_UP)) 171 || !(br->dev->flags & IFF_UP))
172 goto out; 172 goto out;
173 173
174 if (compare_ether_addr(dest, bridge_ula) != 0) 174 if (compare_ether_addr(dest, br->group_addr) != 0)
175 goto out; 175 goto out;
176 176
177 buf = skb_pull(skb, 3); 177 buf = skb_pull(skb, 3);
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 6f577f16c4c0..96bcb2ff59ab 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -242,6 +242,54 @@ static ssize_t show_gc_timer(struct class_device *cd, char *buf)
242} 242}
243static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); 243static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
244 244
245static ssize_t show_group_addr(struct class_device *cd, char *buf)
246{
247 struct net_bridge *br = to_bridge(cd);
248 return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
249 br->group_addr[0], br->group_addr[1],
250 br->group_addr[2], br->group_addr[3],
251 br->group_addr[4], br->group_addr[5]);
252}
253
254static ssize_t store_group_addr(struct class_device *cd, const char *buf,
255 size_t len)
256{
257 struct net_bridge *br = to_bridge(cd);
258 unsigned new_addr[6];
259 int i;
260
261 if (!capable(CAP_NET_ADMIN))
262 return -EPERM;
263
264 if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
265 &new_addr[0], &new_addr[1], &new_addr[2],
266 &new_addr[3], &new_addr[4], &new_addr[5]) != 6)
267 return -EINVAL;
268
269 /* Must be 01:80:c2:00:00:0X */
270 for (i = 0; i < 5; i++)
271 if (new_addr[i] != br_group_address[i])
272 return -EINVAL;
273
274 if (new_addr[5] & ~0xf)
275 return -EINVAL;
276
277 if (new_addr[5] == 1 /* 802.3x Pause address */
278 || new_addr[5] == 2 /* 802.3ad Slow protocols */
279 || new_addr[5] == 3) /* 802.1X PAE address */
280 return -EINVAL;
281
282 spin_lock_bh(&br->lock);
283 for (i = 0; i < 6; i++)
284 br->group_addr[i] = new_addr[i];
285 spin_unlock_bh(&br->lock);
286 return len;
287}
288
289static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
290 show_group_addr, store_group_addr);
291
292
245static struct attribute *bridge_attrs[] = { 293static struct attribute *bridge_attrs[] = {
246 &class_device_attr_forward_delay.attr, 294 &class_device_attr_forward_delay.attr,
247 &class_device_attr_hello_time.attr, 295 &class_device_attr_hello_time.attr,
@@ -259,6 +307,7 @@ static struct attribute *bridge_attrs[] = {
259 &class_device_attr_tcn_timer.attr, 307 &class_device_attr_tcn_timer.attr,
260 &class_device_attr_topology_change_timer.attr, 308 &class_device_attr_topology_change_timer.attr,
261 &class_device_attr_gc_timer.attr, 309 &class_device_attr_gc_timer.attr,
310 &class_device_attr_group_addr.attr,
262 NULL 311 NULL
263}; 312};
264 313