summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2002-10-16 01:20:46 -0500
committerKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2002-10-16 01:20:46 -0500
commit3ff0f2d6649df7a3d76678bfe088eee96f43bc1b (patch)
treeed9c0f49df41a97d0750f986710cf6e308079a7d
parent713f2def8973f44bc8856f6a66f0646837828a70 (diff)
ISDN: Start refcounting for per-ipppd data
We had introduced ipppd_get/put() earlier, so now add a real reference count.
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c102
1 files changed, 59 insertions, 43 deletions
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index e78b2161ad54..d006767b508d 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -29,17 +29,19 @@ struct ipppd {
int unit;
int minor;
unsigned long debug;
+ atomic_t refcnt;
};
/* Prototypes */
-static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
-static void isdn_ppp_closewait(isdn_net_dev *idev);
static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf);
static int isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *);
static void
+ipppd_closewait(struct ipppd *ipppd);
+
+static void
isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb,int proto);
@@ -85,15 +87,49 @@ char *isdn_ppp_revision = "$Revision: 1.85.6.9 $";
static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED;
static struct ipppd *ipppds[NR_IPPPDS];
+static void
+ipppd_destroy(struct ipppd *ipppd)
+{
+ HERE;
+
+ ipppd->state = 0;
+}
+
+static inline struct ipppd *
+__ipppd_get(struct ipppd *ipppd)
+{
+ atomic_inc(&ipppd->refcnt);
+ printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt));
+ return ipppd;
+}
+
static inline struct ipppd *
ipppd_get(int slot)
{
- return ipppds[slot];
+ unsigned long flags;
+ struct ipppd *ipppd;
+
+ if (slot < 0 || slot >= NR_IPPPDS)
+ return NULL;
+
+ spin_lock_irqsave(&ipppds_lock, flags);
+ ipppd = ipppds[slot];
+ if (!ipppd)
+ goto out;
+
+ __ipppd_get(ipppd);
+ out:
+ spin_unlock_irqrestore(&ipppds_lock, flags);
+ return ipppd;
}
static inline void
ipppd_put(struct ipppd *ipppd)
{
+ printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt));
+
+ if (atomic_dec_and_test(&ipppd->refcnt))
+ ipppd_destroy(ipppd);
}
/*
@@ -154,19 +190,11 @@ isdn_ppp_free(isdn_net_dev *idev)
// FIXME much of this wants to rather happen when disconnected()
- if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __FUNCTION__ , idev->ppp_slot);
- return;
- }
-
save_flags(flags);
cli();
#ifdef CONFIG_ISDN_MPP
spin_lock(&idev->pb->lock);
-#endif
-#ifdef CONFIG_ISDN_MPP
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
isdn_ppp_mp_cleanup(lp);
@@ -184,7 +212,8 @@ isdn_ppp_free(isdn_net_dev *idev)
return;
if (is->state & IPPP_CONNECT)
- isdn_ppp_closewait(idev); /* force wakeup on ippp device */
+ ipppd_closewait(is); /* force wakeup on ippp device */
+
else if (is->state & IPPP_ASSIGNED)
is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
@@ -320,16 +349,10 @@ isdn_ppp_wakeup_daemon(isdn_net_dev *idev)
* go into 'device waits for release' state
*/
static void
-isdn_ppp_closewait(isdn_net_dev *idev)
+ipppd_closewait(struct ipppd *ipppd)
{
- struct ipppd *ipppd = ipppd_get(idev->ppp_slot);
-
- if (!ipppd)
- return;
-
wake_up(&ipppd->wq);
ipppd->state = IPPP_CLOSEWAIT;
- ipppd_put(ipppd);
}
/*
@@ -370,6 +393,7 @@ ipppd_open(struct inode *ino, struct file *file)
is = ipppds[slot];
file->private_data = is;
+ __ipppd_get(is);
printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
@@ -377,9 +401,7 @@ ipppd_open(struct inode *ino, struct file *file)
is->unit = -1; /* set, when we have our interface */
init_waitqueue_head(&is->wq);
is->minor = minor;
-
- isdn_lock_drivers();
-
+
return 0;
}
@@ -410,11 +432,8 @@ ipppd_release(struct inode *ino, struct file *file)
}
skb_queue_purge(&is->rq);
- /* this slot is ready for new connections */
- is->state = 0;
+ ipppd_put(is);
- isdn_unlock_drivers();
-
unlock_kernel();
return 0;
}
@@ -665,21 +684,16 @@ ipppd_poll(struct file *file, poll_table * wait)
}
/*
- * fill up isdn_ppp_read() queue ..
+ * Queue packets for ipppd to read().
*/
static int
-isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
+ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len)
{
struct sk_buff *skb;
unsigned char *p;
- struct ipppd *is;
int retval;
- is = ipppd_get(slot);
- if (!is)
- return -ENODEV;
-
if (!(is->state & IPPP_CONNECT)) {
printk(KERN_DEBUG "ippp: device not activated.\n");
retval = -ENOTCONN;
@@ -707,7 +721,6 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
retval = len;
out:
- ipppd_put(is);
return retval;
}
@@ -1098,7 +1111,8 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
}
/* fall through */
default:
- isdn_ppp_fill_rq(skb->data, skb->len, proto, idev->ppp_slot); /* push data to pppd device */
+ // FIXME use skb directly
+ ipppd_queue_read(is, proto, skb->data, skb->len);
kfree_skb(skb);
goto put;
}
@@ -1949,21 +1963,29 @@ isdn_ppp_hangup_slave(char *name)
static void isdn_ppp_dev_kick_up(void *priv)
{
isdn_net_dev *idev = priv;
+ struct ipppd *ipppd = ipppd_get(idev->ppp_slot);
+
+ if (!ipppd)
+ return;
- isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot);
+ ipppd_queue_read(ipppd, PPP_COMPFRAG, NULL, 0);
+ ipppd_put(ipppd);
}
static void isdn_ppp_lp_kick_up(void *priv)
{
isdn_net_local *lp = priv;
isdn_net_dev *idev;
+ struct ipppd *ipppd;
if (list_empty(&lp->online)) {
isdn_BUG();
return;
}
idev = list_entry(lp->online.next, isdn_net_dev, online);
- isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot);
+ ipppd = ipppd_get(idev->ppp_slot);
+ ipppd_queue_read(ipppd, PPP_COMP, NULL, 0);
+ ipppd_put(ipppd);
}
/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. */
@@ -2070,7 +2092,6 @@ isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp,
static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb)
{
- struct ipppd *is;
int proto;
unsigned char *data;
@@ -2078,11 +2099,6 @@ static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_
isdn_BUG();
return;
}
- is = ipppd_get(idev->ppp_slot);
- if (!is) {
- isdn_BUG();
- return;
- }
/* Daemon may send with or without address and control field comp */
data = skb->data;
if (data[0] == 0xff && data[1] == 0x03) {