Commit 65c9ec4d authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Use a skb queue instead of open coded solution in isdn_ppp.c

Apart from cleaning up and simplifying the code, this also gets rid of
some cli() and stuff, since skb_queue accesses are atomic via an internal
spinlock.
parent 828915fc
......@@ -314,8 +314,6 @@ isdn_ppp_open(struct inode *ino, struct file *file)
is->maxcid = 16; /* VJ: maxcid */
is->tk = current;
init_waitqueue_head(&is->wq);
is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
is->minor = minor;
#ifdef CONFIG_ISDN_PPP_VJ
/*
......@@ -337,7 +335,6 @@ static int
isdn_ppp_release(struct inode *ino, struct file *file)
{
uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
int i;
struct ippp_struct *is;
lock_kernel();
......@@ -356,14 +353,7 @@ isdn_ppp_release(struct inode *ino, struct file *file)
is->state &= ~IPPP_CONNECT;
isdn_net_hangup(is->idev);
}
for (i = 0; i < NUM_RCV_BUFFS; i++) {
if (is->rq[i].buf) {
kfree(is->rq[i].buf);
is->rq[i].buf = NULL;
}
}
is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
skb_queue_purge(&is->rq);
#ifdef CONFIG_ISDN_PPP_VJ
/* TODO: if this was the previous master: link the slcomp to the new master */
......@@ -595,12 +585,9 @@ static unsigned int
isdn_ppp_poll(struct file *file, poll_table * wait)
{
unsigned int mask;
struct ippp_buf_queue *bf;
struct ippp_buf_queue *bl;
unsigned long flags;
struct ippp_struct *is;
lock_kernel();
is = file->private_data;
if (is->debug & 0x2)
......@@ -622,21 +609,15 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
/* we're always ready to send .. */
mask = POLLOUT | POLLWRNORM;
save_flags(flags);
cli();
bl = is->last;
bf = is->first;
/*
* if IPPP_NOBLOCK is set we return even if we have nothing to read
*/
if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
if (!skb_queue_empty(&is->rq) || is->state & IPPP_NOBLOCK) {
is->state &= ~IPPP_NOBLOCK;
mask |= POLLIN | POLLRDNORM;
}
restore_flags(flags);
out:
unlock_kernel();
return mask;
}
......@@ -647,10 +628,8 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
static int
isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
{
struct ippp_buf_queue *bf,
*bl;
unsigned long flags;
unsigned char *nbuf;
struct sk_buff *skb;
unsigned char *p;
struct ippp_struct *is;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
......@@ -663,36 +642,23 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
printk(KERN_DEBUG "ippp: device not activated.\n");
return 0;
}
nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
if (!nbuf) {
printk(KERN_WARNING "ippp: Can't alloc buf\n");
if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) {
printk(KERN_WARNING "ippp: Queue is full\n");
return 0;
}
nbuf[0] = PPP_ALLSTATIONS;
nbuf[1] = PPP_UI;
nbuf[2] = proto >> 8;
nbuf[3] = proto & 0xff;
memcpy(nbuf + 4, buf, len);
save_flags(flags);
cli();
bf = is->first;
bl = is->last;
if (bf == bl) {
printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
bf = bf->next;
kfree(bf->buf);
is->first = bf;
skb = dev_alloc_skb(len + 4);
if (!skb) {
printk(KERN_WARNING "ippp: Can't alloc buf\n");
return 0;
}
bl->buf = (char *) nbuf;
bl->len = len + 4;
is->last = bl->next;
restore_flags(flags);
p = skb_put(skb, 4);
p += put_u8(p, PPP_ALLSTATIONS);
p += put_u8(p, PPP_UI);
p += put_u16(p, proto);
memcpy(skb_put(skb, len), buf, len);
wake_up_interruptible(&is->wq);
skb_queue_tail(&is->rq, skb);
wake_up_interruptible(&is->wq);
return len;
}
......@@ -706,54 +672,36 @@ static ssize_t
isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off)
{
struct ippp_struct *is;
struct ippp_buf_queue *b;
unsigned long flags;
unsigned char *save_buf;
struct sk_buff *skb;
int retval;
if (off != &file->f_pos)
return -ESPIPE;
lock_kernel();
is = file->private_data;
if (!(is->state & IPPP_OPEN)) {
retval = 0;
goto out;
}
retval = verify_area(VERIFY_WRITE, (void *) buf, count);
if (retval)
goto out;
save_flags(flags);
cli();
b = is->first->next;
save_buf = b->buf;
if (!save_buf) {
restore_flags(flags);
skb = skb_dequeue(&is->rq);
if (!skb) {
retval = -EAGAIN;
goto out;
}
if (b->len < count)
count = b->len;
b->buf = NULL;
is->first = b;
restore_flags(flags);
if (copy_to_user(buf, save_buf, count)) {
kfree(save_buf);
if (skb->len > count) {
retval = -EMSGSIZE;
goto out_free;
}
if (copy_to_user(buf, skb->data, skb->len)) {
retval = -EFAULT;
goto out;
goto out_free;
}
kfree(save_buf);
retval = count;
retval = skb->len;
out_free:
dev_kfree_skb(skb);
out:
unlock_kernel();
return retval;
}
......@@ -881,15 +829,7 @@ isdn_ppp_init(void)
}
memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
ippp_table[i]->state = 0;
ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
ippp_table[i]->last = ippp_table[i]->rq;
for (j = 0; j < NUM_RCV_BUFFS; j++) {
ippp_table[i]->rq[j].buf = NULL;
ippp_table[i]->rq[j].last = ippp_table[i]->rq +
(NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
}
skb_queue_head_init(&ippp_table[i]->rq);
}
return 0;
}
......
......@@ -159,14 +159,7 @@ typedef struct {
isdn_mppp_stats stats;
} ippp_bundle;
#define NUM_RCV_BUFFS 64
struct ippp_buf_queue {
struct ippp_buf_queue *next;
struct ippp_buf_queue *last;
char *buf; /* NULL here indicates end of queue */
int len;
};
#define IPPP_MAX_RQ_LEN 8
/* The data structure for one CCP reset transaction */
enum ippp_ccp_reset_states {
......@@ -201,9 +194,7 @@ struct ippp_ccp_reset {
struct ippp_struct {
struct ippp_struct *next_link;
int state;
struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
struct ippp_buf_queue *first; /* pointer to (current) first packet */
struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */
struct sk_buff_head rq;
wait_queue_head_t wq;
struct task_struct *tk;
unsigned int mpppcfg;
......
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