Skip to contentSkip to conversation

ppp: add netlink support

PATCH In review Guillaume Nault 3 participants 9 messages Dec 23, 2015 – Jan 25, 2016

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover ppp: add netlink support

This series adds netlink support for creating PPP devices.

It doesn't implement any PPP specific attribute beyond IFLA_PPP_DEV_FD, which is necessary in the PPP device model for passing control plane packets to user space.

Guillaume Nault (2):
ppp: define reusable device creation functions
ppp: implement rtnetlink device handling

 drivers/net/ppp/ppp_generic.c | 319 ++++++++++++++++++++++++++++++------------
 include/uapi/linux/if_link.h  |   8 ++
 2 files changed, 237 insertions(+), 90 deletions(-)
Signature · 1 line
2.6.4
#1 lore raw

PATCH 1/2 ppp: define reusable device creation functions

Move PPP device initialisation and registration out of ppp_create_interface().
This prepares code for device registration with rtnetlink.

While there, cleanup ppp_create_interface() prototype to return an error code rather than the ppp structure. The unit parameter is now read/write so that caller can retrieve the unit identifier without accessing the new ppp structure.

---
 drivers/net/ppp/ppp_generic.c | 216 +++++++++++++++++++++++++-----------------
 1 file changed, 127 insertions(+), 89 deletions(-)
drivers/net/ppp/ppp_generic.c +127 -89
index fc8ad00..bc24537 100644
@@ -183,6 +183,11 @@ struct channel {
 #endif /* CONFIG_PPP_MULTILINK */
 };
 
+struct ppp_config {
+	struct file *file;
+	s32 unit;
+};
+
 /*
  * SMP locking issues:
  * Both the ppp.rlock and ppp.wlock locks protect the ppp.channels
@@ -269,8 +274,7 @@ 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,
-					struct file *file, int *retp);
+static int ppp_create_interface(struct net *net, int *unit, struct file *file);
 static void init_ppp_file(struct ppp_file *pf, int kind);
 static void ppp_destroy_interface(struct ppp *ppp);
 static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit);
@@ -842,12 +846,13 @@ 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, file, &err);
-		if (!ppp)
+
+		err = ppp_create_interface(net, &unit, file);
+		if (err)
 			break;
-		file->private_data = &ppp->file;
+
 		err = -EFAULT;
-		if (put_user(ppp->file.index, p))
+		if (put_user(unit, p))
 			break;
 		err = 0;
 		break;
@@ -949,6 +954,101 @@ static struct pernet_operations ppp_net_ops = {
 	.size = sizeof(struct ppp_net),
 };
 
+static int ppp_unit_register(struct ppp *ppp, int unit)
+{
+	struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
+	int ret;
+
+	mutex_lock(&pn->all_ppp_mutex);
+
+	if (unit < 0) {
+		ret = unit_get(&pn->units_idr, ppp);
+		if (ret < 0)
+			goto err;
+	} else {
+		/* Caller asked for a specific unit number. Fail with -EEXIST
+		 * if unavailable. For backward compatibility, return -EEXIST
+		 * too if idr allocation fails; this makes pppd retry without
+		 * requesting a specific unit number.
+		 */
+		if (unit_find(&pn->units_idr, unit)) {
+			ret = -EEXIST;
+			goto err;
+		}
+		ret = unit_set(&pn->units_idr, ppp, unit);
+		if (ret < 0) {
+			ret = -EEXIST; /* rewrite error for backward compat. */
+			goto err;
+		}
+	}
+
+	ppp->file.index = ret;
+
+	snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
+
+	ret = register_netdevice(ppp->dev);
+	if (ret)
+		goto err_unit;
+
+	atomic_inc(&ppp_unit_count);
+
+	mutex_unlock(&pn->all_ppp_mutex);
+
+	return 0;
+
+err_unit:
+	unit_put(&pn->units_idr, ppp->file.index);
+err:
+	mutex_unlock(&pn->all_ppp_mutex);
+
+	return ret;
+}
+
+static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
+			     const struct ppp_config *conf)
+{
+	struct ppp *ppp = netdev_priv(dev);
+	struct file *file;
+	int indx;
+	int err;
+
+	file = conf->file;
+	if (!file)
+		return -EBADF;
+	if (file->private_data)
+		return -EBUSY;
+
+	init_ppp_file(&ppp->file, INTERFACE);
+	ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */
+	ppp->owner = file;
+
+	for (indx = 0; indx < NUM_NP; ++indx)
+		ppp->npmode[indx] = NPMODE_PASS;
+	INIT_LIST_HEAD(&ppp->channels);
+	spin_lock_init(&ppp->rlock);
+	spin_lock_init(&ppp->wlock);
+#ifdef CONFIG_PPP_MULTILINK
+	ppp->minseq = -1;
+	skb_queue_head_init(&ppp->mrq);
+#endif /* CONFIG_PPP_MULTILINK */
+#ifdef CONFIG_PPP_FILTER
+	ppp->pass_filter = NULL;
+	ppp->active_filter = NULL;
+#endif /* CONFIG_PPP_FILTER */
+
+	ppp->dev = dev;
+	ppp->mru = PPP_MRU;
+	ppp->ppp_net = src_net;
+
+	err = ppp_unit_register(ppp, conf->unit);
+	if (err < 0)
+		return err;
+
+	file->private_data = &ppp->file;
+
+	return 0;
+}
+
 #define PPP_MAJOR	108
 
 /* Called at boot time if ppp is compiled into the kernel,
@@ -2717,101 +2817,39 @@ 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,
-					struct file *file, int *retp)
+static int ppp_create_interface(struct net *net, int *unit, struct file *file)
 {
+	struct ppp_config conf = {
+		.file = file,
+		.unit = *unit,
+	};
+	struct net_device *dev;
 	struct ppp *ppp;
-	struct ppp_net *pn;
-	struct net_device *dev = NULL;
-	int ret = -ENOMEM;
-	int i;
+	int err;
 
 	dev = alloc_netdev(sizeof(struct ppp), "", NET_NAME_ENUM, ppp_setup);
-	if (!dev)
-		goto out1;
-
-	pn = ppp_pernet(net);
-
-	ppp = netdev_priv(dev);
-	ppp->dev = dev;
-	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);
-	spin_lock_init(&ppp->rlock);
-	spin_lock_init(&ppp->wlock);
-#ifdef CONFIG_PPP_MULTILINK
-	ppp->minseq = -1;
-	skb_queue_head_init(&ppp->mrq);
-#endif /* CONFIG_PPP_MULTILINK */
-#ifdef CONFIG_PPP_FILTER
-	ppp->pass_filter = NULL;
-	ppp->active_filter = NULL;
-#endif /* CONFIG_PPP_FILTER */
+	if (!dev) {
+		err = -ENOMEM;
+		goto err;
+	}
 
-	/*
-	 * drum roll: don't forget to set
-	 * the net device is belong to
-	 */
 	dev_net_set(dev, net);
 
 	rtnl_lock();
-	mutex_lock(&pn->all_ppp_mutex);
-
-	if (unit < 0) {
-		unit = unit_get(&pn->units_idr, ppp);
-		if (unit < 0) {
-			ret = unit;
-			goto out2;
-		}
-	} else {
-		ret = -EEXIST;
-		if (unit_find(&pn->units_idr, unit))
-			goto out2; /* unit already exists */
-		/*
-		 * if caller need a specified unit number
-		 * lets try to satisfy him, otherwise --
-		 * he should better ask us for new unit number
-		 *
-		 * NOTE: yes I know that returning EEXIST it's not
-		 * fair but at least pppd will ask us to allocate
-		 * new unit in this case so user is happy :)
-		 */
-		unit = unit_set(&pn->units_idr, ppp, unit);
-		if (unit < 0)
-			goto out2;
-	}
-
-	/* Initialize the new ppp unit */
-	ppp->file.index = unit;
-	sprintf(dev->name, "ppp%d", unit);
-
-	ret = register_netdevice(dev);
-	if (ret != 0) {
-		unit_put(&pn->units_idr, unit);
-		netdev_err(ppp->dev, "PPP: couldn't register device %s (%d)\n",
-			   dev->name, ret);
-		goto out2;
-	}
-
-	ppp->ppp_net = net;
-
-	atomic_inc(&ppp_unit_count);
-	mutex_unlock(&pn->all_ppp_mutex);
+	err = ppp_dev_configure(net, dev, &conf);
 	rtnl_unlock();
+	if (err)
+		goto err_dev;
 
-	*retp = 0;
-	return ppp;
+	ppp = netdev_priv(dev);
+	*unit = ppp->file.index;
 
-out2:
-	mutex_unlock(&pn->all_ppp_mutex);
+	return 0;
+
+err_dev:
 	free_netdev(dev);
-out1:
-	*retp = ret;
-	return NULL;
+err:
+	return err;
 }
 
 /*
Signature · 1 line
2.6.4
#2 lore raw

PATCH 2/2 ppp: implement rtnetlink device handling

In reply to Guillaume Nault

Define PPP device handler for use with rtnetlink.

The only PPP specific attribute is IFLA_PPP_DEV_FD. It is mandatory and contains the file descriptor of the associated /dev/ppp instance (the file descriptor which would have been used for ioctl(PPPIOCNEWUNIT) in the ioctl-based API).

PPP devices created with the rtnetlink API behave like the ones created with ioctl(PPPIOCNEWUNIT). In particular existing ioctls still apply to PPP units created with the rtnetlink API.

---
 drivers/net/ppp/ppp_generic.c | 109 ++++++++++++++++++++++++++++++++++++++++--
 include/uapi/linux/if_link.h  |   8 ++++
 2 files changed, 113 insertions(+), 4 deletions(-)
drivers/net/ppp/ppp_generic.c +105 -4
index bc24537..19476d6 100644
@@ -46,6 +46,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 #include <asm/unaligned.h>
 #include <net/slhc_vj.h>
 #include <linux/atomic.h>
@@ -185,7 +186,9 @@ struct channel {
 
 struct ppp_config {
 	struct file *file;
+	s32 fd;
 	s32 unit;
+	bool ifname_is_set;
 };
 
 /*
@@ -286,6 +289,7 @@ static int unit_get(struct idr *p, void *ptr);
 static int unit_set(struct idr *p, void *ptr, int n);
 static void unit_put(struct idr *p, int n);
 static void *unit_find(struct idr *p, int n);
+static void ppp_setup(struct net_device *dev);
 
 static const struct net_device_ops ppp_netdev_ops;
 
@@ -954,7 +958,7 @@ static struct pernet_operations ppp_net_ops = {
 	.size = sizeof(struct ppp_net),
 };
 
-static int ppp_unit_register(struct ppp *ppp, int unit)
+static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set)
 {
 	struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
 	int ret;
@@ -984,7 +988,8 @@ static int ppp_unit_register(struct ppp *ppp, int unit)
 
 	ppp->file.index = ret;
 
-	snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
+	if (!ifname_is_set)
+		snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
 
 	ret = register_netdevice(ppp->dev);
 	if (ret)
@@ -1012,7 +1017,24 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 	int indx;
 	int err;
 
-	file = conf->file;
+	if (conf->fd >= 0) {
+		file = fget(conf->fd);
+		if (file) {
+			if (file->f_op != &ppp_device_fops) {
+				fput(file);
+				return -EBADF;
+			}
+
+			/* Don't hold reference on file: ppp_release() is
+			 * responsible for safely freeing the associated
+			 * resources upon release. So file won't go away
+			 * from under us.
+			 */
+			fput(file);
+		}
+	} else {
+		file = conf->file;
+	}
 	if (!file)
 		return -EBADF;
 	if (file->private_data)
@@ -1040,7 +1062,7 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 	ppp->mru = PPP_MRU;
 	ppp->ppp_net = src_net;
 
-	err = ppp_unit_register(ppp, conf->unit);
+	err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
 	if (err < 0)
 		return err;
 
@@ -1049,6 +1071,73 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 	return 0;
 }
 
+static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
+	[IFLA_PPP_DEV_FD]	= { .type = NLA_S32 },
+};
+
+static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	if (!data)
+		return -EINVAL;
+
+	if (!data[IFLA_PPP_DEV_FD])
+		return -EINVAL;
+	if (nla_get_s32(data[IFLA_PPP_DEV_FD]) < 0)
+		return -EBADF;
+
+	return 0;
+}
+
+static int ppp_nl_newlink(struct net *src_net, struct net_device *dev,
+			  struct nlattr *tb[], struct nlattr *data[])
+{
+	struct ppp_config conf = {
+		.file = NULL,
+		.unit = -1,
+		.ifname_is_set = true,
+	};
+
+	conf.fd = nla_get_s32(data[IFLA_PPP_DEV_FD]);
+
+	return ppp_dev_configure(src_net, dev, &conf);
+}
+
+static void ppp_nl_dellink(struct net_device *dev, struct list_head *head)
+{
+	unregister_netdevice_queue(dev, head);
+}
+
+static size_t ppp_nl_get_size(const struct net_device *dev)
+{
+	return 0;
+}
+
+static int ppp_nl_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	return 0;
+}
+
+static struct net *ppp_nl_get_link_net(const struct net_device *dev)
+{
+	struct ppp *ppp = netdev_priv(dev);
+
+	return ppp->ppp_net;
+}
+
+static struct rtnl_link_ops ppp_link_ops __read_mostly = {
+	.kind		= "ppp",
+	.maxtype	= IFLA_PPP_MAX,
+	.policy		= ppp_nl_policy,
+	.priv_size	= sizeof(struct ppp),
+	.setup		= ppp_setup,
+	.validate	= ppp_nl_validate,
+	.newlink	= ppp_nl_newlink,
+	.dellink	= ppp_nl_dellink,
+	.get_size	= ppp_nl_get_size,
+	.fill_info	= ppp_nl_fill_info,
+	.get_link_net	= ppp_nl_get_link_net,
+};
+
 #define PPP_MAJOR	108
 
 /* Called at boot time if ppp is compiled into the kernel,
@@ -1077,11 +1166,19 @@ static int __init ppp_init(void)
 		goto out_chrdev;
 	}
 
+	err = rtnl_link_register(&ppp_link_ops);
+	if (err) {
+		pr_err("Failed to register RT netlink PPP handler\n");
+		goto out_class;
+	}
+
 	/* not a big deal if we fail here :-) */
 	device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
 
 	return 0;
 
+out_class:
+	class_destroy(ppp_class);
 out_chrdev:
 	unregister_chrdev(PPP_MAJOR, "ppp");
 out_net:
@@ -2821,7 +2918,9 @@ static int ppp_create_interface(struct net *net, int *unit, struct file *file)
 {
 	struct ppp_config conf = {
 		.file = file,
+		.fd = -1,
 		.unit = *unit,
+		.ifname_is_set = false,
 	};
 	struct net_device *dev;
 	struct ppp *ppp;
@@ -3038,6 +3137,7 @@ static void __exit ppp_cleanup(void)
 	/* should never happen */
 	if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
 		pr_err("PPP: removing module but units remain!\n");
+	rtnl_link_unregister(&ppp_link_ops);
 	unregister_chrdev(PPP_MAJOR, "ppp");
 	device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
 	class_destroy(ppp_class);
@@ -3096,4 +3196,5 @@ EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
+MODULE_ALIAS_RTNL_LINK("ppp");
 MODULE_ALIAS("devname:ppp");
include/uapi/linux/if_link.h +8 -0
index a30b780..72b0213 100644
@@ -470,6 +470,14 @@ enum {
 };
 #define IFLA_GENEVE_MAX	(__IFLA_GENEVE_MAX - 1)
 
+/* PPP section */
+enum {
+	IFLA_PPP_UNSPEC,
+	IFLA_PPP_DEV_FD,
+	__IFLA_PPP_MAX,
+};
+#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1)
+
 /* Bonding section */
 
 enum {
Signature · 1 line
2.6.4
#3 lore raw

Re: [PATCH 2/2] ppp: implement rtnetlink device handling

Am 23.12.2015 21:04, schrieb Guillaume Nault:

Quoted 81 lines

Define PPP device handler for use with rtnetlink.

The only PPP specific attribute is IFLA_PPP_DEV_FD. It is mandatory and contains the file descriptor of the associated /dev/ppp instance (the file descriptor which would have been used for ioctl(PPPIOCNEWUNIT) in the ioctl-based API).

PPP devices created with the rtnetlink API behave like the ones created with ioctl(PPPIOCNEWUNIT). In particular existing ioctls still apply to PPP units created with the rtnetlink API.

---
 drivers/net/ppp/ppp_generic.c | 109 ++++++++++++++++++++++++++++++++++++++++--
 include/uapi/linux/if_link.h  |   8 ++++
 2 files changed, 113 insertions(+), 4 deletions(-)
drivers/net/ppp/ppp_generic.c +17 -3
index bc24537..19476d6 100644
@@ -46,6 +46,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 #include <asm/unaligned.h>
 #include <net/slhc_vj.h>
 #include <linux/atomic.h>
@@ -185,7 +186,9 @@ struct channel {
 
 struct ppp_config {
 	struct file *file;
+	s32 fd;
 	s32 unit;
+	bool ifname_is_set;
 };
 
 /*
@@ -286,6 +289,7 @@ static int unit_get(struct idr *p, void *ptr);
 static int unit_set(struct idr *p, void *ptr, int n);
 static void unit_put(struct idr *p, int n);
 static void *unit_find(struct idr *p, int n);
+static void ppp_setup(struct net_device *dev);
 
 static const struct net_device_ops ppp_netdev_ops;
 
@@ -954,7 +958,7 @@ static struct pernet_operations ppp_net_ops = {
 	.size = sizeof(struct ppp_net),
 };
 
-static int ppp_unit_register(struct ppp *ppp, int unit)
+static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set)
 {
 	struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
 	int ret;
@@ -984,7 +988,8 @@ static int ppp_unit_register(struct ppp *ppp, int unit)
 
 	ppp->file.index = ret;
 
-	snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
+	if (!ifname_is_set)
+		snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
 
 	ret = register_netdevice(ppp->dev);
 	if (ret)
@@ -1012,7 +1017,24 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 	int indx;
 	int err;
 
-	file = conf->file;
+	if (conf->fd >= 0) {
+		file = fget(conf->fd);
+		if (file) {
+			if (file->f_op != &ppp_device_fops) {
+				fput(file);
+				return -EBADF;
+			}
+
+			/* Don't hold reference on file: ppp_release() is
+			 * responsible for safely freeing the associated

drivers/net/ppp/ppp_generic.c static int ppp_dev_configure(struct net *src_net, struct net_device *dev, · line 1039

Quoted 10 lines
drivers/net/ppp/ppp_generic.c +8 -0
+			 * resources upon release. So file won't go away
+			 * from under us.
+			 */
+			fput(file);
+		}
+	} else {
+		file = conf->file;
+	}
 	if (!file)
 		return -EBADF;

I would write that a bid different to reduce indent und improve readability

(note: totaly untested just reviewing)

if (conf->fd < 0) {
	file = conf->file;
	if (!file)

return -EBADF;
}
else
{
file = fget(conf->fd);
if (!file)
return -EBADF;

fput(file);

if (file->f_op != &ppp_device_fops) {		
		return -EBADF;
	}

}

just my 2 cents

re,
wh

Quoted 147 lines
drivers/net/ppp/ppp_generic.c +80 -1
 	if (file->private_data)
@@ -1040,7 +1062,7 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 	ppp->mru = PPP_MRU;
 	ppp->ppp_net = src_net;
 
-	err = ppp_unit_register(ppp, conf->unit);
+	err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
 	if (err < 0)
 		return err;
 
@@ -1049,6 +1071,73 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 	return 0;
 }
 
+static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
+	[IFLA_PPP_DEV_FD]	= { .type = NLA_S32 },
+};
+
+static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	if (!data)
+		return -EINVAL;
+
+	if (!data[IFLA_PPP_DEV_FD])
+		return -EINVAL;
+	if (nla_get_s32(data[IFLA_PPP_DEV_FD]) < 0)
+		return -EBADF;
+
+	return 0;
+}
+
+static int ppp_nl_newlink(struct net *src_net, struct net_device *dev,
+			  struct nlattr *tb[], struct nlattr *data[])
+{
+	struct ppp_config conf = {
+		.file = NULL,
+		.unit = -1,
+		.ifname_is_set = true,
+	};
+
+	conf.fd = nla_get_s32(data[IFLA_PPP_DEV_FD]);
+
+	return ppp_dev_configure(src_net, dev, &conf);
+}
+
+static void ppp_nl_dellink(struct net_device *dev, struct list_head *head)
+{
+	unregister_netdevice_queue(dev, head);
+}
+
+static size_t ppp_nl_get_size(const struct net_device *dev)
+{
+	return 0;
+}
+
+static int ppp_nl_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+	return 0;
+}
+
+static struct net *ppp_nl_get_link_net(const struct net_device *dev)
+{
+	struct ppp *ppp = netdev_priv(dev);
+
+	return ppp->ppp_net;
+}
+
+static struct rtnl_link_ops ppp_link_ops __read_mostly = {
+	.kind		= "ppp",
+	.maxtype	= IFLA_PPP_MAX,
+	.policy		= ppp_nl_policy,
+	.priv_size	= sizeof(struct ppp),
+	.setup		= ppp_setup,
+	.validate	= ppp_nl_validate,
+	.newlink	= ppp_nl_newlink,
+	.dellink	= ppp_nl_dellink,
+	.get_size	= ppp_nl_get_size,
+	.fill_info	= ppp_nl_fill_info,
+	.get_link_net	= ppp_nl_get_link_net,
+};
+
 #define PPP_MAJOR	108
 
 /* Called at boot time if ppp is compiled into the kernel,
@@ -1077,11 +1166,19 @@ static int __init ppp_init(void)
 		goto out_chrdev;
 	}
 
+	err = rtnl_link_register(&ppp_link_ops);
+	if (err) {
+		pr_err("Failed to register RT netlink PPP handler\n");
+		goto out_class;
+	}
+
 	/* not a big deal if we fail here :-) */
 	device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
 
 	return 0;
 
+out_class:
+	class_destroy(ppp_class);
 out_chrdev:
 	unregister_chrdev(PPP_MAJOR, "ppp");
 out_net:
@@ -2821,7 +2918,9 @@ static int ppp_create_interface(struct net *net, int *unit, struct file *file)
 {
 	struct ppp_config conf = {
 		.file = file,
+		.fd = -1,
 		.unit = *unit,
+		.ifname_is_set = false,
 	};
 	struct net_device *dev;
 	struct ppp *ppp;
@@ -3038,6 +3137,7 @@ static void __exit ppp_cleanup(void)
 	/* should never happen */
 	if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
 		pr_err("PPP: removing module but units remain!\n");
+	rtnl_link_unregister(&ppp_link_ops);
 	unregister_chrdev(PPP_MAJOR, "ppp");
 	device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
 	class_destroy(ppp_class);
@@ -3096,4 +3196,5 @@ EXPORT_SYMBOL(ppp_register_compressor);
 EXPORT_SYMBOL(ppp_unregister_compressor);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
+MODULE_ALIAS_RTNL_LINK("ppp");
 MODULE_ALIAS("devname:ppp");
include/uapi/linux/if_link.h +8 -0
index a30b780..72b0213 100644
@@ -470,6 +470,14 @@ enum {
 };
 #define IFLA_GENEVE_MAX	(__IFLA_GENEVE_MAX - 1)
 
+/* PPP section */
+enum {
+	IFLA_PPP_UNSPEC,
+	IFLA_PPP_DEV_FD,
+	__IFLA_PPP_MAX,
+};
+#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1)
+
 /* Bonding section */
 
 enum {
#4 lore raw

Re: [PATCH 2/2] ppp: implement rtnetlink device handling

Quoted 38 lines · walter harms

Am 23.12.2015 21:04, schrieb Guillaume Nault:

Quoted 15 lines
drivers/net/ppp/ppp_generic.c +10 -1
@@ -1012,7 +1017,24 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
 	int indx;
 	int err;
 
-	file = conf->file;
+	if (conf->fd >= 0) {
+		file = fget(conf->fd);
+		if (file) {
+			if (file->f_op != &ppp_device_fops) {
+				fput(file);
+				return -EBADF;
+			}
+
+			/* Don't hold reference on file: ppp_release() is
+			 * responsible for safely freeing the associated

drivers/net/ppp/ppp_generic.c static int ppp_dev_configure(struct net *src_net, struct net_device *dev, · line 1039

Quoted 10 lines
drivers/net/ppp/ppp_generic.c +8 -0
+			 * resources upon release. So file won't go away
+			 * from under us.
+			 */
+			fput(file);
+		}
+	} else {
+		file = conf->file;
+	}
 	if (!file)
 		return -EBADF;

I would write that a bid different to reduce indent und improve readability

(note: totaly untested just reviewing)

if (conf->fd < 0) {
	file = conf->file;
	if (!file)
Quoted 8 lines

return -EBADF;
}
else
{
file = fget(conf->fd);
if (!file)
return -EBADF;

Early return on fget() failure looks indeed simpler.

Quoted 5 lines

fput(file);

if (file->f_op != &ppp_device_fops) {		
		return -EBADF;
	}

But this is wrong: we can't act on file after fput(). So we have to place fput() after the test.

Thanks for your review.

#6 lore raw
In reply to Guillaume Nault
Quoted 2 lines · Guillaume Nault

This series adds netlink support for creating PPP devices.

Any feedback on this series? I can see that it has been marked "Deferred" in patchwork, so I'm unsure about what to do with this patch set now.
Should I repost later (e.g. after the end of the merge window)? Are there any concern/issues with the series itself? Or should the idea of implementing netlink handlers for ppp devices be entirely dropped?

maintainer
#7 lore raw

From: Guillaume Nault <[email protected]>
Date: Tue, 5 Jan 2016 19:10:20 +0100

Quoted 9 lines · Guillaume Nault
Quoted 2 lines

This series adds netlink support for creating PPP devices.

Any feedback on this series? I can see that it has been marked "Deferred" in patchwork, so I'm unsure about what to do with this patch set now.
Should I repost later (e.g. after the end of the merge window)? Are there any concern/issues with the series itself? Or should the idea of implementing netlink handlers for ppp devices be entirely dropped?

Repost it again later, I want more people to see and review this series and the holidays is not a good time for that...

#8 lore raw
Quoted 13 lines · David Miller

From: Guillaume Nault <[email protected]>
Date: Tue, 5 Jan 2016 19:10:20 +0100

Quoted 9 lines · Guillaume Nault
Quoted 2 lines

This series adds netlink support for creating PPP devices.

Any feedback on this series? I can see that it has been marked "Deferred" in patchwork, so I'm unsure about what to do with this patch set now.
Should I repost later (e.g. after the end of the merge window)? Are there any concern/issues with the series itself? Or should the idea of implementing netlink handlers for ppp devices be entirely dropped?

Quoted 2 lines

Repost it again later, I want more people to see and review this series and the holidays is not a good time for that...

Sure. Thanks for the feedback.