diff options
-rw-r--r-- | net/bridge/br_input.c | 7 | ||||
-rw-r--r-- | net/bridge/br_private.h | 3 | ||||
-rw-r--r-- | net/bridge/br_stp_bpdu.c | 4 | ||||
-rw-r--r-- | net/bridge/br_sysfs_br.c | 49 |
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 | ||
22 | const unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | 22 | /* Bridge group multicast address 802.1d (pg 51). */ |
23 | const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | ||
23 | 24 | ||
24 | static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) | 25 | static 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 | */ |
111 | static inline int is_link_local(const unsigned char *dest) | 112 | static 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 | ||
124 | extern struct notifier_block br_device_notifier; | 125 | extern struct notifier_block br_device_notifier; |
125 | extern const unsigned char bridge_ula[6]; | 126 | extern const u8 br_group_address[ETH_ALEN]; |
126 | 127 | ||
127 | /* called under bridge lock */ | 128 | /* called under bridge lock */ |
128 | static inline int br_is_root_bridge(const struct net_bridge *br) | 129 | static 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 | } |
243 | static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); | 243 | static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); |
244 | 244 | ||
245 | static 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 | |||
254 | static 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 | |||
289 | static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, | ||
290 | show_group_addr, store_group_addr); | ||
291 | |||
292 | |||
245 | static struct attribute *bridge_attrs[] = { | 293 | static 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 | ||