diff options
author | Krzysztof Halasa <khc@pm.waw.pl> | 2008-05-19 13:11:08 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-22 06:18:18 -0400 |
commit | aff26e2faa782e196f28b86d04b093fd3bae1ffb (patch) | |
tree | f8ce61aba1566e11f4e36b415d0ef6dce1f972e8 /drivers/net/wan | |
parent | 0178ec3d3e4e48c63b350e712835a4a5c15c6c86 (diff) |
WAN: protect Cisco HDLC state changes with a spinlock.
Signed-off-by: Krzysztof HaĆasa <khc@pm.waw.pl>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/wan')
-rw-r--r-- | drivers/net/wan/hdlc_cisco.c | 82 |
1 files changed, 49 insertions, 33 deletions
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 7133c688cf20..762d21c1c703 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c | |||
@@ -56,6 +56,7 @@ struct cisco_state { | |||
56 | cisco_proto settings; | 56 | cisco_proto settings; |
57 | 57 | ||
58 | struct timer_list timer; | 58 | struct timer_list timer; |
59 | spinlock_t lock; | ||
59 | unsigned long last_poll; | 60 | unsigned long last_poll; |
60 | int up; | 61 | int up; |
61 | int request_sent; | 62 | int request_sent; |
@@ -158,6 +159,7 @@ static int cisco_rx(struct sk_buff *skb) | |||
158 | { | 159 | { |
159 | struct net_device *dev = skb->dev; | 160 | struct net_device *dev = skb->dev; |
160 | hdlc_device *hdlc = dev_to_hdlc(dev); | 161 | hdlc_device *hdlc = dev_to_hdlc(dev); |
162 | struct cisco_state *st = state(hdlc); | ||
161 | struct hdlc_header *data = (struct hdlc_header*)skb->data; | 163 | struct hdlc_header *data = (struct hdlc_header*)skb->data; |
162 | struct cisco_packet *cisco_data; | 164 | struct cisco_packet *cisco_data; |
163 | struct in_device *in_dev; | 165 | struct in_device *in_dev; |
@@ -220,11 +222,12 @@ static int cisco_rx(struct sk_buff *skb) | |||
220 | goto rx_error; | 222 | goto rx_error; |
221 | 223 | ||
222 | case CISCO_KEEPALIVE_REQ: | 224 | case CISCO_KEEPALIVE_REQ: |
223 | state(hdlc)->rxseq = ntohl(cisco_data->par1); | 225 | spin_lock(&st->lock); |
224 | if (state(hdlc)->request_sent && | 226 | st->rxseq = ntohl(cisco_data->par1); |
225 | ntohl(cisco_data->par2) == state(hdlc)->txseq) { | 227 | if (st->request_sent && |
226 | state(hdlc)->last_poll = jiffies; | 228 | ntohl(cisco_data->par2) == st->txseq) { |
227 | if (!state(hdlc)->up) { | 229 | st->last_poll = jiffies; |
230 | if (!st->up) { | ||
228 | u32 sec, min, hrs, days; | 231 | u32 sec, min, hrs, days; |
229 | sec = ntohl(cisco_data->time) / 1000; | 232 | sec = ntohl(cisco_data->time) / 1000; |
230 | min = sec / 60; sec -= min * 60; | 233 | min = sec / 60; sec -= min * 60; |
@@ -232,12 +235,12 @@ static int cisco_rx(struct sk_buff *skb) | |||
232 | days = hrs / 24; hrs -= days * 24; | 235 | days = hrs / 24; hrs -= days * 24; |
233 | printk(KERN_INFO "%s: Link up (peer " | 236 | printk(KERN_INFO "%s: Link up (peer " |
234 | "uptime %ud%uh%um%us)\n", | 237 | "uptime %ud%uh%um%us)\n", |
235 | dev->name, days, hrs, | 238 | dev->name, days, hrs, min, sec); |
236 | min, sec); | ||
237 | netif_dormant_off(dev); | 239 | netif_dormant_off(dev); |
238 | state(hdlc)->up = 1; | 240 | st->up = 1; |
239 | } | 241 | } |
240 | } | 242 | } |
243 | spin_unlock(&st->lock); | ||
241 | 244 | ||
242 | dev_kfree_skb_any(skb); | 245 | dev_kfree_skb_any(skb); |
243 | return NET_RX_SUCCESS; | 246 | return NET_RX_SUCCESS; |
@@ -261,24 +264,25 @@ static void cisco_timer(unsigned long arg) | |||
261 | { | 264 | { |
262 | struct net_device *dev = (struct net_device *)arg; | 265 | struct net_device *dev = (struct net_device *)arg; |
263 | hdlc_device *hdlc = dev_to_hdlc(dev); | 266 | hdlc_device *hdlc = dev_to_hdlc(dev); |
267 | struct cisco_state *st = state(hdlc); | ||
264 | 268 | ||
265 | if (state(hdlc)->up && | 269 | spin_lock(&st->lock); |
266 | time_after(jiffies, state(hdlc)->last_poll + | 270 | if (st->up && |
267 | state(hdlc)->settings.timeout * HZ)) { | 271 | time_after(jiffies, st->last_poll + st->settings.timeout * HZ)) { |
268 | state(hdlc)->up = 0; | 272 | st->up = 0; |
269 | printk(KERN_INFO "%s: Link down\n", dev->name); | 273 | printk(KERN_INFO "%s: Link down\n", dev->name); |
270 | netif_dormant_on(dev); | 274 | netif_dormant_on(dev); |
271 | } | 275 | } |
272 | 276 | ||
273 | cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, | 277 | cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, htonl(++st->txseq), |
274 | htonl(++state(hdlc)->txseq), | 278 | htonl(st->rxseq)); |
275 | htonl(state(hdlc)->rxseq)); | 279 | st->request_sent = 1; |
276 | state(hdlc)->request_sent = 1; | 280 | spin_unlock(&st->lock); |
277 | state(hdlc)->timer.expires = jiffies + | 281 | |
278 | state(hdlc)->settings.interval * HZ; | 282 | st->timer.expires = jiffies + st->settings.interval * HZ; |
279 | state(hdlc)->timer.function = cisco_timer; | 283 | st->timer.function = cisco_timer; |
280 | state(hdlc)->timer.data = arg; | 284 | st->timer.data = arg; |
281 | add_timer(&state(hdlc)->timer); | 285 | add_timer(&st->timer); |
282 | } | 286 | } |
283 | 287 | ||
284 | 288 | ||
@@ -286,15 +290,20 @@ static void cisco_timer(unsigned long arg) | |||
286 | static void cisco_start(struct net_device *dev) | 290 | static void cisco_start(struct net_device *dev) |
287 | { | 291 | { |
288 | hdlc_device *hdlc = dev_to_hdlc(dev); | 292 | hdlc_device *hdlc = dev_to_hdlc(dev); |
289 | state(hdlc)->up = 0; | 293 | struct cisco_state *st = state(hdlc); |
290 | state(hdlc)->request_sent = 0; | 294 | unsigned long flags; |
291 | state(hdlc)->txseq = state(hdlc)->rxseq = 0; | 295 | |
292 | 296 | spin_lock_irqsave(&st->lock, flags); | |
293 | init_timer(&state(hdlc)->timer); | 297 | st->up = 0; |
294 | state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/ | 298 | st->request_sent = 0; |
295 | state(hdlc)->timer.function = cisco_timer; | 299 | st->txseq = st->rxseq = 0; |
296 | state(hdlc)->timer.data = (unsigned long)dev; | 300 | spin_unlock_irqrestore(&st->lock, flags); |
297 | add_timer(&state(hdlc)->timer); | 301 | |
302 | init_timer(&st->timer); | ||
303 | st->timer.expires = jiffies + HZ; /* First poll after 1 s */ | ||
304 | st->timer.function = cisco_timer; | ||
305 | st->timer.data = (unsigned long)dev; | ||
306 | add_timer(&st->timer); | ||
298 | } | 307 | } |
299 | 308 | ||
300 | 309 | ||
@@ -302,10 +311,16 @@ static void cisco_start(struct net_device *dev) | |||
302 | static void cisco_stop(struct net_device *dev) | 311 | static void cisco_stop(struct net_device *dev) |
303 | { | 312 | { |
304 | hdlc_device *hdlc = dev_to_hdlc(dev); | 313 | hdlc_device *hdlc = dev_to_hdlc(dev); |
305 | del_timer_sync(&state(hdlc)->timer); | 314 | struct cisco_state *st = state(hdlc); |
315 | unsigned long flags; | ||
316 | |||
317 | del_timer_sync(&st->timer); | ||
318 | |||
319 | spin_lock_irqsave(&st->lock, flags); | ||
306 | netif_dormant_on(dev); | 320 | netif_dormant_on(dev); |
307 | state(hdlc)->up = 0; | 321 | st->up = 0; |
308 | state(hdlc)->request_sent = 0; | 322 | st->request_sent = 0; |
323 | spin_unlock_irqrestore(&st->lock, flags); | ||
309 | } | 324 | } |
310 | 325 | ||
311 | 326 | ||
@@ -367,6 +382,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) | |||
367 | return result; | 382 | return result; |
368 | 383 | ||
369 | memcpy(&state(hdlc)->settings, &new_settings, size); | 384 | memcpy(&state(hdlc)->settings, &new_settings, size); |
385 | spin_lock_init(&state(hdlc)->lock); | ||
370 | dev->hard_start_xmit = hdlc->xmit; | 386 | dev->hard_start_xmit = hdlc->xmit; |
371 | dev->header_ops = &cisco_header_ops; | 387 | dev->header_ops = &cisco_header_ops; |
372 | dev->type = ARPHRD_CISCO; | 388 | dev->type = ARPHRD_CISCO; |