aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-03-21 01:59:21 -0500
committerDavid S. Miller <davem@davemloft.net>2006-03-21 01:59:21 -0500
commitfda93d92d7824159d8532995072dde2bee4bc4b3 (patch)
treeba28fcd6637d848bbee4a6e22f642a69cbe1c71f /net/bridge
parentcf0f02d04a830c8202e6a8f8bb37acc6c1629a91 (diff)
[BRIDGE]: allow show/store of group multicast address
Bridge's communicate with each other using Spanning Tree Protocol over a standard multicast address. There are times when testing or layering bridges over existing topologies or tunnels, when it is useful to use alternative multicast addresses for STP packets. The 802.1d standard has some unused addresses, that can be used for this. This patch is restrictive in that it only allows one of the possible addresses in the standard. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
-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