diff options
Diffstat (limited to 'net/bridge/br_if.c')
-rw-r--r-- | net/bridge/br_if.c | 55 |
1 files changed, 41 insertions, 14 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 975abe254b7a..11321197338e 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 | */ |
35 | static int br_initial_port_cost(struct net_device *dev) | 35 | static 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 | */ | ||
79 | static 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 | |||
78 | static void destroy_nbp(struct net_bridge_port *p) | 102 | static 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); |
@@ -155,6 +182,7 @@ static struct net_device *new_bridge_dev(const char *name) | |||
155 | br->bridge_id.prio[1] = 0x00; | 182 | br->bridge_id.prio[1] = 0x00; |
156 | memset(br->bridge_id.addr, 0, ETH_ALEN); | 183 | memset(br->bridge_id.addr, 0, ETH_ALEN); |
157 | 184 | ||
185 | br->feature_mask = dev->features; | ||
158 | br->stp_enabled = 0; | 186 | br->stp_enabled = 0; |
159 | br->designated_root = br->bridge_id; | 187 | br->designated_root = br->bridge_id; |
160 | br->root_path_cost = 0; | 188 | br->root_path_cost = 0; |
@@ -195,10 +223,9 @@ static int find_portno(struct net_bridge *br) | |||
195 | return (index >= BR_MAX_PORTS) ? -EXFULL : index; | 223 | return (index >= BR_MAX_PORTS) ? -EXFULL : index; |
196 | } | 224 | } |
197 | 225 | ||
198 | /* called with RTNL */ | 226 | /* called with RTNL but without bridge lock */ |
199 | static struct net_bridge_port *new_nbp(struct net_bridge *br, | 227 | static struct net_bridge_port *new_nbp(struct net_bridge *br, |
200 | struct net_device *dev, | 228 | struct net_device *dev) |
201 | unsigned long cost) | ||
202 | { | 229 | { |
203 | int index; | 230 | int index; |
204 | struct net_bridge_port *p; | 231 | struct net_bridge_port *p; |
@@ -215,12 +242,13 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, | |||
215 | p->br = br; | 242 | p->br = br; |
216 | dev_hold(dev); | 243 | dev_hold(dev); |
217 | p->dev = dev; | 244 | p->dev = dev; |
218 | p->path_cost = cost; | 245 | p->path_cost = port_cost(dev); |
219 | p->priority = 0x8000 >> BR_PORT_BITS; | 246 | p->priority = 0x8000 >> BR_PORT_BITS; |
220 | dev->br_port = p; | 247 | dev->br_port = p; |
221 | p->port_no = index; | 248 | p->port_no = index; |
222 | br_init_port(p); | 249 | br_init_port(p); |
223 | p->state = BR_STATE_DISABLED; | 250 | p->state = BR_STATE_DISABLED; |
251 | INIT_WORK(&p->carrier_check, port_carrier_check, p); | ||
224 | kobject_init(&p->kobj); | 252 | kobject_init(&p->kobj); |
225 | 253 | ||
226 | return p; | 254 | return p; |
@@ -322,9 +350,8 @@ void br_features_recompute(struct net_bridge *br) | |||
322 | struct net_bridge_port *p; | 350 | struct net_bridge_port *p; |
323 | unsigned long features, checksum; | 351 | unsigned long features, checksum; |
324 | 352 | ||
325 | features = NETIF_F_SG | NETIF_F_FRAGLIST | 353 | features = br->feature_mask &~ NETIF_F_IP_CSUM; |
326 | | NETIF_F_HIGHDMA | NETIF_F_TSO; | 354 | checksum = br->feature_mask & NETIF_F_IP_CSUM; |
327 | checksum = NETIF_F_IP_CSUM; /* least commmon subset */ | ||
328 | 355 | ||
329 | list_for_each_entry(p, &br->port_list, list) { | 356 | list_for_each_entry(p, &br->port_list, list) { |
330 | if (!(p->dev->features | 357 | if (!(p->dev->features |
@@ -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))) |