let's describe the situation: i've got a ethernet network and a wavelan network on my
linux 2.4.21-pre6/intel machine. The ethernet network is switched with a low-cost
switch while the wavelan interface on that machine is a prism2 card in hostap mode.
While creating the bridge, I first added the eth interface then the wlan one. Result:
the bridge used the wlan mac address for comunications on both network segments.
This is bad, because being the address declared on the ethernet port different, the switch
decided to discard all my packets with the new arp..and the ethernet network segment
was totally unreachable.
I dislike the quick&dirty solution of adjusting the insertion order in the switch, so
I patched the the bridge-utils-0.9.6 and a 2.4.21-pre6 vanilla kernel to put a new option
that selects which bridge interface should be the "source mac" address.
This doesn't anyway delete the previous behaviour (i've no time at the moment) to change
the hw address at each interface add..
The kernel patch should apply perfectly on a 2.4.20 kernel too..
The code is self explanatory, anyway, recompile your kernel and use
brctl setaddr <bridge> <interface>. I didn't test that thing in an extensive way,
but I think it could help.
Bye,
Alessio
p.s. i'm NOT subscribed to the list because i'm in a temporary situation with my ISP
connection, i will read my thread on the web. please write me in private if needed.
Only in bridge-utils-nail/: Makefile
Only in bridge-utils-nail/brctl: Makefile
diff -r -u bridge-utils/brctl/brctl.c bridge-utils-nail/brctl/brctl.c
--- bridge-utils/brctl/brctl.c 2001-12-07 15:25:58.000000000 +0100
+++ bridge-utils-nail/brctl/brctl.c 2003-03-29 16:12:03.000000000 +0100
@@ -33,6 +33,7 @@
"\tshow\t\t\t\t\tshow a list of bridges\n"
"\tshowmacs\t<bridge>\t\tshow a list of mac addrs\n"
"\tshowstp\t\t<bridge>\t\tshow bridge stp info\n"
+"\tsetaddr\t\t<bridge> <device>\tsets hardware device address for bridge\n"
"\n"
"\tsetageing\t<bridge> <time>\t\tset ageing time\n"
"\tsetbridgeprio\t<bridge> <prio>\t\tset bridge priority\n"
diff -r -u bridge-utils/brctl/brctl_cmd.c bridge-utils-nail/brctl/brctl_cmd.c
--- bridge-utils/brctl/brctl_cmd.c 2001-12-07 15:23:02.000000000 +0100
+++ bridge-utils-nail/brctl/brctl_cmd.c 2003-03-29 16:23:12.000000000 +0100
@@ -229,6 +229,22 @@
br_set_stp_state(br, stp);
}
+void br_cmd_setaddr(struct bridge *br, char *arg0, char *arg1)
+{
+ int ifindex = if_nametoindex(arg0);
+ int err;
+ if (!ifindex) {
+ fprintf(stderr, "interface %s does not exist!\n", arg0);
+ return;
+ }
+ err = br_set_hwaddr(br, ifindex);
+ if(err == EINVAL)
+ {
+ fprintf(stderr, "interface %s is not in the bridge!\n", arg0);
+ return;
+ }
+}
+
void br_cmd_showstp(struct bridge *br, char *arg0, char *arg1)
{
br_dump_info(br);
@@ -317,6 +333,7 @@
{1, 0, "showmacs", br_cmd_showmacs},
{1, 0, "showstp", br_cmd_showstp},
{1, 1, "stp", br_cmd_stp},
+ {1, 1, "setaddr", br_cmd_setaddr}
};
struct command *br_command_lookup(char *cmd)
diff -r -u bridge-utils/libbridge/libbridge.h bridge-utils-nail/libbridge/libbridge.h
--- bridge-utils/libbridge/libbridge.h 2001-06-22 21:59:03.000000000 +0200
+++ bridge-utils-nail/libbridge/libbridge.h 2003-03-29 16:15:26.000000000 +0100
@@ -123,6 +123,7 @@
int br_set_bridge_priority(struct bridge *br, int bridge_priority);
int br_set_port_priority(struct port *p, int port_priority);
int br_set_path_cost(struct port *p, int path_cost);
+int br_set_hwaddr(struct bridge *br, int ifindex);
int br_read_fdb(struct bridge *br, struct fdb_entry *fdbs, int offset, int num);
/* libc5 combatability */
diff -r -u bridge-utils/libbridge/libbridge_devif.c
bridge-utils-nail/libbridge/libbridge_devif.c
--- bridge-utils/libbridge/libbridge_devif.c 2002-01-16 13:04:45.000000000 +0100
+++ bridge-utils-nail/libbridge/libbridge_devif.c 2003-03-29 16:17:47.000000000
+0100
@@ -196,3 +196,10 @@
return numread;
}
+
+int br_set_hwaddr(struct bridge *br, int ifindex)
+{
+ if(br_device_ioctl(br, BRCTL_SET_HWADDR, (unsigned long)ifindex, 0, 0) < 0)
+ return errno;
+ return 0;
+}
diff -r -u linux-2.4.21-pre6-vanilla/include/linux/if_bridge.h
linux-2.4.21-pre6/include/linux/if_bridge.h
--- linux-2.4.21-pre6-vanilla/include/linux/if_bridge.h 2001-11-22 20:47:12.000000000
+0100
+++ linux-2.4.21-pre6/include/linux/if_bridge.h 2003-03-29 16:09:38.000000000 +0100
@@ -38,6 +38,7 @@
#define BRCTL_SET_PORT_PRIORITY 16
#define BRCTL_SET_PATH_COST 17
#define BRCTL_GET_FDB_ENTRIES 18
+#define BRCTL_SET_HWADDR 19
#define BR_STATE_DISABLED 0
#define BR_STATE_LISTENING 1
diff -r -u linux-2.4.21-pre6-vanilla/net/bridge/br_if.c
linux-2.4.21-pre6/net/bridge/br_if.c
--- linux-2.4.21-pre6-vanilla/net/bridge/br_if.c 2003-03-29 17:02:45.000000000
+0100
+++ linux-2.4.21-pre6/net/bridge/br_if.c 2003-03-29 16:48:27.000000000 +0100
@@ -293,3 +293,12 @@
p = p->next;
}
}
+
+int br_set_hwaddr(struct net_bridge *br, struct net_device *dev)
+{
+ write_lock_bh(&br->lock);
+ memcpy(br->dev.dev_addr,dev->dev_addr, ETH_ALEN);
+ printk(KERN_INFO "%s: user forced hardware address to %s\n", br->dev.name,
dev->name);
+ write_unlock_bh(&br->lock);
+ return 0;
+}
diff -r -u linux-2.4.21-pre6-vanilla/net/bridge/br_ioctl.c
linux-2.4.21-pre6/net/bridge/br_ioctl.c
--- linux-2.4.21-pre6-vanilla/net/bridge/br_ioctl.c 2003-03-29 17:01:47.000000000
+0100
+++ linux-2.4.21-pre6/net/bridge/br_ioctl.c 2003-03-29 16:39:11.000000000 +0100
@@ -30,6 +30,27 @@
switch (cmd)
{
+ case BRCTL_SET_HWADDR:
+ {
+ struct net_device *dev;
+ int ret;
+
+ dev = dev_get_by_index(arg0);
+ if(dev == NULL)
+ return -EINVAL;
+ dev_hold(dev);
+ if(dev->br_port == NULL || dev->br_port->br != br) {
+ printk(KERN_ERR "device is not in selected bridge\n");
+ dev_put(dev);
+ return -EINVAL;
+ }
+ ret = br_set_hwaddr(br,dev);
+ dev_put(dev);
+ return ret;
+ }
+
+
+
case BRCTL_ADD_IF:
case BRCTL_DEL_IF:
{
diff -r -u linux-2.4.21-pre6-vanilla/net/bridge/br_private.h
linux-2.4.21-pre6/net/bridge/br_private.h
--- linux-2.4.21-pre6-vanilla/net/bridge/br_private.h 2002-02-25 20:38:14.000000000
+0100
+++ linux-2.4.21-pre6/net/bridge/br_private.h 2003-03-29 16:09:48.000000000 +0100
@@ -164,6 +164,7 @@
int num);
extern void br_get_port_ifindices(struct net_bridge *br,
int *ifindices);
+extern int br_set_hwaddr(struct net_bridge *br, struct net_device *dev);
/* br_input.c */
extern void br_handle_frame(struct sk_buff *skb);
