Loading drivers/net/ppp_generic.c +198 −77 Original line number Diff line number Diff line Loading @@ -49,6 +49,10 @@ #include <net/slhc_vj.h> #include <asm/atomic.h> #include <linux/nsproxy.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #define PPP_VERSION "2.4.2" /* Loading Loading @@ -131,6 +135,7 @@ struct ppp { struct sock_filter *active_filter;/* filter for pkts to reset idle */ unsigned pass_len, active_len; #endif /* CONFIG_PPP_FILTER */ struct net *ppp_net; /* the net we belong to */ }; /* Loading @@ -155,6 +160,7 @@ struct channel { struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ spinlock_t downl; /* protects `chan', file.xq dequeue */ struct ppp *ppp; /* ppp unit we're connected to */ struct net *chan_net; /* the net channel belongs to */ struct list_head clist; /* link in list of channels per unit */ rwlock_t upl; /* protects `ppp' */ #ifdef CONFIG_PPP_MULTILINK Loading @@ -173,25 +179,34 @@ struct channel { * channel.downl. */ static atomic_t ppp_unit_count = ATOMIC_INIT(0); static atomic_t channel_count = ATOMIC_INIT(0); /* per-net private data for this module */ static unsigned int ppp_net_id; struct ppp_net { /* units to ppp mapping */ struct idr units_idr; /* * all_ppp_mutex protects the all_ppp_units mapping. * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. * all_ppp_mutex protects the units_idr mapping. * It also ensures that finding a ppp unit in the units_idr * map and updating its file.refcnt field is atomic. */ static DEFINE_MUTEX(all_ppp_mutex); static atomic_t ppp_unit_count = ATOMIC_INIT(0); static DEFINE_IDR(ppp_units_idr); struct mutex all_ppp_mutex; /* channels */ struct list_head all_channels; struct list_head new_channels; int last_channel_index; /* * all_channels_lock protects all_channels and last_channel_index, * and the atomicity of find a channel and updating its file.refcnt * field. * all_channels_lock protects all_channels and * last_channel_index, and the atomicity of find * a channel and updating its file.refcnt field. */ static DEFINE_SPINLOCK(all_channels_lock); static LIST_HEAD(all_channels); static LIST_HEAD(new_channels); static int last_channel_index; static atomic_t channel_count = ATOMIC_INIT(0); spinlock_t all_channels_lock; }; /* Get the PPP protocol number from a skb */ #define PPP_PROTO(skb) (((skb)->data[0] << 8) + (skb)->data[1]) Loading @@ -216,8 +231,8 @@ static atomic_t channel_count = ATOMIC_INIT(0); #define seq_after(a, b) ((s32)((a) - (b)) > 0) /* Prototypes. */ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); static void ppp_xmit_process(struct ppp *ppp); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); static void ppp_push(struct ppp *ppp); Loading @@ -240,12 +255,12 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); static void ppp_ccp_closed(struct ppp *ppp); static struct compressor *find_compressor(int type); static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); static struct ppp *ppp_create_interface(int unit, int *retp); static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp); static void init_ppp_file(struct ppp_file *pf, int kind); static void ppp_shutdown_interface(struct ppp *ppp); static void ppp_destroy_interface(struct ppp *ppp); static struct ppp *ppp_find_unit(int unit); static struct channel *ppp_find_channel(int unit); static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit); static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); static int ppp_connect_channel(struct channel *pch, int unit); static int ppp_disconnect_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch); Loading @@ -256,6 +271,14 @@ static void *unit_find(struct idr *p, int n); static struct class *ppp_class; /* per net-namespace data */ static inline struct ppp_net *ppp_pernet(struct net *net) { BUG_ON(!net); return net_generic(net, ppp_net_id); } /* Translates a PPP protocol number to a NP index (NP == network protocol) */ static inline int proto_to_npindex(int proto) { Loading Loading @@ -544,7 +567,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int __user *p = argp; if (!pf) return ppp_unattached_ioctl(pf, file, cmd, arg); return ppp_unattached_ioctl(current->nsproxy->net_ns, pf, file, cmd, arg); if (cmd == PPPIOCDETACH) { /* Loading Loading @@ -763,12 +787,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return err; } static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg) static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg) { int unit, err = -EFAULT; struct ppp *ppp; struct channel *chan; struct ppp_net *pn; int __user *p = (int __user *)arg; lock_kernel(); Loading @@ -777,7 +802,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, /* Create a new ppp unit */ if (get_user(unit, p)) break; ppp = ppp_create_interface(unit, &err); ppp = ppp_create_interface(net, unit, &err); if (!ppp) break; file->private_data = &ppp->file; Loading @@ -792,29 +817,31 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, /* Attach to an existing ppp unit */ if (get_user(unit, p)) break; mutex_lock(&all_ppp_mutex); err = -ENXIO; ppp = ppp_find_unit(unit); pn = ppp_pernet(net); mutex_lock(&pn->all_ppp_mutex); ppp = ppp_find_unit(pn, unit); if (ppp) { atomic_inc(&ppp->file.refcnt); file->private_data = &ppp->file; err = 0; } mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); break; case PPPIOCATTCHAN: if (get_user(unit, p)) break; spin_lock_bh(&all_channels_lock); err = -ENXIO; chan = ppp_find_channel(unit); pn = ppp_pernet(net); spin_lock_bh(&pn->all_channels_lock); chan = ppp_find_channel(pn, unit); if (chan) { atomic_inc(&chan->file.refcnt); file->private_data = &chan->file; err = 0; } spin_unlock_bh(&all_channels_lock); spin_unlock_bh(&pn->all_channels_lock); break; default: Loading @@ -834,6 +861,51 @@ static const struct file_operations ppp_device_fops = { .release = ppp_release }; static __net_init int ppp_init_net(struct net *net) { struct ppp_net *pn; int err; pn = kzalloc(sizeof(*pn), GFP_KERNEL); if (!pn) return -ENOMEM; idr_init(&pn->units_idr); mutex_init(&pn->all_ppp_mutex); INIT_LIST_HEAD(&pn->all_channels); INIT_LIST_HEAD(&pn->new_channels); spin_lock_init(&pn->all_channels_lock); err = net_assign_generic(net, ppp_net_id, pn); if (err) { kfree(pn); return err; } return 0; } static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn; pn = net_generic(net, ppp_net_id); idr_destroy(&pn->units_idr); /* * if someone has cached our net then * further net_generic call will return NULL */ net_assign_generic(net, ppp_net_id, NULL); kfree(pn); } static __net_initdata struct pernet_operations ppp_net_ops = { .init = ppp_init_net, .exit = ppp_exit_net, }; #define PPP_MAJOR 108 /* Called at boot time if ppp is compiled into the kernel, Loading @@ -843,25 +915,36 @@ static int __init ppp_init(void) int err; printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); err = register_pernet_gen_device(&ppp_net_id, &ppp_net_ops); if (err) { printk(KERN_ERR "failed to register PPP pernet device (%d)\n", err); goto out; } err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); if (!err) { if (err) { printk(KERN_ERR "failed to register PPP device (%d)\n", err); goto out_net; } ppp_class = class_create(THIS_MODULE, "ppp"); if (IS_ERR(ppp_class)) { err = PTR_ERR(ppp_class); goto out_chrdev; } device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); } out: if (err) printk(KERN_ERR "failed to register PPP device (%d)\n", err); return err; /* not a big deal if we fail here :-) */ device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); return 0; out_chrdev: unregister_chrdev(PPP_MAJOR, "ppp"); goto out; out_net: unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); out: return err; } /* Loading Loading @@ -969,6 +1052,7 @@ static void ppp_setup(struct net_device *dev) dev->tx_queue_len = 3; dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->features |= NETIF_F_NETNS_LOCAL; } /* Loading Loading @@ -1986,19 +2070,27 @@ ppp_mp_reconstruct(struct ppp *ppp) * Channel interface. */ /* * Create a new, unattached ppp channel. */ int ppp_register_channel(struct ppp_channel *chan) /* Create a new, unattached ppp channel. */ int ppp_register_channel(struct ppp_channel *chan) { return ppp_register_net_channel(current->nsproxy->net_ns, chan); } /* Create a new, unattached ppp channel for specified net. */ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan) { struct channel *pch; struct ppp_net *pn; pch = kzalloc(sizeof(struct channel), GFP_KERNEL); if (!pch) return -ENOMEM; pn = ppp_pernet(net); pch->ppp = NULL; pch->chan = chan; pch->chan_net = net; chan->ppp = pch; init_ppp_file(&pch->file, CHANNEL); pch->file.hdrlen = chan->hdrlen; Loading @@ -2008,11 +2100,13 @@ ppp_register_channel(struct ppp_channel *chan) init_rwsem(&pch->chan_sem); spin_lock_init(&pch->downl); rwlock_init(&pch->upl); spin_lock_bh(&all_channels_lock); pch->file.index = ++last_channel_index; list_add(&pch->list, &new_channels); spin_lock_bh(&pn->all_channels_lock); pch->file.index = ++pn->last_channel_index; list_add(&pch->list, &pn->new_channels); atomic_inc(&channel_count); spin_unlock_bh(&all_channels_lock); spin_unlock_bh(&pn->all_channels_lock); return 0; } Loading Loading @@ -2053,9 +2147,11 @@ void ppp_unregister_channel(struct ppp_channel *chan) { struct channel *pch = chan->ppp; struct ppp_net *pn; if (!pch) return; /* should never happen */ chan->ppp = NULL; /* Loading @@ -2068,9 +2164,12 @@ ppp_unregister_channel(struct ppp_channel *chan) spin_unlock_bh(&pch->downl); up_write(&pch->chan_sem); ppp_disconnect_channel(pch); spin_lock_bh(&all_channels_lock); pn = ppp_pernet(pch->chan_net); spin_lock_bh(&pn->all_channels_lock); list_del(&pch->list); spin_unlock_bh(&all_channels_lock); spin_unlock_bh(&pn->all_channels_lock); pch->file.dead = 1; wake_up_interruptible(&pch->file.rwait); if (atomic_dec_and_test(&pch->file.refcnt)) Loading Loading @@ -2395,9 +2494,10 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) * unit == -1 means allocate a new number. */ static struct ppp * ppp_create_interface(int unit, int *retp) ppp_create_interface(struct net *net, int unit, int *retp) { struct ppp *ppp; struct ppp_net *pn; struct net_device *dev = NULL; int ret = -ENOMEM; int i; Loading @@ -2406,6 +2506,8 @@ ppp_create_interface(int unit, int *retp) if (!dev) goto out1; pn = ppp_pernet(net); ppp = netdev_priv(dev); ppp->dev = dev; ppp->mru = PPP_MRU; Loading @@ -2421,17 +2523,23 @@ ppp_create_interface(int unit, int *retp) skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ /* * drum roll: don't forget to set * the net device is belong to */ dev_net_set(dev, net); ret = -EEXIST; mutex_lock(&all_ppp_mutex); mutex_lock(&pn->all_ppp_mutex); if (unit < 0) { unit = unit_get(&ppp_units_idr, ppp); unit = unit_get(&pn->units_idr, ppp); if (unit < 0) { *retp = unit; goto out2; } } else { if (unit_find(&ppp_units_idr, unit)) if (unit_find(&pn->units_idr, unit)) goto out2; /* unit already exists */ /* * if caller need a specified unit number Loading @@ -2442,7 +2550,7 @@ ppp_create_interface(int unit, int *retp) * fair but at least pppd will ask us to allocate * new unit in this case so user is happy :) */ unit = unit_set(&ppp_units_idr, ppp, unit); unit = unit_set(&pn->units_idr, ppp, unit); if (unit < 0) goto out2; } Loading @@ -2453,20 +2561,22 @@ ppp_create_interface(int unit, int *retp) ret = register_netdev(dev); if (ret != 0) { unit_put(&ppp_units_idr, unit); unit_put(&pn->units_idr, unit); printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); goto out2; } ppp->ppp_net = net; atomic_inc(&ppp_unit_count); mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); *retp = 0; return ppp; out2: mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); free_netdev(dev); out1: *retp = ret; Loading @@ -2492,7 +2602,11 @@ init_ppp_file(struct ppp_file *pf, int kind) */ static void ppp_shutdown_interface(struct ppp *ppp) { mutex_lock(&all_ppp_mutex); struct ppp_net *pn; pn = ppp_pernet(ppp->ppp_net); mutex_lock(&pn->all_ppp_mutex); /* This will call dev_close() for us. */ ppp_lock(ppp); if (!ppp->closing) { Loading @@ -2502,11 +2616,12 @@ static void ppp_shutdown_interface(struct ppp *ppp) } else ppp_unlock(ppp); unit_put(&ppp_units_idr, ppp->file.index); unit_put(&pn->units_idr, ppp->file.index); ppp->file.dead = 1; ppp->owner = NULL; wake_up_interruptible(&ppp->file.rwait); mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); } /* Loading Loading @@ -2554,9 +2669,9 @@ static void ppp_destroy_interface(struct ppp *ppp) * The caller should have locked the all_ppp_mutex. */ static struct ppp * ppp_find_unit(int unit) ppp_find_unit(struct ppp_net *pn, int unit) { return unit_find(&ppp_units_idr, unit); return unit_find(&pn->units_idr, unit); } /* Loading @@ -2568,20 +2683,22 @@ ppp_find_unit(int unit) * when we have a lot of channels in use. */ static struct channel * ppp_find_channel(int unit) ppp_find_channel(struct ppp_net *pn, int unit) { struct channel *pch; list_for_each_entry(pch, &new_channels, list) { list_for_each_entry(pch, &pn->new_channels, list) { if (pch->file.index == unit) { list_move(&pch->list, &all_channels); list_move(&pch->list, &pn->all_channels); return pch; } } list_for_each_entry(pch, &all_channels, list) { list_for_each_entry(pch, &pn->all_channels, list) { if (pch->file.index == unit) return pch; } return NULL; } Loading @@ -2592,11 +2709,14 @@ static int ppp_connect_channel(struct channel *pch, int unit) { struct ppp *ppp; struct ppp_net *pn; int ret = -ENXIO; int hdrlen; mutex_lock(&all_ppp_mutex); ppp = ppp_find_unit(unit); pn = ppp_pernet(pch->chan_net); mutex_lock(&pn->all_ppp_mutex); ppp = ppp_find_unit(pn, unit); if (!ppp) goto out; write_lock_bh(&pch->upl); Loading @@ -2620,7 +2740,7 @@ ppp_connect_channel(struct channel *pch, int unit) outl: write_unlock_bh(&pch->upl); out: mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); return ret; } Loading Loading @@ -2677,7 +2797,7 @@ static void __exit ppp_cleanup(void) unregister_chrdev(PPP_MAJOR, "ppp"); device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); idr_destroy(&ppp_units_idr); unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); } /* Loading Loading @@ -2743,6 +2863,7 @@ static void *unit_find(struct idr *p, int n) module_init(ppp_init); module_exit(ppp_cleanup); EXPORT_SYMBOL(ppp_register_net_channel); EXPORT_SYMBOL(ppp_register_channel); EXPORT_SYMBOL(ppp_unregister_channel); EXPORT_SYMBOL(ppp_channel_index); Loading include/linux/ppp_channel.h +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <linux/list.h> #include <linux/skbuff.h> #include <linux/poll.h> #include <net/net_namespace.h> struct ppp_channel; Loading Loading @@ -56,6 +57,9 @@ extern void ppp_input(struct ppp_channel *, struct sk_buff *); that we may have missed a packet. */ extern void ppp_input_error(struct ppp_channel *, int code); /* Attach a channel to a given PPP unit in specified net. */ extern int ppp_register_net_channel(struct net *, struct ppp_channel *); /* Attach a channel to a given PPP unit. */ extern int ppp_register_channel(struct ppp_channel *); Loading Loading
drivers/net/ppp_generic.c +198 −77 Original line number Diff line number Diff line Loading @@ -49,6 +49,10 @@ #include <net/slhc_vj.h> #include <asm/atomic.h> #include <linux/nsproxy.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #define PPP_VERSION "2.4.2" /* Loading Loading @@ -131,6 +135,7 @@ struct ppp { struct sock_filter *active_filter;/* filter for pkts to reset idle */ unsigned pass_len, active_len; #endif /* CONFIG_PPP_FILTER */ struct net *ppp_net; /* the net we belong to */ }; /* Loading @@ -155,6 +160,7 @@ struct channel { struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ spinlock_t downl; /* protects `chan', file.xq dequeue */ struct ppp *ppp; /* ppp unit we're connected to */ struct net *chan_net; /* the net channel belongs to */ struct list_head clist; /* link in list of channels per unit */ rwlock_t upl; /* protects `ppp' */ #ifdef CONFIG_PPP_MULTILINK Loading @@ -173,25 +179,34 @@ struct channel { * channel.downl. */ static atomic_t ppp_unit_count = ATOMIC_INIT(0); static atomic_t channel_count = ATOMIC_INIT(0); /* per-net private data for this module */ static unsigned int ppp_net_id; struct ppp_net { /* units to ppp mapping */ struct idr units_idr; /* * all_ppp_mutex protects the all_ppp_units mapping. * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. * all_ppp_mutex protects the units_idr mapping. * It also ensures that finding a ppp unit in the units_idr * map and updating its file.refcnt field is atomic. */ static DEFINE_MUTEX(all_ppp_mutex); static atomic_t ppp_unit_count = ATOMIC_INIT(0); static DEFINE_IDR(ppp_units_idr); struct mutex all_ppp_mutex; /* channels */ struct list_head all_channels; struct list_head new_channels; int last_channel_index; /* * all_channels_lock protects all_channels and last_channel_index, * and the atomicity of find a channel and updating its file.refcnt * field. * all_channels_lock protects all_channels and * last_channel_index, and the atomicity of find * a channel and updating its file.refcnt field. */ static DEFINE_SPINLOCK(all_channels_lock); static LIST_HEAD(all_channels); static LIST_HEAD(new_channels); static int last_channel_index; static atomic_t channel_count = ATOMIC_INIT(0); spinlock_t all_channels_lock; }; /* Get the PPP protocol number from a skb */ #define PPP_PROTO(skb) (((skb)->data[0] << 8) + (skb)->data[1]) Loading @@ -216,8 +231,8 @@ static atomic_t channel_count = ATOMIC_INIT(0); #define seq_after(a, b) ((s32)((a) - (b)) > 0) /* Prototypes. */ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); static void ppp_xmit_process(struct ppp *ppp); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); static void ppp_push(struct ppp *ppp); Loading @@ -240,12 +255,12 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); static void ppp_ccp_closed(struct ppp *ppp); static struct compressor *find_compressor(int type); static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); static struct ppp *ppp_create_interface(int unit, int *retp); static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp); static void init_ppp_file(struct ppp_file *pf, int kind); static void ppp_shutdown_interface(struct ppp *ppp); static void ppp_destroy_interface(struct ppp *ppp); static struct ppp *ppp_find_unit(int unit); static struct channel *ppp_find_channel(int unit); static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit); static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); static int ppp_connect_channel(struct channel *pch, int unit); static int ppp_disconnect_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch); Loading @@ -256,6 +271,14 @@ static void *unit_find(struct idr *p, int n); static struct class *ppp_class; /* per net-namespace data */ static inline struct ppp_net *ppp_pernet(struct net *net) { BUG_ON(!net); return net_generic(net, ppp_net_id); } /* Translates a PPP protocol number to a NP index (NP == network protocol) */ static inline int proto_to_npindex(int proto) { Loading Loading @@ -544,7 +567,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) int __user *p = argp; if (!pf) return ppp_unattached_ioctl(pf, file, cmd, arg); return ppp_unattached_ioctl(current->nsproxy->net_ns, pf, file, cmd, arg); if (cmd == PPPIOCDETACH) { /* Loading Loading @@ -763,12 +787,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return err; } static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg) static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg) { int unit, err = -EFAULT; struct ppp *ppp; struct channel *chan; struct ppp_net *pn; int __user *p = (int __user *)arg; lock_kernel(); Loading @@ -777,7 +802,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, /* Create a new ppp unit */ if (get_user(unit, p)) break; ppp = ppp_create_interface(unit, &err); ppp = ppp_create_interface(net, unit, &err); if (!ppp) break; file->private_data = &ppp->file; Loading @@ -792,29 +817,31 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, /* Attach to an existing ppp unit */ if (get_user(unit, p)) break; mutex_lock(&all_ppp_mutex); err = -ENXIO; ppp = ppp_find_unit(unit); pn = ppp_pernet(net); mutex_lock(&pn->all_ppp_mutex); ppp = ppp_find_unit(pn, unit); if (ppp) { atomic_inc(&ppp->file.refcnt); file->private_data = &ppp->file; err = 0; } mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); break; case PPPIOCATTCHAN: if (get_user(unit, p)) break; spin_lock_bh(&all_channels_lock); err = -ENXIO; chan = ppp_find_channel(unit); pn = ppp_pernet(net); spin_lock_bh(&pn->all_channels_lock); chan = ppp_find_channel(pn, unit); if (chan) { atomic_inc(&chan->file.refcnt); file->private_data = &chan->file; err = 0; } spin_unlock_bh(&all_channels_lock); spin_unlock_bh(&pn->all_channels_lock); break; default: Loading @@ -834,6 +861,51 @@ static const struct file_operations ppp_device_fops = { .release = ppp_release }; static __net_init int ppp_init_net(struct net *net) { struct ppp_net *pn; int err; pn = kzalloc(sizeof(*pn), GFP_KERNEL); if (!pn) return -ENOMEM; idr_init(&pn->units_idr); mutex_init(&pn->all_ppp_mutex); INIT_LIST_HEAD(&pn->all_channels); INIT_LIST_HEAD(&pn->new_channels); spin_lock_init(&pn->all_channels_lock); err = net_assign_generic(net, ppp_net_id, pn); if (err) { kfree(pn); return err; } return 0; } static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn; pn = net_generic(net, ppp_net_id); idr_destroy(&pn->units_idr); /* * if someone has cached our net then * further net_generic call will return NULL */ net_assign_generic(net, ppp_net_id, NULL); kfree(pn); } static __net_initdata struct pernet_operations ppp_net_ops = { .init = ppp_init_net, .exit = ppp_exit_net, }; #define PPP_MAJOR 108 /* Called at boot time if ppp is compiled into the kernel, Loading @@ -843,25 +915,36 @@ static int __init ppp_init(void) int err; printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); err = register_pernet_gen_device(&ppp_net_id, &ppp_net_ops); if (err) { printk(KERN_ERR "failed to register PPP pernet device (%d)\n", err); goto out; } err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); if (!err) { if (err) { printk(KERN_ERR "failed to register PPP device (%d)\n", err); goto out_net; } ppp_class = class_create(THIS_MODULE, "ppp"); if (IS_ERR(ppp_class)) { err = PTR_ERR(ppp_class); goto out_chrdev; } device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); } out: if (err) printk(KERN_ERR "failed to register PPP device (%d)\n", err); return err; /* not a big deal if we fail here :-) */ device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); return 0; out_chrdev: unregister_chrdev(PPP_MAJOR, "ppp"); goto out; out_net: unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); out: return err; } /* Loading Loading @@ -969,6 +1052,7 @@ static void ppp_setup(struct net_device *dev) dev->tx_queue_len = 3; dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->features |= NETIF_F_NETNS_LOCAL; } /* Loading Loading @@ -1986,19 +2070,27 @@ ppp_mp_reconstruct(struct ppp *ppp) * Channel interface. */ /* * Create a new, unattached ppp channel. */ int ppp_register_channel(struct ppp_channel *chan) /* Create a new, unattached ppp channel. */ int ppp_register_channel(struct ppp_channel *chan) { return ppp_register_net_channel(current->nsproxy->net_ns, chan); } /* Create a new, unattached ppp channel for specified net. */ int ppp_register_net_channel(struct net *net, struct ppp_channel *chan) { struct channel *pch; struct ppp_net *pn; pch = kzalloc(sizeof(struct channel), GFP_KERNEL); if (!pch) return -ENOMEM; pn = ppp_pernet(net); pch->ppp = NULL; pch->chan = chan; pch->chan_net = net; chan->ppp = pch; init_ppp_file(&pch->file, CHANNEL); pch->file.hdrlen = chan->hdrlen; Loading @@ -2008,11 +2100,13 @@ ppp_register_channel(struct ppp_channel *chan) init_rwsem(&pch->chan_sem); spin_lock_init(&pch->downl); rwlock_init(&pch->upl); spin_lock_bh(&all_channels_lock); pch->file.index = ++last_channel_index; list_add(&pch->list, &new_channels); spin_lock_bh(&pn->all_channels_lock); pch->file.index = ++pn->last_channel_index; list_add(&pch->list, &pn->new_channels); atomic_inc(&channel_count); spin_unlock_bh(&all_channels_lock); spin_unlock_bh(&pn->all_channels_lock); return 0; } Loading Loading @@ -2053,9 +2147,11 @@ void ppp_unregister_channel(struct ppp_channel *chan) { struct channel *pch = chan->ppp; struct ppp_net *pn; if (!pch) return; /* should never happen */ chan->ppp = NULL; /* Loading @@ -2068,9 +2164,12 @@ ppp_unregister_channel(struct ppp_channel *chan) spin_unlock_bh(&pch->downl); up_write(&pch->chan_sem); ppp_disconnect_channel(pch); spin_lock_bh(&all_channels_lock); pn = ppp_pernet(pch->chan_net); spin_lock_bh(&pn->all_channels_lock); list_del(&pch->list); spin_unlock_bh(&all_channels_lock); spin_unlock_bh(&pn->all_channels_lock); pch->file.dead = 1; wake_up_interruptible(&pch->file.rwait); if (atomic_dec_and_test(&pch->file.refcnt)) Loading Loading @@ -2395,9 +2494,10 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) * unit == -1 means allocate a new number. */ static struct ppp * ppp_create_interface(int unit, int *retp) ppp_create_interface(struct net *net, int unit, int *retp) { struct ppp *ppp; struct ppp_net *pn; struct net_device *dev = NULL; int ret = -ENOMEM; int i; Loading @@ -2406,6 +2506,8 @@ ppp_create_interface(int unit, int *retp) if (!dev) goto out1; pn = ppp_pernet(net); ppp = netdev_priv(dev); ppp->dev = dev; ppp->mru = PPP_MRU; Loading @@ -2421,17 +2523,23 @@ ppp_create_interface(int unit, int *retp) skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ /* * drum roll: don't forget to set * the net device is belong to */ dev_net_set(dev, net); ret = -EEXIST; mutex_lock(&all_ppp_mutex); mutex_lock(&pn->all_ppp_mutex); if (unit < 0) { unit = unit_get(&ppp_units_idr, ppp); unit = unit_get(&pn->units_idr, ppp); if (unit < 0) { *retp = unit; goto out2; } } else { if (unit_find(&ppp_units_idr, unit)) if (unit_find(&pn->units_idr, unit)) goto out2; /* unit already exists */ /* * if caller need a specified unit number Loading @@ -2442,7 +2550,7 @@ ppp_create_interface(int unit, int *retp) * fair but at least pppd will ask us to allocate * new unit in this case so user is happy :) */ unit = unit_set(&ppp_units_idr, ppp, unit); unit = unit_set(&pn->units_idr, ppp, unit); if (unit < 0) goto out2; } Loading @@ -2453,20 +2561,22 @@ ppp_create_interface(int unit, int *retp) ret = register_netdev(dev); if (ret != 0) { unit_put(&ppp_units_idr, unit); unit_put(&pn->units_idr, unit); printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); goto out2; } ppp->ppp_net = net; atomic_inc(&ppp_unit_count); mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); *retp = 0; return ppp; out2: mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); free_netdev(dev); out1: *retp = ret; Loading @@ -2492,7 +2602,11 @@ init_ppp_file(struct ppp_file *pf, int kind) */ static void ppp_shutdown_interface(struct ppp *ppp) { mutex_lock(&all_ppp_mutex); struct ppp_net *pn; pn = ppp_pernet(ppp->ppp_net); mutex_lock(&pn->all_ppp_mutex); /* This will call dev_close() for us. */ ppp_lock(ppp); if (!ppp->closing) { Loading @@ -2502,11 +2616,12 @@ static void ppp_shutdown_interface(struct ppp *ppp) } else ppp_unlock(ppp); unit_put(&ppp_units_idr, ppp->file.index); unit_put(&pn->units_idr, ppp->file.index); ppp->file.dead = 1; ppp->owner = NULL; wake_up_interruptible(&ppp->file.rwait); mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); } /* Loading Loading @@ -2554,9 +2669,9 @@ static void ppp_destroy_interface(struct ppp *ppp) * The caller should have locked the all_ppp_mutex. */ static struct ppp * ppp_find_unit(int unit) ppp_find_unit(struct ppp_net *pn, int unit) { return unit_find(&ppp_units_idr, unit); return unit_find(&pn->units_idr, unit); } /* Loading @@ -2568,20 +2683,22 @@ ppp_find_unit(int unit) * when we have a lot of channels in use. */ static struct channel * ppp_find_channel(int unit) ppp_find_channel(struct ppp_net *pn, int unit) { struct channel *pch; list_for_each_entry(pch, &new_channels, list) { list_for_each_entry(pch, &pn->new_channels, list) { if (pch->file.index == unit) { list_move(&pch->list, &all_channels); list_move(&pch->list, &pn->all_channels); return pch; } } list_for_each_entry(pch, &all_channels, list) { list_for_each_entry(pch, &pn->all_channels, list) { if (pch->file.index == unit) return pch; } return NULL; } Loading @@ -2592,11 +2709,14 @@ static int ppp_connect_channel(struct channel *pch, int unit) { struct ppp *ppp; struct ppp_net *pn; int ret = -ENXIO; int hdrlen; mutex_lock(&all_ppp_mutex); ppp = ppp_find_unit(unit); pn = ppp_pernet(pch->chan_net); mutex_lock(&pn->all_ppp_mutex); ppp = ppp_find_unit(pn, unit); if (!ppp) goto out; write_lock_bh(&pch->upl); Loading @@ -2620,7 +2740,7 @@ ppp_connect_channel(struct channel *pch, int unit) outl: write_unlock_bh(&pch->upl); out: mutex_unlock(&all_ppp_mutex); mutex_unlock(&pn->all_ppp_mutex); return ret; } Loading Loading @@ -2677,7 +2797,7 @@ static void __exit ppp_cleanup(void) unregister_chrdev(PPP_MAJOR, "ppp"); device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); idr_destroy(&ppp_units_idr); unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); } /* Loading Loading @@ -2743,6 +2863,7 @@ static void *unit_find(struct idr *p, int n) module_init(ppp_init); module_exit(ppp_cleanup); EXPORT_SYMBOL(ppp_register_net_channel); EXPORT_SYMBOL(ppp_register_channel); EXPORT_SYMBOL(ppp_unregister_channel); EXPORT_SYMBOL(ppp_channel_index); Loading
include/linux/ppp_channel.h +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include <linux/list.h> #include <linux/skbuff.h> #include <linux/poll.h> #include <net/net_namespace.h> struct ppp_channel; Loading Loading @@ -56,6 +57,9 @@ extern void ppp_input(struct ppp_channel *, struct sk_buff *); that we may have missed a packet. */ extern void ppp_input_error(struct ppp_channel *, int code); /* Attach a channel to a given PPP unit in specified net. */ extern int ppp_register_net_channel(struct net *, struct ppp_channel *); /* Attach a channel to a given PPP unit. */ extern int ppp_register_channel(struct ppp_channel *); Loading