[BRIDGE]: allow setting hardware address of bridge pseudo-dev
authorStephen Hemminger <shemminger@osdl.org>
Thu, 22 Dec 2005 02:51:49 +0000 (18:51 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Tue, 3 Jan 2006 21:11:00 +0000 (13:11 -0800)
Some people are using bridging to hide multiple machines from an ISP
that restricts by MAC address. So in that case allow the bridge mac
address to be set to any of the existing interfaces.  I don't want to
allow any arbitrary value and confuse STP.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_device.c
net/bridge/br_private.h
net/bridge/br_stp_if.c

index f564ee99782d248dab471e124f3d02dadeb5512a..f7a66abf5def7c5c9c4596da2df2b719597cd422 100644 (file)
@@ -15,7 +15,8 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
-#include <linux/module.h>
+#include <linux/etherdevice.h>
+
 #include <asm/uaccess.h>
 #include "br_private.h"
 
@@ -82,6 +83,29 @@ static int br_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
+/* Allow setting mac address of pseudo-bridge to be same as
+ * any of the bound interfaces
+ */
+static int br_set_mac_address(struct net_device *dev, void *p)
+{
+       struct net_bridge *br = netdev_priv(dev);
+       struct sockaddr *addr = p;
+       struct net_bridge_port *port;
+       int err = -EADDRNOTAVAIL;
+
+       spin_lock_bh(&br->lock);
+       list_for_each_entry(port, &br->port_list, list) {
+               if (!compare_ether_addr(port->dev->dev_addr, addr->sa_data)) {
+                       br_stp_change_bridge_id(br, addr->sa_data);
+                       err = 0;
+                       break;
+               }
+       }
+       spin_unlock_bh(&br->lock);
+
+       return err;
+}
+
 void br_dev_setup(struct net_device *dev)
 {
        memset(dev->dev_addr, 0, ETH_ALEN);
@@ -98,6 +122,6 @@ void br_dev_setup(struct net_device *dev)
        SET_MODULE_OWNER(dev);
        dev->stop = br_dev_stop;
        dev->tx_queue_len = 0;
-       dev->set_mac_address = NULL;
+       dev->set_mac_address = br_set_mac_address;
        dev->priv_flags = IFF_EBRIDGE;
 }
index bdf95a74d8cd3294ec5765dabf94de1edd20de93..2c249486476f8a4253277457b8cf27be201d6875 100644 (file)
@@ -201,6 +201,7 @@ extern void br_stp_disable_bridge(struct net_bridge *br);
 extern void br_stp_enable_port(struct net_bridge_port *p);
 extern void br_stp_disable_port(struct net_bridge_port *p);
 extern void br_stp_recalculate_bridge_id(struct net_bridge *br);
+extern void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *a);
 extern void br_stp_set_bridge_priority(struct net_bridge *br,
                                       u16 newprio);
 extern void br_stp_set_port_priority(struct net_bridge_port *p,
index ac09b6a2352317cde8ee4a43a2db1a01a3caab71..2d2e969ae25de49f1f59d7e7dc5cafdd6a2318ea 100644 (file)
@@ -120,8 +120,7 @@ void br_stp_disable_port(struct net_bridge_port *p)
 }
 
 /* called under bridge lock */
-static void br_stp_change_bridge_id(struct net_bridge *br, 
-                                   const unsigned char *addr)
+void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
 {
        unsigned char oldaddr[6];
        struct net_bridge_port *p;