aboutsummaryrefslogtreecommitdiffstats
path: root/net/atm/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/atm/common.c')
-rw-r--r--net/atm/common.c66
1 files changed, 40 insertions, 26 deletions
diff --git a/net/atm/common.c b/net/atm/common.c
index 63feea49fb13..6656b111cc05 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -221,6 +221,29 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)
221EXPORT_SYMBOL(vcc_release_async); 221EXPORT_SYMBOL(vcc_release_async);
222 222
223 223
224void atm_dev_release_vccs(struct atm_dev *dev)
225{
226 int i;
227
228 write_lock_irq(&vcc_sklist_lock);
229 for (i = 0; i < VCC_HTABLE_SIZE; i++) {
230 struct hlist_head *head = &vcc_hash[i];
231 struct hlist_node *node, *tmp;
232 struct sock *s;
233 struct atm_vcc *vcc;
234
235 sk_for_each_safe(s, node, tmp, head) {
236 vcc = atm_sk(s);
237 if (vcc->dev == dev) {
238 vcc_release_async(vcc, -EPIPE);
239 sk_del_node_init(s);
240 }
241 }
242 }
243 write_unlock_irq(&vcc_sklist_lock);
244}
245
246
224static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) 247static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
225{ 248{
226 int max_sdu; 249 int max_sdu;
@@ -332,12 +355,13 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
332 return -EINVAL; 355 return -EINVAL;
333 if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) 356 if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
334 return -EPERM; 357 return -EPERM;
335 error = 0; 358 error = -ENODEV;
336 if (!try_module_get(dev->ops->owner)) 359 if (!try_module_get(dev->ops->owner))
337 return -ENODEV; 360 return error;
338 vcc->dev = dev; 361 vcc->dev = dev;
339 write_lock_irq(&vcc_sklist_lock); 362 write_lock_irq(&vcc_sklist_lock);
340 if ((error = find_ci(vcc, &vpi, &vci))) { 363 if (test_bit(ATM_DF_REMOVED, &dev->flags) ||
364 (error = find_ci(vcc, &vpi, &vci))) {
341 write_unlock_irq(&vcc_sklist_lock); 365 write_unlock_irq(&vcc_sklist_lock);
342 goto fail_module_put; 366 goto fail_module_put;
343 } 367 }
@@ -423,33 +447,23 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
423 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || 447 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
424 vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) 448 vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
425 return -EINVAL; 449 return -EINVAL;
426 if (itf != ATM_ITF_ANY) { 450 if (likely(itf != ATM_ITF_ANY)) {
427 dev = atm_dev_lookup(itf); 451 dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
428 if (!dev)
429 return -ENODEV;
430 error = __vcc_connect(vcc, dev, vpi, vci);
431 if (error) {
432 atm_dev_put(dev);
433 return error;
434 }
435 } else { 452 } else {
436 struct list_head *p, *next;
437
438 dev = NULL; 453 dev = NULL;
439 spin_lock(&atm_dev_lock); 454 down(&atm_dev_mutex);
440 list_for_each_safe(p, next, &atm_devs) { 455 if (!list_empty(&atm_devs)) {
441 dev = list_entry(p, struct atm_dev, dev_list); 456 dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
442 atm_dev_hold(dev); 457 atm_dev_hold(dev);
443 spin_unlock(&atm_dev_lock);
444 if (!__vcc_connect(vcc, dev, vpi, vci))
445 break;
446 atm_dev_put(dev);
447 dev = NULL;
448 spin_lock(&atm_dev_lock);
449 } 458 }
450 spin_unlock(&atm_dev_lock); 459 up(&atm_dev_mutex);
451 if (!dev) 460 }
452 return -ENODEV; 461 if (!dev)
462 return -ENODEV;
463 error = __vcc_connect(vcc, dev, vpi, vci);
464 if (error) {
465 atm_dev_put(dev);
466 return error;
453 } 467 }
454 if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) 468 if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
455 set_bit(ATM_VF_PARTIAL,&vcc->flags); 469 set_bit(ATM_VF_PARTIAL,&vcc->flags);