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 @@ #include #include "br_private.h" -const unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; +/* Bridge group multicast address 802.1d (pg 51). */ +const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) { @@ -108,9 +109,9 @@ static int br_handle_local_finish(struct sk_buff *skb) /* Does address match the link local multicast address. * 01:80:c2:00:00:0X */ -static inline int is_link_local(const unsigned char *dest) +static inline int is_link_local(const const unsigned char *dest) { - return memcmp(dest, bridge_ula, 5) == 0 && (dest[5] & 0xf0) == 0; + return memcmp(dest, br_group_address, 5) == 0 && (dest[5] & 0xf0) == 0; } /* 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 unsigned long bridge_hello_time; unsigned long bridge_forward_delay; + u8 group_addr[ETH_ALEN]; u16 root_port; unsigned char stp_enabled; unsigned char topology_change; @@ -122,7 +123,7 @@ struct net_bridge }; extern struct notifier_block br_device_notifier; -extern const unsigned char bridge_ula[6]; +extern const u8 br_group_address[ETH_ALEN]; /* called under bridge lock */ 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 skb->dev = dev; skb->protocol = htons(ETH_P_802_2); skb->mac.raw = skb_put(skb, size); - memcpy(skb->mac.raw, bridge_ula, ETH_ALEN); + memcpy(skb->mac.raw, p->br->group_addr, ETH_ALEN); memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN); skb->mac.raw[2*ETH_ALEN] = 0; skb->mac.raw[2*ETH_ALEN+1] = length; @@ -171,7 +171,7 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, || !(br->dev->flags & IFF_UP)) goto out; - if (compare_ether_addr(dest, bridge_ula) != 0) + if (compare_ether_addr(dest, br->group_addr) != 0) goto out; 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) } static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); +static ssize_t show_group_addr(struct class_device *cd, char *buf) +{ + struct net_bridge *br = to_bridge(cd); + return sprintf(buf, "%x:%x:%x:%x:%x:%x\n", + br->group_addr[0], br->group_addr[1], + br->group_addr[2], br->group_addr[3], + br->group_addr[4], br->group_addr[5]); +} + +static ssize_t store_group_addr(struct class_device *cd, const char *buf, + size_t len) +{ + struct net_bridge *br = to_bridge(cd); + unsigned new_addr[6]; + int i; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (sscanf(buf, "%x:%x:%x:%x:%x:%x", + &new_addr[0], &new_addr[1], &new_addr[2], + &new_addr[3], &new_addr[4], &new_addr[5]) != 6) + return -EINVAL; + + /* Must be 01:80:c2:00:00:0X */ + for (i = 0; i < 5; i++) + if (new_addr[i] != br_group_address[i]) + return -EINVAL; + + if (new_addr[5] & ~0xf) + return -EINVAL; + + if (new_addr[5] == 1 /* 802.3x Pause address */ + || new_addr[5] == 2 /* 802.3ad Slow protocols */ + || new_addr[5] == 3) /* 802.1X PAE address */ + return -EINVAL; + + spin_lock_bh(&br->lock); + for (i = 0; i < 6; i++) + br->group_addr[i] = new_addr[i]; + spin_unlock_bh(&br->lock); + return len; +} + +static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, + show_group_addr, store_group_addr); + + static struct attribute *bridge_attrs[] = { &class_device_attr_forward_delay.attr, &class_device_attr_hello_time.attr, @@ -259,6 +307,7 @@ static struct attribute *bridge_attrs[] = { &class_device_attr_tcn_timer.attr, &class_device_attr_topology_change_timer.attr, &class_device_attr_gc_timer.attr, + &class_device_attr_group_addr.attr, NULL };