X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fppp_generic.c;h=3b377f6cd4a0bff915d75d46cef3d66eb16cbf20;hb=16cf0ec7408f389279d413869e94c1a351392f97;hp=ffd5ac3a848ee1f617e98eed2743fca8bf3ab656;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index ffd5ac3a8..3b377f6cd 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -19,7 +19,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20020217== + * ==FILEVERSION 20041108== */ #include @@ -129,8 +129,9 @@ struct ppp { #endif /* CONFIG_PPP_MULTILINK */ struct net_device_stats stats; /* statistics */ #ifdef CONFIG_PPP_FILTER - struct sock_fprog pass_filter; /* filter for packets to pass */ - struct sock_fprog active_filter;/* filter for pkts to reset idle */ + struct sock_filter *pass_filter; /* filter for packets to pass */ + struct sock_filter *active_filter;/* filter for pkts to reset idle */ + unsigned pass_len, active_len; #endif /* CONFIG_PPP_FILTER */ }; @@ -209,7 +210,7 @@ static atomic_t ppp_unit_count = ATOMIC_INIT(0); * and the atomicity of find a channel and updating its file.refcnt * field. */ -static spinlock_t all_channels_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(all_channels_lock); static LIST_HEAD(all_channels); static LIST_HEAD(new_channels); static int last_channel_index; @@ -370,7 +371,7 @@ static int ppp_release(struct inode *inode, struct file *file) struct ppp *ppp; if (pf != 0) { - file->private_data = 0; + file->private_data = NULL; if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); if (file == ppp->owner) @@ -396,7 +397,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf, struct ppp_file *pf = file->private_data; DECLARE_WAITQUEUE(wait, current); ssize_t ret; - struct sk_buff *skb = 0; + struct sk_buff *skb = NULL; ret = count; @@ -411,6 +412,17 @@ static ssize_t ppp_read(struct file *file, char __user *buf, ret = 0; if (pf->dead) break; + if (pf->kind == INTERFACE) { + /* + * Return 0 (EOF) on an interface that has no + * channels connected, unless it is looping + * network traffic (demand mode). + */ + struct ppp *ppp = PF_TO_PPP(pf); + if (ppp->n_channels == 0 + && (ppp->flags & SC_LOOP_TRAFFIC) == 0) + break; + } ret = -EAGAIN; if (file->f_flags & O_NONBLOCK) break; @@ -490,9 +502,56 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait) mask |= POLLIN | POLLRDNORM; if (pf->dead) mask |= POLLHUP; + else if (pf->kind == INTERFACE) { + /* see comment in ppp_read */ + struct ppp *ppp = PF_TO_PPP(pf); + if (ppp->n_channels == 0 + && (ppp->flags & SC_LOOP_TRAFFIC) == 0) + mask |= POLLIN | POLLRDNORM; + } + return mask; } +#ifdef CONFIG_PPP_FILTER +static int get_filter(void __user *arg, struct sock_filter **p) +{ + struct sock_fprog uprog; + struct sock_filter *code = NULL; + int len, err; + + if (copy_from_user(&uprog, arg, sizeof(uprog))) + return -EFAULT; + + if (uprog.len > BPF_MAXINSNS) + return -EINVAL; + + if (!uprog.len) { + *p = NULL; + return 0; + } + + len = uprog.len * sizeof(struct sock_filter); + code = kmalloc(len, GFP_KERNEL); + if (code == NULL) + return -ENOMEM; + + if (copy_from_user(code, uprog.filter, len)) { + kfree(code); + return -EFAULT; + } + + err = sk_chk_filter(code, uprog.len); + if (err) { + kfree(code); + return err; + } + + *p = code; + return uprog.len; +} +#endif /* CONFIG_PPP_FILTER */ + static int ppp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -503,6 +562,8 @@ static int ppp_ioctl(struct inode *inode, struct file *file, struct npioctl npi; int unit, cflags; struct slcompress *vj; + void __user *argp = (void __user *)arg; + int __user *p = argp; if (pf == 0) return ppp_unattached_ioctl(pf, file, cmd, arg); @@ -540,7 +601,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, switch (cmd) { case PPPIOCCONNECT: - if (get_user(unit, (int *) arg)) + if (get_user(unit, p)) break; err = ppp_connect_channel(pch, unit); break; @@ -569,14 +630,14 @@ static int ppp_ioctl(struct inode *inode, struct file *file, ppp = PF_TO_PPP(pf); switch (cmd) { case PPPIOCSMRU: - if (get_user(val, (int *) arg)) + if (get_user(val, p)) break; ppp->mru = val; err = 0; break; case PPPIOCSFLAGS: - if (get_user(val, (int *) arg)) + if (get_user(val, p)) break; ppp_lock(ppp); cflags = ppp->flags & ~val; @@ -589,7 +650,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, case PPPIOCGFLAGS: val = ppp->flags | ppp->xstate | ppp->rstate; - if (put_user(val, (int *) arg)) + if (put_user(val, p)) break; err = 0; break; @@ -599,20 +660,20 @@ static int ppp_ioctl(struct inode *inode, struct file *file, break; case PPPIOCGUNIT: - if (put_user(ppp->file.index, (int *) arg)) + if (put_user(ppp->file.index, p)) break; err = 0; break; case PPPIOCSDEBUG: - if (get_user(val, (int *) arg)) + if (get_user(val, p)) break; ppp->debug = val; err = 0; break; case PPPIOCGDEBUG: - if (put_user(ppp->debug, (int *) arg)) + if (put_user(ppp->debug, p)) break; err = 0; break; @@ -620,13 +681,13 @@ static int ppp_ioctl(struct inode *inode, struct file *file, case PPPIOCGIDLE: idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ; idle.recv_idle = (jiffies - ppp->last_recv) / HZ; - if (copy_to_user((void __user *) arg, &idle, sizeof(idle))) + if (copy_to_user(argp, &idle, sizeof(idle))) break; err = 0; break; case PPPIOCSMAXCID: - if (get_user(val, (int *) arg)) + if (get_user(val, p)) break; val2 = 15; if ((val >> 16) != 0) { @@ -649,7 +710,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, case PPPIOCGNPMODE: case PPPIOCSNPMODE: - if (copy_from_user(&npi, (void __user *) arg, sizeof(npi))) + if (copy_from_user(&npi, argp, sizeof(npi))) break; err = proto_to_npindex(npi.protocol); if (err < 0) @@ -658,7 +719,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, if (cmd == PPPIOCGNPMODE) { err = -EFAULT; npi.mode = ppp->npmode[i]; - if (copy_to_user((void __user *) arg, &npi, sizeof(npi))) + if (copy_to_user(argp, &npi, sizeof(npi))) break; } else { ppp->npmode[i] = npi.mode; @@ -670,49 +731,38 @@ static int ppp_ioctl(struct inode *inode, struct file *file, #ifdef CONFIG_PPP_FILTER case PPPIOCSPASS: + { + struct sock_filter *code; + err = get_filter(argp, &code); + if (err >= 0) { + ppp_lock(ppp); + kfree(ppp->pass_filter); + ppp->pass_filter = code; + ppp->pass_len = err; + ppp_unlock(ppp); + err = 0; + } + break; + } case PPPIOCSACTIVE: { - struct sock_fprog uprog, *filtp; - struct sock_filter *code = NULL; - int len; - - if (copy_from_user(&uprog, (void __user *) arg, sizeof(uprog))) - break; - err = -EINVAL; - if (uprog.len > BPF_MAXINSNS) - break; - err = -ENOMEM; - if (uprog.len > 0) { - len = uprog.len * sizeof(struct sock_filter); - code = kmalloc(len, GFP_KERNEL); - if (code == NULL) - break; - err = -EFAULT; - if (copy_from_user(code, (void __user *) uprog.filter, len)) { - kfree(code); - break; - } - err = sk_chk_filter(code, uprog.len); - if (err) { - kfree(code); - break; - } + struct sock_filter *code; + err = get_filter(argp, &code); + if (err >= 0) { + ppp_lock(ppp); + kfree(ppp->active_filter); + ppp->active_filter = code; + ppp->active_len = err; + ppp_unlock(ppp); + err = 0; } - filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter; - ppp_lock(ppp); - if (filtp->filter) - kfree(filtp->filter); - filtp->filter = code; - filtp->len = uprog.len; - ppp_unlock(ppp); - err = 0; break; } #endif /* CONFIG_PPP_FILTER */ #ifdef CONFIG_PPP_MULTILINK case PPPIOCSMRRU: - if (get_user(val, (int *) arg)) + if (get_user(val, p)) break; ppp_recv_lock(ppp); ppp->mrru = val; @@ -734,11 +784,12 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, int unit, err = -EFAULT; struct ppp *ppp; struct channel *chan; + int __user *p = (int __user *)arg; switch (cmd) { case PPPIOCNEWUNIT: /* Create a new ppp unit */ - if (get_user(unit, (int *) arg)) + if (get_user(unit, p)) break; ppp = ppp_create_interface(unit, &err); if (ppp == 0) @@ -746,14 +797,14 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, file->private_data = &ppp->file; ppp->owner = file; err = -EFAULT; - if (put_user(ppp->file.index, (int *) arg)) + if (put_user(ppp->file.index, p)) break; err = 0; break; case PPPIOCATTACH: /* Attach to an existing ppp unit */ - if (get_user(unit, (int *) arg)) + if (get_user(unit, p)) break; down(&all_ppp_sem); err = -ENXIO; @@ -767,7 +818,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, break; case PPPIOCATTCHAN: - if (get_user(unit, (int *) arg)) + if (get_user(unit, p)) break; spin_lock_bh(&all_channels_lock); err = -ENXIO; @@ -994,23 +1045,19 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) /* check if we should pass this packet */ /* the filter instructions are constructed assuming a four-byte PPP header on each packet */ - { - u_int16_t *p = (u_int16_t *) skb_push(skb, 2); - - *p = htons(4); /* indicate outbound in DLT_LINUX_SLL */; - } - if (ppp->pass_filter.filter - && sk_run_filter(skb, ppp->pass_filter.filter, - ppp->pass_filter.len) == 0) { + *skb_push(skb, 2) = 1; + if (ppp->pass_filter + && sk_run_filter(skb, ppp->pass_filter, + ppp->pass_len) == 0) { if (ppp->debug & 1) printk(KERN_DEBUG "PPP: outbound frame not passed\n"); kfree_skb(skb); return; } /* if this packet passes the active filter, record the time */ - if (!(ppp->active_filter.filter - && sk_run_filter(skb, ppp->active_filter.filter, - ppp->active_filter.len) == 0)) + if (!(ppp->active_filter + && sk_run_filter(skb, ppp->active_filter, + ppp->active_len) == 0)) ppp->last_xmit = jiffies; skb_pull(skb, 2); #else @@ -1129,7 +1176,7 @@ ppp_push(struct ppp *ppp) list = &ppp->channels; if (list_empty(list)) { /* nowhere to send the packet, just drop it */ - ppp->xmit_pending = 0; + ppp->xmit_pending = NULL; kfree_skb(skb); return; } @@ -1142,11 +1189,11 @@ ppp_push(struct ppp *ppp) spin_lock_bh(&pch->downl); if (pch->chan) { if (pch->chan->ops->start_xmit(pch->chan, skb)) - ppp->xmit_pending = 0; + ppp->xmit_pending = NULL; } else { /* channel got unregistered */ kfree_skb(skb); - ppp->xmit_pending = 0; + ppp->xmit_pending = NULL; } spin_unlock_bh(&pch->downl); return; @@ -1159,7 +1206,7 @@ ppp_push(struct ppp *ppp) return; #endif /* CONFIG_PPP_MULTILINK */ - ppp->xmit_pending = 0; + ppp->xmit_pending = NULL; kfree_skb(skb); } @@ -1541,22 +1588,18 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) /* check if the packet passes the pass and active filters */ /* the filter instructions are constructed assuming a four-byte PPP header on each packet */ - { - u_int16_t *p = (u_int16_t *) skb_push(skb, 2); - - *p = 0; /* indicate inbound in DLT_LINUX_SLL */ - } - if (ppp->pass_filter.filter - && sk_run_filter(skb, ppp->pass_filter.filter, - ppp->pass_filter.len) == 0) { + *skb_push(skb, 2) = 0; + if (ppp->pass_filter + && sk_run_filter(skb, ppp->pass_filter, + ppp->pass_len) == 0) { if (ppp->debug & 1) printk(KERN_DEBUG "PPP: inbound frame not passed\n"); kfree_skb(skb); return; } - if (!(ppp->active_filter.filter - && sk_run_filter(skb, ppp->active_filter.filter, - ppp->active_filter.len) == 0)) + if (!(ppp->active_filter + && sk_run_filter(skb, ppp->active_filter, + ppp->active_len) == 0)) ppp->last_recv = jiffies; skb_pull(skb, 2); #else @@ -1571,6 +1614,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb->mac.raw = skb->data; + skb->input_dev = ppp->dev; netif_rx(skb); ppp->dev->last_rx = jiffies; } @@ -1895,7 +1939,7 @@ ppp_register_channel(struct ppp_channel *chan) #endif /* CONFIG_PPP_MULTILINK */ init_rwsem(&pch->chan_sem); spin_lock_init(&pch->downl); - pch->upl = RW_LOCK_UNLOCKED; + rwlock_init(&pch->upl); spin_lock_bh(&all_channels_lock); pch->file.index = ++last_channel_index; list_add(&pch->list, &new_channels); @@ -1944,7 +1988,7 @@ ppp_unregister_channel(struct ppp_channel *chan) if (pch == 0) return; /* should never happen */ - chan->ppp = 0; + chan->ppp = NULL; /* * This ensures that we have returned from any calls into the @@ -1952,7 +1996,7 @@ ppp_unregister_channel(struct ppp_channel *chan) */ down_write(&pch->chan_sem); spin_lock_bh(&pch->downl); - pch->chan = 0; + pch->chan = NULL; spin_unlock_bh(&pch->downl); up_write(&pch->chan_sem); ppp_disconnect_channel(pch); @@ -2155,11 +2199,11 @@ ppp_ccp_closed(struct ppp *ppp) ppp->xstate = 0; xcomp = ppp->xcomp; xstate = ppp->xc_state; - ppp->xc_state = 0; + ppp->xc_state = NULL; ppp->rstate = 0; rcomp = ppp->rcomp; rstate = ppp->rc_state; - ppp->rc_state = 0; + ppp->rc_state = NULL; ppp_unlock(ppp); if (xstate) { @@ -2174,7 +2218,7 @@ ppp_ccp_closed(struct ppp *ppp) /* List of compressors. */ static LIST_HEAD(compressor_list); -static spinlock_t compressor_list_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(compressor_list_lock); struct compressor_entry { struct list_head list; @@ -2192,7 +2236,7 @@ find_comp_entry(int proto) if (ce->comp->compress_proto == proto) return ce; } - return 0; + return NULL; } /* Register a compressor */ @@ -2237,7 +2281,7 @@ static struct compressor * find_compressor(int type) { struct compressor_entry *ce; - struct compressor *cp = 0; + struct compressor *cp = NULL; spin_lock(&compressor_list_lock); ce = find_comp_entry(type); @@ -2381,7 +2425,7 @@ static void ppp_shutdown_interface(struct ppp *ppp) down(&all_ppp_sem); ppp_lock(ppp); dev = ppp->dev; - ppp->dev = 0; + ppp->dev = NULL; ppp_unlock(ppp); /* This will call dev_close() for us. */ if (dev) { @@ -2415,7 +2459,7 @@ static void ppp_destroy_interface(struct ppp *ppp) ppp_ccp_closed(ppp); if (ppp->vj) { slhc_free(ppp->vj); - ppp->vj = 0; + ppp->vj = NULL; } skb_queue_purge(&ppp->file.xq); skb_queue_purge(&ppp->file.rq); @@ -2423,14 +2467,10 @@ static void ppp_destroy_interface(struct ppp *ppp) skb_queue_purge(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ #ifdef CONFIG_PPP_FILTER - if (ppp->pass_filter.filter) { - kfree(ppp->pass_filter.filter); - ppp->pass_filter.filter = NULL; - } - if (ppp->active_filter.filter) { - kfree(ppp->active_filter.filter); - ppp->active_filter.filter = 0; - } + kfree(ppp->pass_filter); + ppp->pass_filter = NULL; + kfree(ppp->active_filter); + ppp->active_filter = NULL; #endif /* CONFIG_PPP_FILTER */ kfree(ppp); @@ -2475,7 +2515,7 @@ ppp_find_channel(int unit) if (pch->file.index == unit) return pch; } - return 0; + return NULL; } /* @@ -2534,7 +2574,8 @@ ppp_disconnect_channel(struct channel *pch) /* remove it from the ppp unit's list */ ppp_lock(ppp); list_del(&pch->clist); - --ppp->n_channels; + if (--ppp->n_channels == 0) + wake_up_interruptible(&ppp->file.rwait); ppp_unlock(ppp); if (atomic_dec_and_test(&ppp->file.refcnt)) ppp_destroy_interface(ppp); @@ -2696,8 +2737,6 @@ EXPORT_SYMBOL(ppp_input_error); EXPORT_SYMBOL(ppp_output_wakeup); EXPORT_SYMBOL(ppp_register_compressor); EXPORT_SYMBOL(ppp_unregister_compressor); -EXPORT_SYMBOL(all_ppp_units); /* for debugging */ -EXPORT_SYMBOL(all_channels); /* for debugging */ MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(PPP_MAJOR); MODULE_ALIAS("/dev/ppp");