summaryrefslogtreecommitdiffstats
path: root/net/atm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-09 02:54:55 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-09 02:54:55 +0000
commit493c987f7a352ca64fdb4dc03a21e24cbaf46f55 (patch)
tree184cddc0925e082c0500afd042f92e9f340fe890 /net/atm
parent2d25612a92c62b5708d6d43f38d28c6141173328 (diff)
Merge with Linux 2.4.0-pre3-test6.
Diffstat (limited to 'net/atm')
-rw-r--r--net/atm/Makefile2
-rw-r--r--net/atm/clip.c28
-rw-r--r--net/atm/common.c10
-rw-r--r--net/atm/common.h1
-rw-r--r--net/atm/ipcommon.c35
-rw-r--r--net/atm/ipcommon.h4
-rw-r--r--net/atm/lec.c26
-rw-r--r--net/atm/mpc.c2
-rw-r--r--net/atm/proc.c9
-rw-r--r--net/atm/signaling.c27
-rw-r--r--net/atm/signaling.h8
-rw-r--r--net/atm/svc.c13
12 files changed, 104 insertions, 61 deletions
diff --git a/net/atm/Makefile b/net/atm/Makefile
index a43d790b1..c21cdcad1 100644
--- a/net/atm/Makefile
+++ b/net/atm/Makefile
@@ -25,7 +25,7 @@ ifeq ($(CONFIG_NET_SCH_ATM),y)
NEED_IPCOM = ipcommon.o
endif
-O_OBJS += $(NEED_IPCOM)
+OX_OBJS += $(NEED_IPCOM)
ifeq ($(CONFIG_PROC_FS),y)
OX_OBJS += proc.o
diff --git a/net/atm/clip.c b/net/atm/clip.c
index c2b6788c9..ca79e0066 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -274,14 +274,14 @@ static void clip_neigh_error(struct neighbour *neigh,struct sk_buff *skb)
static struct neigh_ops clip_neigh_ops = {
- AF_INET, /* family */
- clip_neigh_destroy, /* destructor */
- clip_neigh_solicit, /* solicit */
- clip_neigh_error, /* error_report */
- dev_queue_xmit, /* output */
- dev_queue_xmit, /* connected_output */
- dev_queue_xmit, /* hh_output */
- dev_queue_xmit /* queue_xmit */
+ family: AF_INET,
+ destructor: clip_neigh_destroy,
+ solicit: clip_neigh_solicit,
+ error_report: clip_neigh_error,
+ output: dev_queue_xmit,
+ connected_output: dev_queue_xmit,
+ hh_output: dev_queue_xmit,
+ queue_xmit: dev_queue_xmit,
};
@@ -384,6 +384,7 @@ static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
if (!skb->dst) {
printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n");
dev_kfree_skb(skb);
+ clip_priv->stats.tx_dropped++;
return 0;
}
if (!skb->dst->neighbour) {
@@ -395,8 +396,10 @@ static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
return 0;
}
#endif
-printk("clip_start_xmit: NO NEIGHBOUR !\n");
-return 0;
+ printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
+ dev_kfree_skb(skb);
+ clip_priv->stats.tx_dropped++;
+ return 0;
}
entry = NEIGH2ENTRY(skb->dst->neighbour);
if (!entry->vccs) {
@@ -440,7 +443,6 @@ return 0;
entry->vccs->xoff = 0;
return 0;
}
- if (old) return 0;
spin_lock_irqsave(&clip_priv->xoff_lock,flags);
netif_stop_queue(dev); /* XOFF -> throttle immediately */
barrier();
@@ -482,6 +484,7 @@ int clip_mkip(struct atm_vcc *vcc,int timeout)
clip_vcc->old_pop = vcc->pop;
vcc->push = clip_push;
vcc->pop = clip_pop;
+ skb_queue_head_init(&copy);
skb_migrate(&vcc->recvq,&copy);
/* re-process everything received between connection setup and MKIP */
while ((skb = skb_dequeue(&copy)))
@@ -622,7 +625,7 @@ static int clip_device_event(struct notifier_block *this,unsigned long event,
DPRINTK("clip_device_event NETDEV_UP\n");
(void) to_atmarpd(act_up,PRIV(dev)->number,0);
break;
- case NETDEV_DOWN:
+ case NETDEV_GOING_DOWN:
DPRINTK("clip_device_event NETDEV_DOWN\n");
(void) to_atmarpd(act_down,PRIV(dev)->number,0);
break;
@@ -633,6 +636,7 @@ static int clip_device_event(struct notifier_block *this,unsigned long event,
break;
case NETDEV_REBOOT:
case NETDEV_REGISTER:
+ case NETDEV_DOWN:
DPRINTK("clip_device_event %ld\n",event);
/* ignore */
break;
diff --git a/net/atm/common.c b/net/atm/common.c
index 867085ed8..16a6fb6b4 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -105,6 +105,7 @@ int atm_create(struct socket *sock,int protocol,int family)
vcc->callback = NULL;
memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
+ vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
atomic_set(&vcc->tx_inuse,0);
atomic_set(&vcc->rx_inuse,0);
vcc->push = NULL;
@@ -116,6 +117,7 @@ int atm_create(struct socket *sock,int protocol,int family)
init_waitqueue_head(&vcc->sleep);
skb_queue_head_init(&vcc->recvq);
skb_queue_head_init(&vcc->listenq);
+ sk->sleep = &vcc->sleep;
sock->sk = sk;
return 0;
}
@@ -409,6 +411,7 @@ int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len,
return vcc->reply;
if (!test_bit(ATM_VF_READY,&vcc->flags)) return -EPIPE;
if (!size) return 0;
+ if (size < 0 || size > vcc->qos.txtp.max_sdu) return -EMSGSIZE;
/* verify_area is done by net/socket.c */
eff = (size+3) & ~3; /* align to word boundary */
add_wait_queue(&vcc->sleep,&wait);
@@ -750,8 +753,10 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
}
-int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
+static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{
+ int error;
+
/*
* Don't let the QoS change the already connected AAL type nor the
* traffic class.
@@ -760,6 +765,9 @@ int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
return -EINVAL;
+ error = adjust_tp(&qos->txtp,qos->aal);
+ if (!error) error = adjust_tp(&qos->rxtp,qos->aal);
+ if (error) return error;
if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
if (vcc->family == AF_ATMPVC)
return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
diff --git a/net/atm/common.h b/net/atm/common.h
index faf1866ac..6330ca31c 100644
--- a/net/atm/common.h
+++ b/net/atm/common.h
@@ -26,7 +26,6 @@ int atm_getsockopt(struct socket *sock,int level,int optname,char *optval,
int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci);
void atm_release_vcc_sk(struct sock *sk,int free_sk);
-int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos);
void atm_shutdown_dev(struct atm_dev *dev);
int atm_proc_init(void);
diff --git a/net/atm/ipcommon.c b/net/atm/ipcommon.c
index d7c4a4d3a..707b74fb6 100644
--- a/net/atm/ipcommon.c
+++ b/net/atm/ipcommon.c
@@ -3,6 +3,7 @@
/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */
+#include <linux/module.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
@@ -31,7 +32,11 @@ const unsigned char llc_oui[] = {
/*
- * skb_migrate moves the list at FROM to TO, emptying FROM in the process.
+ * skb_migrate appends the list at "from" to "to", emptying "from" in the
+ * process. skb_migrate is atomic with respect to all other skb operations on
+ * "from" and "to". Note that it locks both lists at the same time, so beware
+ * of potential deadlocks.
+ *
* This function should live in skbuff.c or skbuff.h.
*/
@@ -40,18 +45,26 @@ void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to)
{
struct sk_buff *skb;
unsigned long flags;
+ struct sk_buff *skb_from = (struct sk_buff *) from;
+ struct sk_buff *skb_to = (struct sk_buff *) to;
+ struct sk_buff *prev;
spin_lock_irqsave(&from->lock,flags);
- *to = *from;
- from->prev = (struct sk_buff *) from;
- from->next = (struct sk_buff *) from;
+ spin_lock(&to->lock);
+ prev = from->prev;
+ from->next->prev = to->prev;
+ prev->next = skb_to;
+ to->prev->next = from->next;
+ to->prev = from->prev;
+ for (skb = from->next; skb != skb_to; skb = skb->next)
+ skb->list = to;
+ to->qlen += from->qlen;
+ spin_unlock(&to->lock);
+ from->prev = skb_from;
+ from->next = skb_from;
from->qlen = 0;
spin_unlock_irqrestore(&from->lock,flags);
- spin_lock_init(&to->lock);
- for (skb = ((struct sk_buff *) to)->next;
- skb != (struct sk_buff *) from; skb = skb->next) skb->list = to;
- if (to->next == (struct sk_buff *) from)
- to->next = (struct sk_buff *) to;
- to->next->prev = (struct sk_buff *) to;
- to->prev->next = (struct sk_buff *) to;
}
+
+
+EXPORT_SYMBOL(skb_migrate);
diff --git a/net/atm/ipcommon.h b/net/atm/ipcommon.h
index 30a5583b0..bc1675eca 100644
--- a/net/atm/ipcommon.h
+++ b/net/atm/ipcommon.h
@@ -16,8 +16,8 @@
extern struct net_device *clip_devs;
/*
- * Moves all skbs from "from" to "to". The operation is atomic for "from", but
- * not for "to". "to" may only be accessed after skb_migrate finishes.
+ * Appends all skbs from "from" to "to". The operation is atomic with respect
+ * to all other skb operations on "from" or "to".
*/
void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to);
diff --git a/net/atm/lec.c b/net/atm/lec.c
index f9b14dce5..d9921b408 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -332,23 +332,33 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
ATM_SKB(skb2)->vcc = send_vcc;
- atomic_add(skb2->truesize, &send_vcc->tx_inuse);
ATM_SKB(skb2)->iovcnt = 0;
ATM_SKB(skb2)->atm_options = send_vcc->atm_options;
DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name,
send_vcc->vpi, send_vcc->vci);
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb2->len;
- send_vcc->send(send_vcc, skb2);
+ if (atm_may_send(send_vcc, skb2->len)) {
+ atomic_add(skb2->truesize, &send_vcc->tx_inuse);
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb2->len;
+ send_vcc->send(send_vcc, skb2);
+ } else {
+ priv->stats.tx_dropped++;
+ dev_kfree_skb(skb2);
+ }
}
ATM_SKB(skb)->vcc = send_vcc;
- atomic_add(skb->truesize, &send_vcc->tx_inuse);
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = send_vcc->atm_options;
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
- send_vcc->send(send_vcc, skb);
+ if (atm_may_send(send_vcc, skb->len)) {
+ atomic_add(skb->truesize, &send_vcc->tx_inuse);
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ send_vcc->send(send_vcc, skb);
+ } else {
+ priv->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ }
#if 0
/* Should we wait for card's device driver to notify us? */
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index 1b3e13ad6..68cd8a034 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -239,7 +239,7 @@ void atm_mpoa_disp_qos(char *page, int *len)
while (qos != NULL) {
ip = (unsigned char *)&qos->ipaddr;
sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(ip));
- *len += sprintf(page + *len, "%%u.%u.%u.%u\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n",
+ *len += sprintf(page + *len, "%u.%u.%u.%u\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n",
NIPQUAD(ipaddr),
qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu,
qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu);
diff --git a/net/atm/proc.c b/net/atm/proc.c
index 79ab6e045..b2b186ac4 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -104,7 +104,7 @@ static int svc_addr(char *buf,struct sockaddr_atmsvc *addr)
strcpy(buf,addr->sas_addr.pub);
len = strlen(addr->sas_addr.pub);
buf += len;
- if (*addr->sas_addr.pub) {
+ if (*addr->sas_addr.prv) {
*buf++ = '+';
len++;
}
@@ -233,9 +233,10 @@ static void svc_info(struct atm_vcc *vcc,char *buf)
int i;
if (!vcc->dev)
- sprintf(buf,sizeof(void *) == 4 ? "N/A@%p%6s" : "N/A@%p%2s",
+ sprintf(buf,sizeof(void *) == 4 ? "N/A@%p%10s" : "N/A@%p%2s",
vcc,"");
- else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci);
+ else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
+ vcc->vci);
here = strchr(buf,0);
here += sprintf(here,"%-10s ",vcc_state(vcc));
here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub,
@@ -376,7 +377,7 @@ static int atm_svc_info(loff_t pos,char *buf)
int left;
if (!pos)
- return sprintf(buf,"Itf VPI VCI State Remote\n");
+ return sprintf(buf,"Itf VPI VCI State Remote\n");
left = pos-1;
for (dev = atm_devs; dev; dev = dev->next)
for (vcc = dev->vccs; vcc; vcc = vcc->next)
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
index 0240aa874..dc7998fd1 100644
--- a/net/atm/signaling.c
+++ b/net/atm/signaling.c
@@ -158,9 +158,9 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
}
-void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
+void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type,
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
- const struct sockaddr_atmsvc *svc)
+ const struct sockaddr_atmsvc *svc,const struct atm_qos *qos,int reply)
{
struct sk_buff *skb;
struct atmsvc_msg *msg;
@@ -173,21 +173,26 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
msg->type = type;
*(struct atm_vcc **) &msg->vcc = vcc;
*(struct atm_vcc **) &msg->listen_vcc = listen_vcc;
- msg->reply = 0; /* other ISP applications may use this field */
- if (vcc) {
- msg->qos = vcc->qos;
- msg->sap = vcc->sap;
- }
- if (!svc) msg->svc.sas_family = 0;
- else msg->svc = *svc;
+ msg->reply = reply;
+ if (qos) msg->qos = *qos;
+ if (vcc) msg->sap = vcc->sap;
+ if (svc) msg->svc = *svc;
if (vcc) msg->local = vcc->local;
- if (!pvc) memset(&msg->pvc,0,sizeof(msg->pvc));
- else msg->pvc = *pvc;
+ if (pvc) msg->pvc = *pvc;
sigd_put_skb(skb);
if (vcc) set_bit(ATM_VF_REGIS,&vcc->flags);
}
+void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
+ struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
+ const struct sockaddr_atmsvc *svc)
+{
+ sigd_enq2(vcc,type,listen_vcc,pvc,svc,vcc ? &vcc->qos : NULL,0);
+ /* other ISP applications may use "reply" */
+}
+
+
static void purge_vccs(struct atm_vcc *vcc)
{
while (vcc) {
diff --git a/net/atm/signaling.h b/net/atm/signaling.h
index 30d5d51d4..3b933ddb7 100644
--- a/net/atm/signaling.h
+++ b/net/atm/signaling.h
@@ -17,6 +17,14 @@
extern struct atm_vcc *sigd; /* needed in svc_release */
+/*
+ * sigd_enq is a wrapper for sigd_enq2, covering the more common cases, and
+ * avoiding huge lists of null values.
+ */
+
+void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type,
+ struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
+ const struct sockaddr_atmsvc *svc,const struct atm_qos *qos,int reply);
void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
const struct sockaddr_atmsvc *svc);
diff --git a/net/atm/svc.c b/net/atm/svc.c
index 70fa063cb..bffe7aac5 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -77,8 +77,7 @@ static void svc_disconnect(struct atm_vcc *vcc)
as_indicate has been answered */
while ((skb = skb_dequeue(&vcc->listenq))) {
DPRINTK("LISTEN REL\n");
- sigd_enq(NULL,as_reject,vcc,NULL,NULL); /* @@@ should include
- the reason */
+ sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
dev_kfree_skb(skb);
}
clear_bit(ATM_VF_REGIS,&vcc->flags);
@@ -310,8 +309,8 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
dev_kfree_skb(skb);
old_vcc->backlog_quota++;
if (error) {
- sigd_enq(NULL,as_reject,old_vcc,NULL,NULL);
- /* @@@ should include the reason */
+ sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
+ &old_vcc->qos,error);
return error == -EAGAIN ? -EBUSY : error;
}
/* wait should be short, so we ignore the non-blocking flag */
@@ -348,13 +347,9 @@ static int svc_getname(struct socket *sock,struct sockaddr *sockaddr,
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{
DECLARE_WAITQUEUE(wait,current);
- struct atm_qos save_qos;
vcc->reply = WAITING;
- save_qos = vcc->qos; /* @@@ really gross hack ... */
- vcc->qos = *qos;
- sigd_enq(vcc,as_modify,NULL,NULL,&vcc->local);
- vcc->qos = save_qos;
+ sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
add_wait_queue(&vcc->sleep,&wait);
while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
&& sigd) {