patch-2.3.17 linux/drivers/net/ppp_generic.c
Next file: linux/drivers/net/sun3lance.c
Previous file: linux/drivers/net/ppp_async.c
Back to the patch index
Back to the overall index
- Lines: 276
- Date:
Thu Sep 2 09:25:17 1999
- Orig file:
v2.3.16/linux/drivers/net/ppp_generic.c
- Orig date:
Wed Aug 18 11:36:42 1999
diff -u --recursive --new-file v2.3.16/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
@@ -22,7 +22,7 @@
* ==FILEVERSION 990806==
*/
-/* $Id$ */
+/* $Id: ppp_generic.c,v 1.3 1999/09/02 05:30:12 paulus Exp $ */
#include <linux/config.h>
#include <linux/module.h>
@@ -94,7 +94,7 @@
void *rc_state; /* its internal state */
unsigned long last_xmit; /* jiffies when last pkt sent */
unsigned long last_recv; /* jiffies when last pkt rcvd */
- struct net_device dev; /* network interface device */
+ struct net_device *dev; /* network interface device */
struct net_device_stats stats; /* statistics */
};
@@ -144,6 +144,7 @@
static struct compressor *find_compressor(int type);
static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
static struct ppp *ppp_create_unit(int unit, int *retp);
+static void ppp_release_unit(struct ppp *ppp);
static struct ppp *ppp_find_unit(int unit);
/* Translates a PPP protocol number to a NP index (NP == network protocol) */
@@ -267,49 +268,11 @@
static int ppp_release(struct inode *inode, struct file *file)
{
struct ppp *ppp = (struct ppp *) file->private_data;
- struct list_head *list, *next;
- int ref;
-
- if (ppp == 0)
- goto out;
- file->private_data = 0;
- spin_lock(&all_ppp_lock);
- ref = --ppp->refcnt;
- if (ref == 0)
- list_del(&ppp->list);
- spin_unlock(&all_ppp_lock);
- if (ref != 0)
- goto out;
- /* Last fd open to this ppp unit is being closed -
- mark the interface down, free the ppp unit */
- rtnl_lock();
- dev_close(&ppp->dev);
- rtnl_unlock();
- for (list = ppp->channels.next; list != &ppp->channels; list = next) {
- /* forcibly detach this channel */
- struct channel *chan;
- chan = list_entry(list, struct channel, list);
- chan->chan->ppp = 0;
- next = list->next;
- kfree(chan);
+ if (ppp != 0) {
+ file->private_data = 0;
+ ppp_release_unit(ppp);
}
-
- /* Free up resources. */
- ppp_ccp_closed(ppp);
- lock_xmit_path(ppp);
- lock_recv_path(ppp);
- if (ppp->vj) {
- slhc_free(ppp->vj);
- ppp->vj = 0;
- }
- free_skbs(&ppp->xq);
- free_skbs(&ppp->rq);
- free_skbs(&ppp->recv_pending);
- unregister_netdev(&ppp->dev);
- kfree(ppp);
-
- out:
MOD_DEC_USE_COUNT;
return 0;
}
@@ -453,6 +416,12 @@
return -ENXIO;
err = -EFAULT;
switch (cmd) {
+ case PPPIOCDETACH:
+ file->private_data = 0;
+ ppp_release_unit(ppp);
+ err = 0;
+ break;
+
case PPPIOCSMRU:
if (get_user(val, (int *) arg))
break;
@@ -832,7 +801,7 @@
/* try to do packet compression */
if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
&& proto != PPP_LCP && proto != PPP_CCP) {
- new_skb = alloc_skb(ppp->dev.mtu + PPP_HDRLEN, GFP_ATOMIC);
+ new_skb = alloc_skb(ppp->dev->mtu + PPP_HDRLEN, GFP_ATOMIC);
if (new_skb == 0) {
printk(KERN_ERR "PPP: no memory (comp pkt)\n");
goto drop;
@@ -841,7 +810,7 @@
/* compressor still expects A/C bytes in hdr */
len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
new_skb->data, skb->len + 2,
- ppp->dev.mtu + PPP_HDRLEN);
+ ppp->dev->mtu + PPP_HDRLEN);
if (len > 0 && (ppp->flags & SC_CCP_UP)) {
kfree_skb(skb);
skb = new_skb;
@@ -853,6 +822,10 @@
}
}
+ /* for data packets, record the time */
+ if (proto < 0x8000)
+ ppp->last_xmit = jiffies;
+
/*
* If we are waiting for traffic (demand dialling),
* queue it up for pppd to receive.
@@ -994,7 +967,7 @@
goto err;
if (skb_tailroom(skb) < 124) {
/* copy to a new sk_buff with more tailroom */
- ns = alloc_skb(skb->len + 128, GFP_ATOMIC);
+ ns = dev_alloc_skb(skb->len + 128);
if (ns == 0) {
printk(KERN_ERR"PPP: no memory (VJ decomp)\n");
goto err;
@@ -1051,12 +1024,12 @@
} else {
/* network protocol frame - give it to the kernel */
ppp->last_recv = jiffies;
- if ((ppp->dev.flags & IFF_UP) == 0
+ if ((ppp->dev->flags & IFF_UP) == 0
|| ppp->npmode[npi] != NPMODE_PASS) {
kfree_skb(skb);
} else {
skb_pull(skb, 2); /* chop off protocol */
- skb->dev = &ppp->dev;
+ skb->dev = ppp->dev;
skb->protocol = htons(npindex_to_ethertype[npi]);
skb->mac.raw = skb->data;
netif_rx(skb);
@@ -1079,7 +1052,7 @@
int len;
if (proto == PPP_COMP) {
- ns = alloc_skb(ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
+ ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
if (ns == 0) {
printk(KERN_ERR "ppp_receive: no memory\n");
goto err;
@@ -1189,7 +1162,7 @@
if (trylock_xmit_path(ppp))
ppp_xmit_unlock(ppp);
if (ppp->xmit_pending == 0) {
- ppp->dev.tbusy = 0;
+ ppp->dev->tbusy = 0;
mark_bh(NET_BH);
}
}
@@ -1476,6 +1449,7 @@
ppp_create_unit(int unit, int *retp)
{
struct ppp *ppp;
+ struct net_device *dev;
struct list_head *list;
int last_unit = -1;
int ret = -EEXIST;
@@ -1501,6 +1475,12 @@
if (ppp == 0)
goto out;
memset(ppp, 0, sizeof(struct ppp));
+ dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+ if (dev == 0) {
+ kfree(ppp);
+ goto out;
+ }
+ memset(dev, 0, sizeof(struct net_device));
ppp->index = unit;
sprintf(ppp->name, "ppp%d", unit);
@@ -1514,13 +1494,18 @@
INIT_LIST_HEAD(&ppp->channels);
skb_queue_head_init(&ppp->recv_pending);
- ppp->dev.init = ppp_net_init;
- ppp->dev.name = ppp->name;
- ppp->dev.priv = ppp;
+ ppp->dev = dev;
+ dev->init = ppp_net_init;
+ dev->name = ppp->name;
+ dev->priv = ppp;
+ dev->new_style = 1;
- ret = register_netdev(&ppp->dev);
+ rtnl_lock();
+ ret = register_netdevice(dev);
+ rtnl_unlock();
if (ret != 0) {
printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret);
+ kfree(dev);
kfree(ppp);
goto out;
}
@@ -1535,6 +1520,59 @@
}
/*
+ * Remove a reference to a ppp unit, and destroy it if
+ * the reference count goes to 0.
+ */
+static void ppp_release_unit(struct ppp *ppp)
+{
+ struct list_head *list, *next;
+ int ref;
+
+ spin_lock(&all_ppp_lock);
+ ref = --ppp->refcnt;
+ if (ref == 0)
+ list_del(&ppp->list);
+ spin_unlock(&all_ppp_lock);
+ if (ref != 0)
+ return;
+
+ /* Last fd open to this ppp unit is being closed or detached:
+ mark the interface down, free the ppp unit */
+ if (ppp->dev) {
+ rtnl_lock();
+ dev_close(ppp->dev);
+ rtnl_unlock();
+ }
+ for (list = ppp->channels.next; list != &ppp->channels; list = next) {
+ /* forcibly detach this channel */
+ struct channel *chan;
+ chan = list_entry(list, struct channel, list);
+ chan->chan->ppp = 0;
+ next = list->next;
+ kfree(chan);
+ }
+
+ /* Free up resources. */
+ ppp_ccp_closed(ppp);
+ lock_xmit_path(ppp);
+ lock_recv_path(ppp);
+ if (ppp->vj) {
+ slhc_free(ppp->vj);
+ ppp->vj = 0;
+ }
+ free_skbs(&ppp->xq);
+ free_skbs(&ppp->rq);
+ free_skbs(&ppp->recv_pending);
+ if (ppp->dev) {
+ rtnl_lock();
+ unregister_netdevice(ppp->dev);
+ ppp->dev = 0;
+ rtnl_unlock();
+ }
+ kfree(ppp);
+}
+
+/*
* Locate an existing ppp unit.
* The caller should have locked the all_ppp_lock.
*/
@@ -1568,7 +1606,7 @@
cleanup_module(void)
{
/* should never happen */
- if (all_ppp_units.next != &all_ppp_units)
+ if (!list_empty(&all_ppp_units))
printk(KERN_ERR "PPP: removing module but units remain!\n");
if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
printk(KERN_ERR "PPP: failed to unregister PPP device\n");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)