diff -urN ./linux-2.6.6-old/include/linux/if_bridge.h ./linux-2.6.6/include/linux/if_bridge.h --- ./linux-2.6.6-old/include/linux/if_bridge.h 2004-05-10 04:32:37.000000000 +0200 +++ ./linux-2.6.6/include/linux/if_bridge.h 2004-06-15 22:55:46.000000000 +0200 @@ -44,6 +44,7 @@ #define BR_STATE_LEARNING 2 #define BR_STATE_FORWARDING 3 #define BR_STATE_BLOCKING 4 +#define BR_STATE_NOLINK 5 struct __bridge_info { diff -urN ./linux-2.6.6-old/net/bridge/br_fdb.c ./linux-2.6.6/net/bridge/br_fdb.c --- ./linux-2.6.6-old/net/bridge/br_fdb.c 2004-05-10 04:32:00.000000000 +0200 +++ ./linux-2.6.6/net/bridge/br_fdb.c 2004-06-15 22:17:16.000000000 +0200 @@ -281,12 +281,13 @@ printk(KERN_INFO "%s: attempt to add" " interface with same source address.\n", source->dev->name); - else if (net_ratelimit()) + else if (net_ratelimit()) { printk(KERN_WARNING "%s: received packet with " " own address as source address\n", source->dev->name); - ret = -EEXIST; - goto out; + ret = -EEXIST; + goto out; + } } diff -urN ./linux-2.6.6-old/net/bridge/br_if.c ./linux-2.6.6/net/bridge/br_if.c --- ./linux-2.6.6-old/net/bridge/br_if.c 2004-05-10 04:33:21.000000000 +0200 +++ ./linux-2.6.6/net/bridge/br_if.c 2004-06-15 23:12:30.000000000 +0200 @@ -189,6 +189,7 @@ /* called under bridge lock */ static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device *dev, + struct net_device *rdev, unsigned long cost) { int index; @@ -206,6 +207,7 @@ p->br = br; dev_hold(dev); p->dev = dev; + p->rdev = rdev; p->path_cost = cost; p->priority = 0x8000 >> BR_PORT_BITS; dev->br_port = p; @@ -257,7 +259,7 @@ return ret; } -int br_add_if(struct net_bridge *br, struct net_device *dev) +int br_add_if(struct net_bridge *br, struct net_device *dev , struct net_device *rdev) { struct net_bridge_port *p; unsigned long cost; @@ -275,7 +277,7 @@ if (dev->br_port != NULL) err = -EBUSY; - else if (IS_ERR(p = new_nbp(br, dev, cost))) + else if (IS_ERR(p = new_nbp(br, dev, rdev, cost))) err = PTR_ERR(p); else if ((err = br_fdb_insert(br, p, dev->dev_addr, 1))) diff -urN ./linux-2.6.6-old/net/bridge/br_ioctl.c ./linux-2.6.6/net/bridge/br_ioctl.c --- ./linux-2.6.6-old/net/bridge/br_ioctl.c 2004-05-10 04:32:01.000000000 +0200 +++ ./linux-2.6.6/net/bridge/br_ioctl.c 2004-06-15 22:36:32.000000000 +0200 @@ -39,17 +39,19 @@ case BRCTL_DEL_IF: { struct net_device *dev; + struct net_device *rdev; int ret; if (!capable(CAP_NET_ADMIN)) return -EPERM; dev = dev_get_by_index(arg0); + rdev = dev_get_by_index(arg1); if (dev == NULL) return -EINVAL; if (cmd == BRCTL_ADD_IF) - ret = br_add_if(br, dev); + ret = br_add_if(br, dev, rdev); else ret = br_del_if(br, dev); diff -urN ./linux-2.6.6-old/net/bridge/br_private.h ./linux-2.6.6/net/bridge/br_private.h --- ./linux-2.6.6-old/net/bridge/br_private.h 2004-05-10 04:32:26.000000000 +0200 +++ ./linux-2.6.6/net/bridge/br_private.h 2004-06-15 22:47:18.000000000 +0200 @@ -58,6 +58,7 @@ { struct net_bridge *br; struct net_device *dev; + struct net_device *rdev; struct list_head list; /* STP */ @@ -84,6 +85,7 @@ spinlock_t lock; struct list_head port_list; struct net_device *dev; + struct net_device *rdev; struct net_device_stats statistics; rwlock_t hash_lock; struct hlist_head hash[BR_HASH_SIZE]; @@ -165,7 +167,7 @@ extern int br_del_bridge(const char *name); extern void br_cleanup_bridges(void); extern int br_add_if(struct net_bridge *br, - struct net_device *dev); + struct net_device *dev, struct net_device *rdev); extern int br_del_if(struct net_bridge *br, struct net_device *dev); extern int br_get_bridge_ifindices(int *indices, @@ -195,6 +197,7 @@ u16 port_no); extern void br_init_port(struct net_bridge_port *p); extern void br_become_designated_port(struct net_bridge_port *p); +void check_link( struct net_bridge_port *p ); /* br_stp_if.c */ extern void br_stp_enable_bridge(struct net_bridge *br); diff -urN ./linux-2.6.6-old/net/bridge/br_stp.c ./linux-2.6.6/net/bridge/br_stp.c --- ./linux-2.6.6-old/net/bridge/br_stp.c 2004-05-10 04:32:25.000000000 +0200 +++ ./linux-2.6.6/net/bridge/br_stp.c 2004-06-16 12:29:25.000000000 +0200 @@ -14,6 +14,7 @@ */ #include #include +#include #include "br_private.h" #include "br_private_stp.h" @@ -24,6 +25,7 @@ [BR_STATE_LEARNING] = "learning", [BR_STATE_FORWARDING] = "forwarding", [BR_STATE_BLOCKING] = "blocking", + [BR_STATE_NOLINK] = "nolink", }; void br_log_state(const struct net_bridge_port *p) @@ -351,10 +353,11 @@ if (p->state != BR_STATE_DISABLED && p->state != BR_STATE_BLOCKING) { if (p->state == BR_STATE_FORWARDING || - p->state == BR_STATE_LEARNING) + p->state == BR_STATE_LEARNING || + p->state == BR_STATE_NOLINK ) br_topology_change_detection(p->br); - p->state = BR_STATE_BLOCKING; + if ( p->state != BR_STATE_NOLINK ) p->state = BR_STATE_BLOCKING; br_log_state(p); del_timer(&p->forward_delay_timer); } @@ -363,14 +366,55 @@ /* called under bridge lock */ static void br_make_forwarding(struct net_bridge_port *p) { - if (p->state == BR_STATE_BLOCKING) { - if (p->br->stp_enabled) { - p->state = BR_STATE_LISTENING; - } else { - p->state = BR_STATE_LEARNING; - } - br_log_state(p); - mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay); } + if (p->state == BR_STATE_BLOCKING ) { + if (p->br->stp_enabled) { + p->state = BR_STATE_LISTENING; + } else { + p->state = BR_STATE_LEARNING; + } + br_log_state(p); + mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay); } +} + +void check_link( struct net_bridge_port *p ) +{ + if ( p->rdev != NULL ) { + if ( ethtool_op_get_link( p->rdev ) ) { + if ( p->state == BR_STATE_NOLINK ) { + spin_lock_bh(&p->br->lock); + p->state=BR_STATE_BLOCKING; + p->config_pending = 0; + p->topology_change_ack = 0; + br_log_state(p); + br_make_forwarding(p); + spin_unlock_bh(&p->br->lock); + } + return; + } + } else { + if ( ethtool_op_get_link( p->dev ) ) { + if ( p->state == BR_STATE_NOLINK ) { + spin_lock_bh(&p->br->lock); + p->state=BR_STATE_BLOCKING; + p->config_pending = 0; + p->topology_change_ack = 0; + br_log_state(p); + br_make_forwarding(p); + spin_unlock_bh(&p->br->lock); + } + return; + } + } + if ( p->state != BR_STATE_NOLINK ) { + spin_lock_bh(&p->br->lock); + p->config_pending = 0; + p->topology_change_ack = 0; + br_make_blocking(p); + p->state=BR_STATE_NOLINK; + spin_unlock_bh(&p->br->lock); + br_log_state(p); + } + return; } /* called under bridge lock */ @@ -379,11 +423,11 @@ struct net_bridge_port *p; list_for_each_entry(p, &br->port_list, list) { - if (p->state != BR_STATE_DISABLED) { + if (p->state != BR_STATE_DISABLED ) { if (p->port_no == br->root_port) { p->config_pending = 0; p->topology_change_ack = 0; - br_make_forwarding(p); + br_make_forwarding(p); } else if (br_is_designated_port(p)) { del_timer(&p->message_age_timer); br_make_forwarding(p); diff -urN ./linux-2.6.6-old/net/bridge/br_stp_timer.c ./linux-2.6.6/net/bridge/br_stp_timer.c --- ./linux-2.6.6-old/net/bridge/br_stp_timer.c 2004-05-10 04:32:37.000000000 +0200 +++ ./linux-2.6.6/net/bridge/br_stp_timer.c 2004-06-16 13:42:00.000000000 +0200 @@ -136,7 +136,9 @@ pr_debug("%s: %d(%s) hold timer expired\n", p->br->dev->name, p->port_no, p->dev->name); - + if (p->br->stp_enabled) { + check_link(p); + } spin_lock_bh(&p->br->lock); if (p->config_pending) br_transmit_config(p);