aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ppp
diff options
context:
space:
mode:
authorGuillaume Nault <g.nault@alphalink.fr>2016-04-28 11:55:30 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-29 16:09:44 -0400
commit96d934c70db6e1bc135600c57da1285eaf7efb26 (patch)
treeef01020246a3fbe5aa82f4d1460298e5008d28a0 /drivers/net/ppp
parent7d9f0b48746d37e4381efc02da27535a0a1bac43 (diff)
ppp: add rtnetlink device creation support
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). The PPP device is removed when this file descriptor is released (same behaviour as with ioctl based PPP devices). PPP devices created with the rtnetlink API behave like the ones created with ioctl(PPPIOCNEWUNIT). In particular existing ioctls work the same way, no matter how the PPP device was created. The rtnl callbacks are also assigned to ioctl based PPP devices. This way, rtnl messages have the same effect on any PPP devices. The immediate effect is that all PPP devices, even ioctl-based ones, can now be removed with "ip link del". A minor difference still exists between ioctl and rtnl based PPP interfaces: in the device name, the number following the "ppp" prefix corresponds to the PPP unit number for ioctl based devices, while it is just an unrelated incrementing index for rtnl ones. Signed-off-by: Guillaume Nault <g.nault@alphalink.fr> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ppp')
-rw-r--r--drivers/net/ppp/ppp_generic.c115
1 files changed, 112 insertions, 3 deletions
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 59077c86ba0e..8dedafa1a95d 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -46,6 +46,7 @@
46#include <linux/device.h> 46#include <linux/device.h>
47#include <linux/mutex.h> 47#include <linux/mutex.h>
48#include <linux/slab.h> 48#include <linux/slab.h>
49#include <linux/file.h>
49#include <asm/unaligned.h> 50#include <asm/unaligned.h>
50#include <net/slhc_vj.h> 51#include <net/slhc_vj.h>
51#include <linux/atomic.h> 52#include <linux/atomic.h>
@@ -186,6 +187,7 @@ struct channel {
186struct ppp_config { 187struct ppp_config {
187 struct file *file; 188 struct file *file;
188 s32 unit; 189 s32 unit;
190 bool ifname_is_set;
189}; 191};
190 192
191/* 193/*
@@ -286,6 +288,7 @@ static int unit_get(struct idr *p, void *ptr);
286static int unit_set(struct idr *p, void *ptr, int n); 288static int unit_set(struct idr *p, void *ptr, int n);
287static void unit_put(struct idr *p, int n); 289static void unit_put(struct idr *p, int n);
288static void *unit_find(struct idr *p, int n); 290static void *unit_find(struct idr *p, int n);
291static void ppp_setup(struct net_device *dev);
289 292
290static const struct net_device_ops ppp_netdev_ops; 293static const struct net_device_ops ppp_netdev_ops;
291 294
@@ -964,7 +967,7 @@ static struct pernet_operations ppp_net_ops = {
964 .size = sizeof(struct ppp_net), 967 .size = sizeof(struct ppp_net),
965}; 968};
966 969
967static int ppp_unit_register(struct ppp *ppp, int unit) 970static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set)
968{ 971{
969 struct ppp_net *pn = ppp_pernet(ppp->ppp_net); 972 struct ppp_net *pn = ppp_pernet(ppp->ppp_net);
970 int ret; 973 int ret;
@@ -994,7 +997,8 @@ static int ppp_unit_register(struct ppp *ppp, int unit)
994 } 997 }
995 ppp->file.index = ret; 998 ppp->file.index = ret;
996 999
997 snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index); 1000 if (!ifname_is_set)
1001 snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
998 1002
999 ret = register_netdevice(ppp->dev); 1003 ret = register_netdevice(ppp->dev);
1000 if (ret < 0) 1004 if (ret < 0)
@@ -1043,7 +1047,7 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
1043 ppp->active_filter = NULL; 1047 ppp->active_filter = NULL;
1044#endif /* CONFIG_PPP_FILTER */ 1048#endif /* CONFIG_PPP_FILTER */
1045 1049
1046 err = ppp_unit_register(ppp, conf->unit); 1050 err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set);
1047 if (err < 0) 1051 if (err < 0)
1048 return err; 1052 return err;
1049 1053
@@ -1052,6 +1056,99 @@ static int ppp_dev_configure(struct net *src_net, struct net_device *dev,
1052 return 0; 1056 return 0;
1053} 1057}
1054 1058
1059static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = {
1060 [IFLA_PPP_DEV_FD] = { .type = NLA_S32 },
1061};
1062
1063static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[])
1064{
1065 if (!data)
1066 return -EINVAL;
1067
1068 if (!data[IFLA_PPP_DEV_FD])
1069 return -EINVAL;
1070 if (nla_get_s32(data[IFLA_PPP_DEV_FD]) < 0)
1071 return -EBADF;
1072
1073 return 0;
1074}
1075
1076static int ppp_nl_newlink(struct net *src_net, struct net_device *dev,
1077 struct nlattr *tb[], struct nlattr *data[])
1078{
1079 struct ppp_config conf = {
1080 .unit = -1,
1081 .ifname_is_set = true,
1082 };
1083 struct file *file;
1084 int err;
1085
1086 file = fget(nla_get_s32(data[IFLA_PPP_DEV_FD]));
1087 if (!file)
1088 return -EBADF;
1089
1090 /* rtnl_lock is already held here, but ppp_create_interface() locks
1091 * ppp_mutex before holding rtnl_lock. Using mutex_trylock() avoids
1092 * possible deadlock due to lock order inversion, at the cost of
1093 * pushing the problem back to userspace.
1094 */
1095 if (!mutex_trylock(&ppp_mutex)) {
1096 err = -EBUSY;
1097 goto out;
1098 }
1099
1100 if (file->f_op != &ppp_device_fops || file->private_data) {
1101 err = -EBADF;
1102 goto out_unlock;
1103 }
1104
1105 conf.file = file;
1106 err = ppp_dev_configure(src_net, dev, &conf);
1107
1108out_unlock:
1109 mutex_unlock(&ppp_mutex);
1110out:
1111 fput(file);
1112
1113 return err;
1114}
1115
1116static void ppp_nl_dellink(struct net_device *dev, struct list_head *head)
1117{
1118 unregister_netdevice_queue(dev, head);
1119}
1120
1121static size_t ppp_nl_get_size(const struct net_device *dev)
1122{
1123 return 0;
1124}
1125
1126static int ppp_nl_fill_info(struct sk_buff *skb, const struct net_device *dev)
1127{
1128 return 0;
1129}
1130
1131static struct net *ppp_nl_get_link_net(const struct net_device *dev)
1132{
1133 struct ppp *ppp = netdev_priv(dev);
1134
1135 return ppp->ppp_net;
1136}
1137
1138static struct rtnl_link_ops ppp_link_ops __read_mostly = {
1139 .kind = "ppp",
1140 .maxtype = IFLA_PPP_MAX,
1141 .policy = ppp_nl_policy,
1142 .priv_size = sizeof(struct ppp),
1143 .setup = ppp_setup,
1144 .validate = ppp_nl_validate,
1145 .newlink = ppp_nl_newlink,
1146 .dellink = ppp_nl_dellink,
1147 .get_size = ppp_nl_get_size,
1148 .fill_info = ppp_nl_fill_info,
1149 .get_link_net = ppp_nl_get_link_net,
1150};
1151
1055#define PPP_MAJOR 108 1152#define PPP_MAJOR 108
1056 1153
1057/* Called at boot time if ppp is compiled into the kernel, 1154/* Called at boot time if ppp is compiled into the kernel,
@@ -1080,11 +1177,19 @@ static int __init ppp_init(void)
1080 goto out_chrdev; 1177 goto out_chrdev;
1081 } 1178 }
1082 1179
1180 err = rtnl_link_register(&ppp_link_ops);
1181 if (err) {
1182 pr_err("failed to register rtnetlink PPP handler\n");
1183 goto out_class;
1184 }
1185
1083 /* not a big deal if we fail here :-) */ 1186 /* not a big deal if we fail here :-) */
1084 device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); 1187 device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
1085 1188
1086 return 0; 1189 return 0;
1087 1190
1191out_class:
1192 class_destroy(ppp_class);
1088out_chrdev: 1193out_chrdev:
1089 unregister_chrdev(PPP_MAJOR, "ppp"); 1194 unregister_chrdev(PPP_MAJOR, "ppp");
1090out_net: 1195out_net:
@@ -2829,6 +2934,7 @@ static int ppp_create_interface(struct net *net, struct file *file, int *unit)
2829 struct ppp_config conf = { 2934 struct ppp_config conf = {
2830 .file = file, 2935 .file = file,
2831 .unit = *unit, 2936 .unit = *unit,
2937 .ifname_is_set = false,
2832 }; 2938 };
2833 struct net_device *dev; 2939 struct net_device *dev;
2834 struct ppp *ppp; 2940 struct ppp *ppp;
@@ -2840,6 +2946,7 @@ static int ppp_create_interface(struct net *net, struct file *file, int *unit)
2840 goto err; 2946 goto err;
2841 } 2947 }
2842 dev_net_set(dev, net); 2948 dev_net_set(dev, net);
2949 dev->rtnl_link_ops = &ppp_link_ops;
2843 2950
2844 rtnl_lock(); 2951 rtnl_lock();
2845 2952
@@ -3046,6 +3153,7 @@ static void __exit ppp_cleanup(void)
3046 /* should never happen */ 3153 /* should never happen */
3047 if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) 3154 if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
3048 pr_err("PPP: removing module but units remain!\n"); 3155 pr_err("PPP: removing module but units remain!\n");
3156 rtnl_link_unregister(&ppp_link_ops);
3049 unregister_chrdev(PPP_MAJOR, "ppp"); 3157 unregister_chrdev(PPP_MAJOR, "ppp");
3050 device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); 3158 device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
3051 class_destroy(ppp_class); 3159 class_destroy(ppp_class);
@@ -3104,4 +3212,5 @@ EXPORT_SYMBOL(ppp_register_compressor);
3104EXPORT_SYMBOL(ppp_unregister_compressor); 3212EXPORT_SYMBOL(ppp_unregister_compressor);
3105MODULE_LICENSE("GPL"); 3213MODULE_LICENSE("GPL");
3106MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0); 3214MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
3215MODULE_ALIAS_RTNL_LINK("ppp");
3107MODULE_ALIAS("devname:ppp"); 3216MODULE_ALIAS("devname:ppp");