aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_if.c49
-rw-r--r--net/bridge/br_notify.c14
-rw-r--r--net/bridge/br_private.h3
3 files changed, 44 insertions, 22 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 975abe254b7a..e6b8bb51d613 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -32,9 +32,8 @@
32 * ethtool, use ethtool_ops. Also, since driver might sleep need to 32 * ethtool, use ethtool_ops. Also, since driver might sleep need to
33 * not be holding any locks. 33 * not be holding any locks.
34 */ 34 */
35static int br_initial_port_cost(struct net_device *dev) 35static int port_cost(struct net_device *dev)
36{ 36{
37
38 struct ethtool_cmd ecmd = { ETHTOOL_GSET }; 37 struct ethtool_cmd ecmd = { ETHTOOL_GSET };
39 struct ifreq ifr; 38 struct ifreq ifr;
40 mm_segment_t old_fs; 39 mm_segment_t old_fs;
@@ -58,10 +57,6 @@ static int br_initial_port_cost(struct net_device *dev)
58 return 2; 57 return 2;
59 case SPEED_10: 58 case SPEED_10:
60 return 100; 59 return 100;
61 default:
62 pr_info("bridge: can't decode speed from %s: %d\n",
63 dev->name, ecmd.speed);
64 return 100;
65 } 60 }
66 } 61 }
67 62
@@ -75,6 +70,35 @@ static int br_initial_port_cost(struct net_device *dev)
75 return 100; /* assume old 10Mbps */ 70 return 100; /* assume old 10Mbps */
76} 71}
77 72
73
74/*
75 * Check for port carrier transistions.
76 * Called from work queue to allow for calling functions that
77 * might sleep (such as speed check), and to debounce.
78 */
79static void port_carrier_check(void *arg)
80{
81 struct net_bridge_port *p = arg;
82
83 rtnl_lock();
84 if (netif_carrier_ok(p->dev)) {
85 u32 cost = port_cost(p->dev);
86
87 spin_lock_bh(&p->br->lock);
88 if (p->state == BR_STATE_DISABLED) {
89 p->path_cost = cost;
90 br_stp_enable_port(p);
91 }
92 spin_unlock_bh(&p->br->lock);
93 } else {
94 spin_lock_bh(&p->br->lock);
95 if (p->state != BR_STATE_DISABLED)
96 br_stp_disable_port(p);
97 spin_unlock_bh(&p->br->lock);
98 }
99 rtnl_unlock();
100}
101
78static void destroy_nbp(struct net_bridge_port *p) 102static void destroy_nbp(struct net_bridge_port *p)
79{ 103{
80 struct net_device *dev = p->dev; 104 struct net_device *dev = p->dev;
@@ -102,6 +126,9 @@ static void del_nbp(struct net_bridge_port *p)
102 dev->br_port = NULL; 126 dev->br_port = NULL;
103 dev_set_promiscuity(dev, -1); 127 dev_set_promiscuity(dev, -1);
104 128
129 cancel_delayed_work(&p->carrier_check);
130 flush_scheduled_work();
131
105 spin_lock_bh(&br->lock); 132 spin_lock_bh(&br->lock);
106 br_stp_disable_port(p); 133 br_stp_disable_port(p);
107 spin_unlock_bh(&br->lock); 134 spin_unlock_bh(&br->lock);
@@ -195,10 +222,9 @@ static int find_portno(struct net_bridge *br)
195 return (index >= BR_MAX_PORTS) ? -EXFULL : index; 222 return (index >= BR_MAX_PORTS) ? -EXFULL : index;
196} 223}
197 224
198/* called with RTNL */ 225/* called with RTNL but without bridge lock */
199static struct net_bridge_port *new_nbp(struct net_bridge *br, 226static struct net_bridge_port *new_nbp(struct net_bridge *br,
200 struct net_device *dev, 227 struct net_device *dev)
201 unsigned long cost)
202{ 228{
203 int index; 229 int index;
204 struct net_bridge_port *p; 230 struct net_bridge_port *p;
@@ -215,12 +241,13 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
215 p->br = br; 241 p->br = br;
216 dev_hold(dev); 242 dev_hold(dev);
217 p->dev = dev; 243 p->dev = dev;
218 p->path_cost = cost; 244 p->path_cost = port_cost(dev);
219 p->priority = 0x8000 >> BR_PORT_BITS; 245 p->priority = 0x8000 >> BR_PORT_BITS;
220 dev->br_port = p; 246 dev->br_port = p;
221 p->port_no = index; 247 p->port_no = index;
222 br_init_port(p); 248 br_init_port(p);
223 p->state = BR_STATE_DISABLED; 249 p->state = BR_STATE_DISABLED;
250 INIT_WORK(&p->carrier_check, port_carrier_check, p);
224 kobject_init(&p->kobj); 251 kobject_init(&p->kobj);
225 252
226 return p; 253 return p;
@@ -351,7 +378,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
351 if (dev->br_port != NULL) 378 if (dev->br_port != NULL)
352 return -EBUSY; 379 return -EBUSY;
353 380
354 if (IS_ERR(p = new_nbp(br, dev, br_initial_port_cost(dev)))) 381 if (IS_ERR(p = new_nbp(br, dev)))
355 return PTR_ERR(p); 382 return PTR_ERR(p);
356 383
357 if ((err = br_fdb_insert(br, p, dev->dev_addr))) 384 if ((err = br_fdb_insert(br, p, dev->dev_addr)))
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 917311c6828b..a43a9c1d50d7 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -52,17 +52,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
52 br_stp_recalculate_bridge_id(br); 52 br_stp_recalculate_bridge_id(br);
53 break; 53 break;
54 54
55 case NETDEV_CHANGE: /* device is up but carrier changed */ 55 case NETDEV_CHANGE:
56 if (!(br->dev->flags & IFF_UP)) 56 if (br->dev->flags & IFF_UP)
57 break; 57 schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE);
58
59 if (netif_carrier_ok(dev)) {
60 if (p->state == BR_STATE_DISABLED)
61 br_stp_enable_port(p);
62 } else {
63 if (p->state != BR_STATE_DISABLED)
64 br_stp_disable_port(p);
65 }
66 break; 58 break;
67 59
68 case NETDEV_FEAT_CHANGE: 60 case NETDEV_FEAT_CHANGE:
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 2c249486476f..7ad53c2aa684 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -27,6 +27,8 @@
27#define BR_PORT_BITS 10 27#define BR_PORT_BITS 10
28#define BR_MAX_PORTS (1<<BR_PORT_BITS) 28#define BR_MAX_PORTS (1<<BR_PORT_BITS)
29 29
30#define BR_PORT_DEBOUNCE (HZ/10)
31
30typedef struct bridge_id bridge_id; 32typedef struct bridge_id bridge_id;
31typedef struct mac_addr mac_addr; 33typedef struct mac_addr mac_addr;
32typedef __u16 port_id; 34typedef __u16 port_id;
@@ -78,6 +80,7 @@ struct net_bridge_port
78 struct timer_list hold_timer; 80 struct timer_list hold_timer;
79 struct timer_list message_age_timer; 81 struct timer_list message_age_timer;
80 struct kobject kobj; 82 struct kobject kobj;
83 struct work_struct carrier_check;
81 struct rcu_head rcu; 84 struct rcu_head rcu;
82}; 85};
83 86