Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Guillaume Nault and committed by
David S. Miller
96d934c7 7d9f0b48

+120 -3
+112 -3
drivers/net/ppp/ppp_generic.c
··· 46 46 #include <linux/device.h> 47 47 #include <linux/mutex.h> 48 48 #include <linux/slab.h> 49 + #include <linux/file.h> 49 50 #include <asm/unaligned.h> 50 51 #include <net/slhc_vj.h> 51 52 #include <linux/atomic.h> ··· 187 186 struct ppp_config { 188 187 struct file *file; 189 188 s32 unit; 189 + bool ifname_is_set; 190 190 }; 191 191 192 192 /* ··· 288 286 static int unit_set(struct idr *p, void *ptr, int n); 289 287 static void unit_put(struct idr *p, int n); 290 288 static void *unit_find(struct idr *p, int n); 289 + static void ppp_setup(struct net_device *dev); 291 290 292 291 static const struct net_device_ops ppp_netdev_ops; 293 292 ··· 967 964 .size = sizeof(struct ppp_net), 968 965 }; 969 966 970 - static int ppp_unit_register(struct ppp *ppp, int unit) 967 + static int ppp_unit_register(struct ppp *ppp, int unit, bool ifname_is_set) 971 968 { 972 969 struct ppp_net *pn = ppp_pernet(ppp->ppp_net); 973 970 int ret; ··· 997 994 } 998 995 ppp->file.index = ret; 999 996 1000 - snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index); 997 + if (!ifname_is_set) 998 + snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index); 1001 999 1002 1000 ret = register_netdevice(ppp->dev); 1003 1001 if (ret < 0) ··· 1047 1043 ppp->active_filter = NULL; 1048 1044 #endif /* CONFIG_PPP_FILTER */ 1049 1045 1050 - err = ppp_unit_register(ppp, conf->unit); 1046 + err = ppp_unit_register(ppp, conf->unit, conf->ifname_is_set); 1051 1047 if (err < 0) 1052 1048 return err; 1053 1049 ··· 1055 1051 1056 1052 return 0; 1057 1053 } 1054 + 1055 + static const struct nla_policy ppp_nl_policy[IFLA_PPP_MAX + 1] = { 1056 + [IFLA_PPP_DEV_FD] = { .type = NLA_S32 }, 1057 + }; 1058 + 1059 + static int ppp_nl_validate(struct nlattr *tb[], struct nlattr *data[]) 1060 + { 1061 + if (!data) 1062 + return -EINVAL; 1063 + 1064 + if (!data[IFLA_PPP_DEV_FD]) 1065 + return -EINVAL; 1066 + if (nla_get_s32(data[IFLA_PPP_DEV_FD]) < 0) 1067 + return -EBADF; 1068 + 1069 + return 0; 1070 + } 1071 + 1072 + static int ppp_nl_newlink(struct net *src_net, struct net_device *dev, 1073 + struct nlattr *tb[], struct nlattr *data[]) 1074 + { 1075 + struct ppp_config conf = { 1076 + .unit = -1, 1077 + .ifname_is_set = true, 1078 + }; 1079 + struct file *file; 1080 + int err; 1081 + 1082 + file = fget(nla_get_s32(data[IFLA_PPP_DEV_FD])); 1083 + if (!file) 1084 + return -EBADF; 1085 + 1086 + /* rtnl_lock is already held here, but ppp_create_interface() locks 1087 + * ppp_mutex before holding rtnl_lock. Using mutex_trylock() avoids 1088 + * possible deadlock due to lock order inversion, at the cost of 1089 + * pushing the problem back to userspace. 1090 + */ 1091 + if (!mutex_trylock(&ppp_mutex)) { 1092 + err = -EBUSY; 1093 + goto out; 1094 + } 1095 + 1096 + if (file->f_op != &ppp_device_fops || file->private_data) { 1097 + err = -EBADF; 1098 + goto out_unlock; 1099 + } 1100 + 1101 + conf.file = file; 1102 + err = ppp_dev_configure(src_net, dev, &conf); 1103 + 1104 + out_unlock: 1105 + mutex_unlock(&ppp_mutex); 1106 + out: 1107 + fput(file); 1108 + 1109 + return err; 1110 + } 1111 + 1112 + static void ppp_nl_dellink(struct net_device *dev, struct list_head *head) 1113 + { 1114 + unregister_netdevice_queue(dev, head); 1115 + } 1116 + 1117 + static size_t ppp_nl_get_size(const struct net_device *dev) 1118 + { 1119 + return 0; 1120 + } 1121 + 1122 + static int ppp_nl_fill_info(struct sk_buff *skb, const struct net_device *dev) 1123 + { 1124 + return 0; 1125 + } 1126 + 1127 + static struct net *ppp_nl_get_link_net(const struct net_device *dev) 1128 + { 1129 + struct ppp *ppp = netdev_priv(dev); 1130 + 1131 + return ppp->ppp_net; 1132 + } 1133 + 1134 + static struct rtnl_link_ops ppp_link_ops __read_mostly = { 1135 + .kind = "ppp", 1136 + .maxtype = IFLA_PPP_MAX, 1137 + .policy = ppp_nl_policy, 1138 + .priv_size = sizeof(struct ppp), 1139 + .setup = ppp_setup, 1140 + .validate = ppp_nl_validate, 1141 + .newlink = ppp_nl_newlink, 1142 + .dellink = ppp_nl_dellink, 1143 + .get_size = ppp_nl_get_size, 1144 + .fill_info = ppp_nl_fill_info, 1145 + .get_link_net = ppp_nl_get_link_net, 1146 + }; 1058 1147 1059 1148 #define PPP_MAJOR 108 1060 1149 ··· 1177 1080 goto out_chrdev; 1178 1081 } 1179 1082 1083 + err = rtnl_link_register(&ppp_link_ops); 1084 + if (err) { 1085 + pr_err("failed to register rtnetlink PPP handler\n"); 1086 + goto out_class; 1087 + } 1088 + 1180 1089 /* not a big deal if we fail here :-) */ 1181 1090 device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); 1182 1091 1183 1092 return 0; 1184 1093 1094 + out_class: 1095 + class_destroy(ppp_class); 1185 1096 out_chrdev: 1186 1097 unregister_chrdev(PPP_MAJOR, "ppp"); 1187 1098 out_net: ··· 2934 2829 struct ppp_config conf = { 2935 2830 .file = file, 2936 2831 .unit = *unit, 2832 + .ifname_is_set = false, 2937 2833 }; 2938 2834 struct net_device *dev; 2939 2835 struct ppp *ppp; ··· 2946 2840 goto err; 2947 2841 } 2948 2842 dev_net_set(dev, net); 2843 + dev->rtnl_link_ops = &ppp_link_ops; 2949 2844 2950 2845 rtnl_lock(); 2951 2846 ··· 3153 3046 /* should never happen */ 3154 3047 if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) 3155 3048 pr_err("PPP: removing module but units remain!\n"); 3049 + rtnl_link_unregister(&ppp_link_ops); 3156 3050 unregister_chrdev(PPP_MAJOR, "ppp"); 3157 3051 device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); 3158 3052 class_destroy(ppp_class); ··· 3212 3104 EXPORT_SYMBOL(ppp_unregister_compressor); 3213 3105 MODULE_LICENSE("GPL"); 3214 3106 MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0); 3107 + MODULE_ALIAS_RTNL_LINK("ppp"); 3215 3108 MODULE_ALIAS("devname:ppp");
+8
include/uapi/linux/if_link.h
··· 520 520 }; 521 521 #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) 522 522 523 + /* PPP section */ 524 + enum { 525 + IFLA_PPP_UNSPEC, 526 + IFLA_PPP_DEV_FD, 527 + __IFLA_PPP_MAX 528 + }; 529 + #define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1) 530 + 523 531 /* Bonding section */ 524 532 525 533 enum {