@@ -245,8 +245,8 @@ struct ppp_net {
#define seq_after(a, b) ((s32)((a) - (b)) > 0)
/* Prototypes. */
-static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
- struct file *file, unsigned int cmd, unsigned long arg);
+static int ppp_unattached_ioctl(struct net *net, 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);
@@ -584,12 +584,19 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
void __user *argp = (void __user *)arg;
int __user *p = argp;
+ switch (cmd) {
+ case PPPIOCNEWUNIT:
+ case PPPIOCATTACH:
+ case PPPIOCATTCHAN:
+ return ppp_unattached_ioctl(current->nsproxy->net_ns, file,
+ cmd, arg);
+ }
+
mutex_lock(&ppp_mutex);
pf = file->private_data;
if (!pf) {
- err = ppp_unattached_ioctl(current->nsproxy->net_ns,
- pf, file, cmd, arg);
+ err = -ENOTTY;
goto out;
}
@@ -838,8 +845,8 @@ out:
return err;
}
-static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
- struct file *file, unsigned int cmd, unsigned long arg)
+static int ppp_unattached_ioctl(struct net *net, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
int unit, err = -EFAULT;
struct ppp *ppp;
@@ -867,31 +874,43 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
/* Attach to an existing ppp unit */
if (get_user(unit, p))
break;
+
err = -ENXIO;
pn = ppp_pernet(net);
+ mutex_lock(&ppp_mutex);
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;
+ err = -ENOTTY;
+ if (!file->private_data) {
+ atomic_inc(&ppp->file.refcnt);
+ file->private_data = &ppp->file;
+ err = 0;
+ }
}
mutex_unlock(&pn->all_ppp_mutex);
+ mutex_unlock(&ppp_mutex);
break;
case PPPIOCATTCHAN:
if (get_user(unit, p))
break;
+
err = -ENXIO;
pn = ppp_pernet(net);
+ mutex_lock(&ppp_mutex);
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;
+ err = -ENOTTY;
+ if (!file->private_data) {
+ atomic_inc(&chan->file.refcnt);
+ file->private_data = &chan->file;
+ err = 0;
+ }
}
spin_unlock_bh(&pn->all_channels_lock);
+ mutex_unlock(&ppp_mutex);
break;
default:
@@ -2772,9 +2791,15 @@ static int ppp_create_interface(struct net *net, struct file *file, int *unit)
*/
dev_net_set(dev, net);
+ mutex_lock(&ppp_mutex);
rtnl_lock();
mutex_lock(&pn->all_ppp_mutex);
+ if (file->private_data) {
+ ret = -ENOTTY;
+ goto out2;
+ }
+
if (*unit < 0) {
ret = unit_get(&pn->units_idr, ppp);
if (ret < 0)
@@ -2818,12 +2843,14 @@ static int ppp_create_interface(struct net *net, struct file *file, int *unit)
mutex_unlock(&pn->all_ppp_mutex);
rtnl_unlock();
+ mutex_unlock(&ppp_mutex);
return 0;
out2:
mutex_unlock(&pn->all_ppp_mutex);
rtnl_unlock();
+ mutex_unlock(&ppp_mutex);
free_netdev(dev);
out1:
return ret;
Let ppp_unattached_ioctl() lock ppp_mutex only when needed. For PPPIOCATTACH and PPPIOCATTCHAN, we just need to lock ppp_mutex before all_ppp_mutex/all_channels_lock (to keep lock ordering) and to take care of the -ENOTTY error code when file->private_data is not NULL. For PPPIOCNEWUNIT, ppp_mutex is pushed further down in ppp_create_interface() and is held right before rtnl_lock. The goal is to eventually lock ppp_mutex after rtnl_lock, so that PPP device creation can be done inside a rtnetlink function handler. While there, remove unused ppp_file argument from ppp_unattached_ioctl() prototype. Signed-off-by: Guillaume Nault <g.nault@alphalink.fr> --- drivers/net/ppp/ppp_generic.c | 51 +++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 12 deletions(-)