diff options
Diffstat (limited to 'net/atm')
-rw-r--r-- | net/atm/addr.c | 55 | ||||
-rw-r--r-- | net/atm/addr.h | 12 | ||||
-rw-r--r-- | net/atm/atm_misc.c | 13 | ||||
-rw-r--r-- | net/atm/br2684.c | 2 | ||||
-rw-r--r-- | net/atm/clip.c | 2 | ||||
-rw-r--r-- | net/atm/common.c | 72 | ||||
-rw-r--r-- | net/atm/common.h | 2 | ||||
-rw-r--r-- | net/atm/ioctl.c | 34 | ||||
-rw-r--r-- | net/atm/lec.c | 43 | ||||
-rw-r--r-- | net/atm/resources.c | 98 | ||||
-rw-r--r-- | net/atm/resources.h | 3 | ||||
-rw-r--r-- | net/atm/signaling.c | 8 | ||||
-rw-r--r-- | net/atm/svc.c | 1 |
13 files changed, 221 insertions, 124 deletions
diff --git a/net/atm/addr.c b/net/atm/addr.c index 1c8867f7f54a..3060fd0ba4b9 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -44,29 +44,43 @@ static void notify_sigd(struct atm_dev *dev) sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); } -void atm_reset_addr(struct atm_dev *dev) +void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype) { unsigned long flags; struct atm_dev_addr *this, *p; + struct list_head *head; spin_lock_irqsave(&dev->lock, flags); - list_for_each_entry_safe(this, p, &dev->local, entry) - kfree(this); + if (atype == ATM_ADDR_LECS) + head = &dev->lecs; + else + head = &dev->local; + list_for_each_entry_safe(this, p, head, entry) { + list_del(&this->entry); + kfree(this); + } spin_unlock_irqrestore(&dev->lock, flags); - notify_sigd(dev); + if (head == &dev->local) + notify_sigd(dev); } -int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) +int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, + enum atm_addr_type_t atype) { unsigned long flags; struct atm_dev_addr *this; + struct list_head *head; int error; error = check_addr(addr); if (error) return error; spin_lock_irqsave(&dev->lock, flags); - list_for_each_entry(this, &dev->local, entry) { + if (atype == ATM_ADDR_LECS) + head = &dev->lecs; + else + head = &dev->local; + list_for_each_entry(this, head, entry) { if (identical(&this->addr, addr)) { spin_unlock_irqrestore(&dev->lock, flags); return -EEXIST; @@ -78,28 +92,36 @@ int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) return -ENOMEM; } this->addr = *addr; - list_add(&this->entry, &dev->local); + list_add(&this->entry, head); spin_unlock_irqrestore(&dev->lock, flags); - notify_sigd(dev); + if (head == &dev->local) + notify_sigd(dev); return 0; } -int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) +int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, + enum atm_addr_type_t atype) { unsigned long flags; struct atm_dev_addr *this; + struct list_head *head; int error; error = check_addr(addr); if (error) return error; spin_lock_irqsave(&dev->lock, flags); - list_for_each_entry(this, &dev->local, entry) { + if (atype == ATM_ADDR_LECS) + head = &dev->lecs; + else + head = &dev->local; + list_for_each_entry(this, head, entry) { if (identical(&this->addr, addr)) { list_del(&this->entry); spin_unlock_irqrestore(&dev->lock, flags); kfree(this); - notify_sigd(dev); + if (head == &dev->local) + notify_sigd(dev); return 0; } } @@ -108,22 +130,27 @@ int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) } int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, - size_t size) + size_t size, enum atm_addr_type_t atype) { unsigned long flags; struct atm_dev_addr *this; + struct list_head *head; int total = 0, error; struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; spin_lock_irqsave(&dev->lock, flags); - list_for_each_entry(this, &dev->local, entry) + if (atype == ATM_ADDR_LECS) + head = &dev->lecs; + else + head = &dev->local; + list_for_each_entry(this, head, entry) total += sizeof(struct sockaddr_atmsvc); tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); if (!tmp_buf) { spin_unlock_irqrestore(&dev->lock, flags); return -ENOMEM; } - list_for_each_entry(this, &dev->local, entry) + list_for_each_entry(this, head, entry) memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); spin_unlock_irqrestore(&dev->lock, flags); error = total > size ? -E2BIG : total; diff --git a/net/atm/addr.h b/net/atm/addr.h index 3099d21feeaa..f39433ad45da 100644 --- a/net/atm/addr.h +++ b/net/atm/addr.h @@ -9,10 +9,12 @@ #include <linux/atm.h> #include <linux/atmdev.h> - -void atm_reset_addr(struct atm_dev *dev); -int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); -int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); -int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc __user *buf,size_t size); +void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t type); +int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, + enum atm_addr_type_t type); +int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, + enum atm_addr_type_t type); +int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user *buf, + size_t size, enum atm_addr_type_t type); #endif diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c index b2113c3454ae..02cc7e71efea 100644 --- a/net/atm/atm_misc.c +++ b/net/atm/atm_misc.c @@ -25,7 +25,7 @@ int atm_charge(struct atm_vcc *vcc,int truesize) struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, - int gfp_flags) + gfp_t gfp_flags) { struct sock *sk = sk_atm(vcc); int guess = atm_guess_pdu2truesize(pdu_size); @@ -74,11 +74,14 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, */ -int atm_pcr_goal(struct atm_trafprm *tp) +int atm_pcr_goal(const struct atm_trafprm *tp) { - if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr; - if (tp->min_pcr && !tp->pcr) return tp->min_pcr; - if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr; + if (tp->pcr && tp->pcr != ATM_MAX_PCR) + return -tp->pcr; + if (tp->min_pcr && !tp->pcr) + return tp->min_pcr; + if (tp->max_pcr != ATM_MAX_PCR) + return -tp->max_pcr; return 0; } diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 289956c4dd3e..72f3f7b8de80 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -220,7 +220,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) /* netif_stop_queue(dev); */ dev_kfree_skb(skb); read_unlock(&devs_lock); - return -EUNATCH; + return 0; } if (!br2684_xmit_vcc(skb, brdev, brvcc)) { /* diff --git a/net/atm/clip.c b/net/atm/clip.c index 28dab55a4387..4f54c9a5e84a 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -310,7 +310,7 @@ static int clip_constructor(struct neighbour *neigh) if (neigh->type != RTN_UNICAST) return -EINVAL; rcu_read_lock(); - in_dev = rcu_dereference(__in_dev_get(dev)); + in_dev = __in_dev_get_rcu(dev); if (!in_dev) { rcu_read_unlock(); return -EINVAL; diff --git a/net/atm/common.c b/net/atm/common.c index e93e838069e8..6656b111cc05 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -46,7 +46,7 @@ static void __vcc_insert_socket(struct sock *sk) struct atm_vcc *vcc = atm_sk(sk); struct hlist_head *head = &vcc_hash[vcc->vci & (VCC_HTABLE_SIZE - 1)]; - sk->sk_hashent = vcc->vci & (VCC_HTABLE_SIZE - 1); + sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1); sk_add_node(sk, head); } @@ -178,8 +178,6 @@ static void vcc_destroy_socket(struct sock *sk) if (vcc->push) vcc->push(vcc, NULL); /* atmarpd has no push */ - vcc_remove_socket(sk); /* no more receive */ - while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { atm_return(vcc,skb->truesize); kfree_skb(skb); @@ -188,6 +186,8 @@ static void vcc_destroy_socket(struct sock *sk) module_put(vcc->dev->ops->owner); atm_dev_put(vcc->dev); } + + vcc_remove_socket(sk); } @@ -221,6 +221,29 @@ void vcc_release_async(struct atm_vcc *vcc, int reply) EXPORT_SYMBOL(vcc_release_async); +void atm_dev_release_vccs(struct atm_dev *dev) +{ + int i; + + write_lock_irq(&vcc_sklist_lock); + for (i = 0; i < VCC_HTABLE_SIZE; i++) { + struct hlist_head *head = &vcc_hash[i]; + struct hlist_node *node, *tmp; + struct sock *s; + struct atm_vcc *vcc; + + sk_for_each_safe(s, node, tmp, head) { + vcc = atm_sk(s); + if (vcc->dev == dev) { + vcc_release_async(vcc, -EPIPE); + sk_del_node_init(s); + } + } + } + write_unlock_irq(&vcc_sklist_lock); +} + + static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) { int max_sdu; @@ -332,12 +355,13 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi, return -EINVAL; if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) return -EPERM; - error = 0; + error = -ENODEV; if (!try_module_get(dev->ops->owner)) - return -ENODEV; + return error; vcc->dev = dev; write_lock_irq(&vcc_sklist_lock); - if ((error = find_ci(vcc, &vpi, &vci))) { + if (test_bit(ATM_DF_REMOVED, &dev->flags) || + (error = find_ci(vcc, &vpi, &vci))) { write_unlock_irq(&vcc_sklist_lock); goto fail_module_put; } @@ -423,33 +447,23 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) return -EINVAL; - if (itf != ATM_ITF_ANY) { - dev = atm_dev_lookup(itf); - if (!dev) - return -ENODEV; - error = __vcc_connect(vcc, dev, vpi, vci); - if (error) { - atm_dev_put(dev); - return error; - } + if (likely(itf != ATM_ITF_ANY)) { + dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); } else { - struct list_head *p, *next; - dev = NULL; - spin_lock(&atm_dev_lock); - list_for_each_safe(p, next, &atm_devs) { - dev = list_entry(p, struct atm_dev, dev_list); + down(&atm_dev_mutex); + if (!list_empty(&atm_devs)) { + dev = list_entry(atm_devs.next, struct atm_dev, dev_list); atm_dev_hold(dev); - spin_unlock(&atm_dev_lock); - if (!__vcc_connect(vcc, dev, vpi, vci)) - break; - atm_dev_put(dev); - dev = NULL; - spin_lock(&atm_dev_lock); } - spin_unlock(&atm_dev_lock); - if (!dev) - return -ENODEV; + up(&atm_dev_mutex); + } + if (!dev) + return -ENODEV; + error = __vcc_connect(vcc, dev, vpi, vci); + if (error) { + atm_dev_put(dev); + return error; } if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) set_bit(ATM_VF_PARTIAL,&vcc->flags); diff --git a/net/atm/common.h b/net/atm/common.h index e49ed41c0e33..4887c317cefe 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -47,4 +47,6 @@ static inline void atm_proc_exit(void) /* SVC */ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); +void atm_dev_release_vccs(struct atm_dev *dev); + #endif diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index d89056ec44d4..a150198b05a3 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -105,17 +105,35 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (!error) sock->state = SS_CONNECTED; goto done; - default: + case ATM_SETBACKEND: + case ATM_NEWBACKENDIF: + { + atm_backend_t backend; + error = get_user(backend, (atm_backend_t __user *) argp); + if (error) + goto done; + switch (backend) { + case ATM_BACKEND_PPP: + request_module("pppoatm"); + break; + case ATM_BACKEND_BR2684: + request_module("br2684"); + break; + } + } + break; + case ATMMPC_CTRL: + case ATMMPC_DATA: + request_module("mpoa"); + break; + case ATMARPD_CTRL: + request_module("clip"); + break; + case ATMLEC_CTRL: + request_module("lec"); break; } - if (cmd == ATMMPC_CTRL || cmd == ATMMPC_DATA) - request_module("mpoa"); - if (cmd == ATMARPD_CTRL) - request_module("clip"); - if (cmd == ATMLEC_CTRL) - request_module("lec"); - error = -ENOIOCTLCMD; down(&ioctl_mutex); diff --git a/net/atm/lec.c b/net/atm/lec.c index a0752487026d..ad840b9afba8 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -686,9 +686,19 @@ static unsigned char lec_ctrl_magic[] = { 0x01, 0x01 }; +#define LEC_DATA_DIRECT_8023 2 +#define LEC_DATA_DIRECT_8025 3 + +static int lec_is_data_direct(struct atm_vcc *vcc) +{ + return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) || + (vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025)); +} + static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) { + unsigned long flags; struct net_device *dev = (struct net_device *)vcc->proto_data; struct lec_priv *priv = (struct lec_priv *)dev->priv; @@ -728,7 +738,8 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb) skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk, skb->len); } else { /* Data frame, queue to protocol handlers */ - unsigned char *dst; + struct lec_arp_table *entry; + unsigned char *src, *dst; atm_return(vcc,skb->truesize); if (*(uint16_t *)skb->data == htons(priv->lecid) || @@ -741,10 +752,30 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb) return; } #ifdef CONFIG_TR - if (priv->is_trdev) dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest; + if (priv->is_trdev) + dst = ((struct lecdatahdr_8025 *) skb->data)->h_dest; else #endif - dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest; + dst = ((struct lecdatahdr_8023 *) skb->data)->h_dest; + + /* If this is a Data Direct VCC, and the VCC does not match + * the LE_ARP cache entry, delete the LE_ARP cache entry. + */ + spin_lock_irqsave(&priv->lec_arp_lock, flags); + if (lec_is_data_direct(vcc)) { +#ifdef CONFIG_TR + if (priv->is_trdev) + src = ((struct lecdatahdr_8025 *) skb->data)->h_source; + else +#endif + src = ((struct lecdatahdr_8023 *) skb->data)->h_source; + entry = lec_arp_find(priv, src); + if (entry && entry->vcc != vcc) { + lec_arp_remove(priv, entry); + kfree(entry); + } + } + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */ !priv->is_proxy && /* Proxy wants all the packets */ @@ -1990,6 +2021,12 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, found = entry->vcc; goto out; } + /* If the LE_ARP cache entry is still pending, reset count to 0 + * so another LE_ARP request can be made for this frame. + */ + if (entry->status == ESI_ARP_PENDING) { + entry->no_tries = 0; + } /* Data direct VC not yet set up, check to see if the unknown frame count is greater than the limit. If the limit has not been reached, allow the caller to send packet to diff --git a/net/atm/resources.c b/net/atm/resources.c index a57a9268bd24..c8c459fcb038 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -25,7 +25,7 @@ LIST_HEAD(atm_devs); -DEFINE_SPINLOCK(atm_dev_lock); +DECLARE_MUTEX(atm_dev_mutex); static struct atm_dev *__alloc_atm_dev(const char *type) { @@ -40,6 +40,7 @@ static struct atm_dev *__alloc_atm_dev(const char *type) dev->link_rate = ATM_OC3_PCR; spin_lock_init(&dev->lock); INIT_LIST_HEAD(&dev->local); + INIT_LIST_HEAD(&dev->lecs); return dev; } @@ -51,7 +52,7 @@ static struct atm_dev *__atm_dev_lookup(int number) list_for_each(p, &atm_devs) { dev = list_entry(p, struct atm_dev, dev_list); - if ((dev->ops) && (dev->number == number)) { + if (dev->number == number) { atm_dev_hold(dev); return dev; } @@ -63,12 +64,13 @@ struct atm_dev *atm_dev_lookup(int number) { struct atm_dev *dev; - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); dev = __atm_dev_lookup(number); - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); return dev; } + struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, int number, unsigned long *flags) { @@ -80,11 +82,11 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, type); return NULL; } - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); if (number != -1) { if ((inuse = __atm_dev_lookup(number))) { atm_dev_put(inuse); - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); kfree(dev); return NULL; } @@ -104,19 +106,17 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, memset(&dev->flags, 0, sizeof(dev->flags)); memset(&dev->stats, 0, sizeof(dev->stats)); atomic_set(&dev->refcnt, 1); - list_add_tail(&dev->dev_list, &atm_devs); - spin_unlock(&atm_dev_lock); if (atm_proc_dev_register(dev) < 0) { printk(KERN_ERR "atm_dev_register: " "atm_proc_dev_register failed for dev %s\n", type); - spin_lock(&atm_dev_lock); - list_del(&dev->dev_list); - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); kfree(dev); return NULL; } + list_add_tail(&dev->dev_list, &atm_devs); + up(&atm_dev_mutex); return dev; } @@ -124,37 +124,22 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, void atm_dev_deregister(struct atm_dev *dev) { - unsigned long warning_time; + BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags)); + set_bit(ATM_DF_REMOVED, &dev->flags); + + /* + * if we remove current device from atm_devs list, new device + * with same number can appear, such we need deregister proc, + * release async all vccs and remove them from vccs list too + */ + down(&atm_dev_mutex); + list_del(&dev->dev_list); + up(&atm_dev_mutex); + atm_dev_release_vccs(dev); atm_proc_dev_deregister(dev); - spin_lock(&atm_dev_lock); - list_del(&dev->dev_list); - spin_unlock(&atm_dev_lock); - - warning_time = jiffies; - while (atomic_read(&dev->refcnt) != 1) { - msleep(250); - if ((jiffies - warning_time) > 10 * HZ) { - printk(KERN_EMERG "atm_dev_deregister: waiting for " - "dev %d to become free. Usage count = %d\n", - dev->number, atomic_read(&dev->refcnt)); - warning_time = jiffies; - } - } - - kfree(dev); -} - -void shutdown_atm_dev(struct atm_dev *dev) -{ - if (atomic_read(&dev->refcnt) > 1) { - set_bit(ATM_DF_CLOSE, &dev->flags); - return; - } - if (dev->ops->dev_close) - dev->ops->dev_close(dev); - atm_dev_deregister(dev); + atm_dev_put(dev); } @@ -210,16 +195,16 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) return -EFAULT; if (get_user(len, &iobuf->length)) return -EFAULT; - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); list_for_each(p, &atm_devs) size += sizeof(int); if (size > len) { - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); return -E2BIG; } tmp_buf = kmalloc(size, GFP_ATOMIC); if (!tmp_buf) { - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); return -ENOMEM; } tmp_p = tmp_buf; @@ -227,7 +212,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) dev = list_entry(p, struct atm_dev, dev_list); *tmp_p++ = dev->number; } - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); error = ((copy_to_user(buf, tmp_buf, size)) || put_user(size, &iobuf->length)) ? -EFAULT : 0; @@ -244,7 +229,8 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) if (get_user(number, &sioc->number)) return -EFAULT; - if (!(dev = atm_dev_lookup(number))) + if (!(dev = try_then_request_module(atm_dev_lookup(number), + "atm-device-%d", number))) return -ENODEV; switch (cmd) { @@ -320,10 +306,12 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) error = -EPERM; goto done; } - atm_reset_addr(dev); + atm_reset_addr(dev, ATM_ADDR_LOCAL); break; case ATM_ADDADDR: case ATM_DELADDR: + case ATM_ADDLECSADDR: + case ATM_DELLECSADDR: if (!capable(CAP_NET_ADMIN)) { error = -EPERM; goto done; @@ -335,14 +323,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) error = -EFAULT; goto done; } - if (cmd == ATM_ADDADDR) - error = atm_add_addr(dev, &addr); + if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) + error = atm_add_addr(dev, &addr, + (cmd == ATM_ADDADDR ? + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); else - error = atm_del_addr(dev, &addr); + error = atm_del_addr(dev, &addr, + (cmd == ATM_DELADDR ? + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); goto done; } case ATM_GETADDR: - error = atm_get_addr(dev, buf, len); + case ATM_GETLECSADDR: + error = atm_get_addr(dev, buf, len, + (cmd == ATM_GETADDR ? + ATM_ADDR_LOCAL : ATM_ADDR_LECS)); if (error < 0) goto done; size = error; @@ -404,13 +399,13 @@ static __inline__ void *dev_get_idx(loff_t left) void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) { - spin_lock(&atm_dev_lock); + down(&atm_dev_mutex); return *pos ? dev_get_idx(*pos) : (void *) 1; } void atm_dev_seq_stop(struct seq_file *seq, void *v) { - spin_unlock(&atm_dev_lock); + up(&atm_dev_mutex); } void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) @@ -424,4 +419,3 @@ void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) EXPORT_SYMBOL(atm_dev_register); EXPORT_SYMBOL(atm_dev_deregister); EXPORT_SYMBOL(atm_dev_lookup); -EXPORT_SYMBOL(shutdown_atm_dev); diff --git a/net/atm/resources.h b/net/atm/resources.h index 12910619dbb6..b7fb82a93b42 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h @@ -11,8 +11,7 @@ extern struct list_head atm_devs; -extern spinlock_t atm_dev_lock; - +extern struct semaphore atm_dev_mutex; int atm_dev_ioctl(unsigned int cmd, void __user *arg); diff --git a/net/atm/signaling.c b/net/atm/signaling.c index f7c449ac1800..e7211a7f382c 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -217,8 +217,9 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, static void purge_vcc(struct atm_vcc *vcc) { if (sk_atm(vcc)->sk_family == PF_ATMSVC && - !test_bit(ATM_VF_META,&vcc->flags)) { - set_bit(ATM_VF_RELEASED,&vcc->flags); + !test_bit(ATM_VF_META, &vcc->flags)) { + set_bit(ATM_VF_RELEASED, &vcc->flags); + clear_bit(ATM_VF_REGIS, &vcc->flags); vcc_release_async(vcc, -EUNATCH); } } @@ -243,8 +244,7 @@ static void sigd_close(struct atm_vcc *vcc) sk_for_each(s, node, head) { struct atm_vcc *vcc = atm_sk(s); - if (vcc->dev) - purge_vcc(vcc); + purge_vcc(vcc); } } read_unlock(&vcc_sklist_lock); diff --git a/net/atm/svc.c b/net/atm/svc.c index 08e46052a3e4..d7b266136bf6 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -302,6 +302,7 @@ static int svc_listen(struct socket *sock,int backlog) error = -EINVAL; goto out; } + vcc_insert_socket(sk); set_bit(ATM_VF_WAITING, &vcc->flags); prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); |