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 | ||
