|
@@ -269,9 +269,9 @@ 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(struct net *net, int unit, int *retp);
|
|
|
+static struct ppp *ppp_create_interface(struct net *net, int unit,
|
|
|
+ struct file *file, 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(struct ppp_net *pn, int unit);
|
|
|
static struct channel *ppp_find_channel(struct ppp_net *pn, int unit);
|
|
@@ -392,8 +392,10 @@ static int ppp_release(struct inode *unused, struct file *file)
|
|
|
file->private_data = NULL;
|
|
|
if (pf->kind == INTERFACE) {
|
|
|
ppp = PF_TO_PPP(pf);
|
|
|
+ rtnl_lock();
|
|
|
if (file == ppp->owner)
|
|
|
- ppp_shutdown_interface(ppp);
|
|
|
+ unregister_netdevice(ppp->dev);
|
|
|
+ rtnl_unlock();
|
|
|
}
|
|
|
if (atomic_dec_and_test(&pf->refcnt)) {
|
|
|
switch (pf->kind) {
|
|
@@ -593,8 +595,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
mutex_lock(&ppp_mutex);
|
|
|
if (pf->kind == INTERFACE) {
|
|
|
ppp = PF_TO_PPP(pf);
|
|
|
+ rtnl_lock();
|
|
|
if (file == ppp->owner)
|
|
|
- ppp_shutdown_interface(ppp);
|
|
|
+ unregister_netdevice(ppp->dev);
|
|
|
+ rtnl_unlock();
|
|
|
}
|
|
|
if (atomic_long_read(&file->f_count) < 2) {
|
|
|
ppp_release(NULL, file);
|
|
@@ -838,11 +842,10 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
|
|
|
/* Create a new ppp unit */
|
|
|
if (get_user(unit, p))
|
|
|
break;
|
|
|
- ppp = ppp_create_interface(net, unit, &err);
|
|
|
+ ppp = ppp_create_interface(net, unit, file, &err);
|
|
|
if (!ppp)
|
|
|
break;
|
|
|
file->private_data = &ppp->file;
|
|
|
- ppp->owner = file;
|
|
|
err = -EFAULT;
|
|
|
if (put_user(ppp->file.index, p))
|
|
|
break;
|
|
@@ -916,6 +919,16 @@ static __net_init int ppp_init_net(struct net *net)
|
|
|
static __net_exit void ppp_exit_net(struct net *net)
|
|
|
{
|
|
|
struct ppp_net *pn = net_generic(net, ppp_net_id);
|
|
|
+ struct ppp *ppp;
|
|
|
+ LIST_HEAD(list);
|
|
|
+ int id;
|
|
|
+
|
|
|
+ rtnl_lock();
|
|
|
+ idr_for_each_entry(&pn->units_idr, ppp, id)
|
|
|
+ unregister_netdevice_queue(ppp->dev, &list);
|
|
|
+
|
|
|
+ unregister_netdevice_many(&list);
|
|
|
+ rtnl_unlock();
|
|
|
|
|
|
idr_destroy(&pn->units_idr);
|
|
|
}
|
|
@@ -1088,8 +1101,28 @@ static int ppp_dev_init(struct net_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void ppp_dev_uninit(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct ppp *ppp = netdev_priv(dev);
|
|
|
+ struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
|
|
|
+
|
|
|
+ ppp_lock(ppp);
|
|
|
+ ppp->closing = 1;
|
|
|
+ ppp_unlock(ppp);
|
|
|
+
|
|
|
+ mutex_lock(&pn->all_ppp_mutex);
|
|
|
+ unit_put(&pn->units_idr, ppp->file.index);
|
|
|
+ mutex_unlock(&pn->all_ppp_mutex);
|
|
|
+
|
|
|
+ ppp->owner = NULL;
|
|
|
+
|
|
|
+ ppp->file.dead = 1;
|
|
|
+ wake_up_interruptible(&ppp->file.rwait);
|
|
|
+}
|
|
|
+
|
|
|
static const struct net_device_ops ppp_netdev_ops = {
|
|
|
.ndo_init = ppp_dev_init,
|
|
|
+ .ndo_uninit = ppp_dev_uninit,
|
|
|
.ndo_start_xmit = ppp_start_xmit,
|
|
|
.ndo_do_ioctl = ppp_net_ioctl,
|
|
|
.ndo_get_stats64 = ppp_get_stats64,
|
|
@@ -2667,8 +2700,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
|
|
|
* or if there is already a unit with the requested number.
|
|
|
* unit == -1 means allocate a new number.
|
|
|
*/
|
|
|
-static struct ppp *
|
|
|
-ppp_create_interface(struct net *net, int unit, int *retp)
|
|
|
+static struct ppp *ppp_create_interface(struct net *net, int unit,
|
|
|
+ struct file *file, int *retp)
|
|
|
{
|
|
|
struct ppp *ppp;
|
|
|
struct ppp_net *pn;
|
|
@@ -2688,6 +2721,7 @@ ppp_create_interface(struct net *net, int unit, int *retp)
|
|
|
ppp->mru = PPP_MRU;
|
|
|
init_ppp_file(&ppp->file, INTERFACE);
|
|
|
ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */
|
|
|
+ ppp->owner = file;
|
|
|
for (i = 0; i < NUM_NP; ++i)
|
|
|
ppp->npmode[i] = NPMODE_PASS;
|
|
|
INIT_LIST_HEAD(&ppp->channels);
|
|
@@ -2775,34 +2809,6 @@ init_ppp_file(struct ppp_file *pf, int kind)
|
|
|
init_waitqueue_head(&pf->rwait);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Take down a ppp interface unit - called when the owning file
|
|
|
- * (the one that created the unit) is closed or detached.
|
|
|
- */
|
|
|
-static void ppp_shutdown_interface(struct ppp *ppp)
|
|
|
-{
|
|
|
- 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) {
|
|
|
- ppp->closing = 1;
|
|
|
- ppp_unlock(ppp);
|
|
|
- unregister_netdev(ppp->dev);
|
|
|
- unit_put(&pn->units_idr, ppp->file.index);
|
|
|
- } else
|
|
|
- ppp_unlock(ppp);
|
|
|
-
|
|
|
- ppp->file.dead = 1;
|
|
|
- ppp->owner = NULL;
|
|
|
- wake_up_interruptible(&ppp->file.rwait);
|
|
|
-
|
|
|
- mutex_unlock(&pn->all_ppp_mutex);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Free the memory used by a ppp unit. This is only called once
|
|
|
* there are no channels connected to the unit and no file structs
|