Commit 3ff0f2d6 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Start refcounting for per-ipppd data

We had introduced ipppd_get/put() earlier, so now add a real reference
count.
parent 713f2def
...@@ -29,16 +29,18 @@ struct ipppd { ...@@ -29,16 +29,18 @@ struct ipppd {
int unit; int unit;
int minor; int minor;
unsigned long debug; unsigned long debug;
atomic_t refcnt;
}; };
/* Prototypes */ /* 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, static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb, int proto); struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf); static int isdn_ppp_if_get_unit(char *namebuf);
static int isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *); static int isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *);
static void
ipppd_closewait(struct ipppd *ipppd);
static void static void
isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp, isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb,int proto); struct sk_buff *skb,int proto);
...@@ -85,15 +87,49 @@ char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; ...@@ -85,15 +87,49 @@ char *isdn_ppp_revision = "$Revision: 1.85.6.9 $";
static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED; static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED;
static struct ipppd *ipppds[NR_IPPPDS]; 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 * static inline struct ipppd *
ipppd_get(int slot) 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 static inline void
ipppd_put(struct ipppd *ipppd) 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) ...@@ -154,19 +190,11 @@ isdn_ppp_free(isdn_net_dev *idev)
// FIXME much of this wants to rather happen when disconnected() // 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); save_flags(flags);
cli(); cli();
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
spin_lock(&idev->pb->lock); spin_lock(&idev->pb->lock);
#endif
#ifdef CONFIG_ISDN_MPP
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
isdn_ppp_mp_cleanup(lp); isdn_ppp_mp_cleanup(lp);
...@@ -184,7 +212,8 @@ isdn_ppp_free(isdn_net_dev *idev) ...@@ -184,7 +212,8 @@ isdn_ppp_free(isdn_net_dev *idev)
return; return;
if (is->state & IPPP_CONNECT) 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) else if (is->state & IPPP_ASSIGNED)
is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
...@@ -320,16 +349,10 @@ isdn_ppp_wakeup_daemon(isdn_net_dev *idev) ...@@ -320,16 +349,10 @@ isdn_ppp_wakeup_daemon(isdn_net_dev *idev)
* go into 'device waits for release' state * go into 'device waits for release' state
*/ */
static void 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); wake_up(&ipppd->wq);
ipppd->state = IPPP_CLOSEWAIT; ipppd->state = IPPP_CLOSEWAIT;
ipppd_put(ipppd);
} }
/* /*
...@@ -370,6 +393,7 @@ ipppd_open(struct inode *ino, struct file *file) ...@@ -370,6 +393,7 @@ ipppd_open(struct inode *ino, struct file *file)
is = ipppds[slot]; is = ipppds[slot];
file->private_data = is; file->private_data = is;
__ipppd_get(is);
printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state); 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) ...@@ -377,9 +401,7 @@ ipppd_open(struct inode *ino, struct file *file)
is->unit = -1; /* set, when we have our interface */ is->unit = -1; /* set, when we have our interface */
init_waitqueue_head(&is->wq); init_waitqueue_head(&is->wq);
is->minor = minor; is->minor = minor;
isdn_lock_drivers();
return 0; return 0;
} }
...@@ -410,11 +432,8 @@ ipppd_release(struct inode *ino, struct file *file) ...@@ -410,11 +432,8 @@ ipppd_release(struct inode *ino, struct file *file)
} }
skb_queue_purge(&is->rq); skb_queue_purge(&is->rq);
/* this slot is ready for new connections */ ipppd_put(is);
is->state = 0;
isdn_unlock_drivers();
unlock_kernel(); unlock_kernel();
return 0; return 0;
} }
...@@ -665,21 +684,16 @@ ipppd_poll(struct file *file, poll_table * wait) ...@@ -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 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; struct sk_buff *skb;
unsigned char *p; unsigned char *p;
struct ipppd *is;
int retval; int retval;
is = ipppd_get(slot);
if (!is)
return -ENODEV;
if (!(is->state & IPPP_CONNECT)) { if (!(is->state & IPPP_CONNECT)) {
printk(KERN_DEBUG "ippp: device not activated.\n"); printk(KERN_DEBUG "ippp: device not activated.\n");
retval = -ENOTCONN; retval = -ENOTCONN;
...@@ -707,7 +721,6 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) ...@@ -707,7 +721,6 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
retval = len; retval = len;
out: out:
ipppd_put(is);
return retval; return retval;
} }
...@@ -1098,7 +1111,8 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -1098,7 +1111,8 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
} }
/* fall through */ /* fall through */
default: 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); kfree_skb(skb);
goto put; goto put;
} }
...@@ -1949,21 +1963,29 @@ isdn_ppp_hangup_slave(char *name) ...@@ -1949,21 +1963,29 @@ isdn_ppp_hangup_slave(char *name)
static void isdn_ppp_dev_kick_up(void *priv) static void isdn_ppp_dev_kick_up(void *priv)
{ {
isdn_net_dev *idev = 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) static void isdn_ppp_lp_kick_up(void *priv)
{ {
isdn_net_local *lp = priv; isdn_net_local *lp = priv;
isdn_net_dev *idev; isdn_net_dev *idev;
struct ipppd *ipppd;
if (list_empty(&lp->online)) { if (list_empty(&lp->online)) {
isdn_BUG(); isdn_BUG();
return; return;
} }
idev = list_entry(lp->online.next, isdn_net_dev, online); 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. */ /* 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, ...@@ -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) static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb)
{ {
struct ipppd *is;
int proto; int proto;
unsigned char *data; unsigned char *data;
...@@ -2078,11 +2099,6 @@ static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_ ...@@ -2078,11 +2099,6 @@ static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_
isdn_BUG(); isdn_BUG();
return; return;
} }
is = ipppd_get(idev->ppp_slot);
if (!is) {
isdn_BUG();
return;
}
/* Daemon may send with or without address and control field comp */ /* Daemon may send with or without address and control field comp */
data = skb->data; data = skb->data;
if (data[0] == 0xff && data[1] == 0x03) { if (data[0] == 0xff && data[1] == 0x03) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment