提交 273ec51d 编写于 作者: C Cyrill Gorcunov 提交者: David S. Miller

net: ppp_generic - introduce net-namespace functionality v2

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