aboutsummaryrefslogtreecommitdiff
path: root/net/atm
diff options
context:
space:
mode:
Diffstat (limited to 'net/atm')
-rw-r--r--net/atm/addr.c6
-rw-r--r--net/atm/clip.c2
-rw-r--r--net/atm/common.c6
-rw-r--r--net/atm/ioctl.c34
-rw-r--r--net/atm/lec.c43
-rw-r--r--net/atm/signaling.c8
-rw-r--r--net/atm/svc.c1
7 files changed, 79 insertions, 21 deletions
diff --git a/net/atm/addr.c b/net/atm/addr.c
index 1c8867f7f54..a30d0bf4806 100644
--- a/net/atm/addr.c
+++ b/net/atm/addr.c
@@ -50,8 +50,10 @@ void atm_reset_addr(struct atm_dev *dev)
struct atm_dev_addr *this, *p;
spin_lock_irqsave(&dev->lock, flags);
- list_for_each_entry_safe(this, p, &dev->local, entry)
- kfree(this);
+ list_for_each_entry_safe(this, p, &dev->local, entry) {
+ list_del(&this->entry);
+ kfree(this);
+ }
spin_unlock_irqrestore(&dev->lock, flags);
notify_sigd(dev);
}
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 28dab55a438..4f54c9a5e84 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 e93e838069e..63feea49fb1 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);
}
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index d89056ec44d..a150198b05a 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 a0752487026..ad840b9afba 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/signaling.c b/net/atm/signaling.c
index f7c449ac180..e7211a7f382 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 08e46052a3e..d7b266136bf 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);