* [PATCH 1/9] ipv4: streamline ipmr_new_tunnel
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 11:46 ` [PATCH 2/9] ipv4: consolidate the VIFF_TUNNEL handling in ipmr_new_tunnel Christoph Hellwig
` (7 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
Reduce a few level of indentation to simplify the function.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv4/ipmr.c | 73 ++++++++++++++++++++++++-------------------------
1 file changed, 36 insertions(+), 37 deletions(-)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 5c218db2dede7..a1169b6941134 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -471,50 +471,49 @@ static bool ipmr_init_vif_indev(const struct net_device *dev)
static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
{
- struct net_device *dev;
+ struct net_device *tunnel_dev, *new_dev;
+ struct ip_tunnel_parm p = { };
+ mm_segment_t oldfs = get_fs();
+ struct ifreq ifr;
+ int err;
- dev = __dev_get_by_name(net, "tunl0");
+ tunnel_dev = __dev_get_by_name(net, "tunl0");
+ if (!tunnel_dev)
+ goto out;
- if (dev) {
- const struct net_device_ops *ops = dev->netdev_ops;
- int err;
- struct ifreq ifr;
- struct ip_tunnel_parm p;
+ p.iph.daddr = v->vifc_rmt_addr.s_addr;
+ p.iph.saddr = v->vifc_lcl_addr.s_addr;
+ p.iph.version = 4;
+ p.iph.ihl = 5;
+ p.iph.protocol = IPPROTO_IPIP;
+ sprintf(p.name, "dvmrp%d", v->vifc_vifi);
+ ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
- memset(&p, 0, sizeof(p));
- p.iph.daddr = v->vifc_rmt_addr.s_addr;
- p.iph.saddr = v->vifc_lcl_addr.s_addr;
- p.iph.version = 4;
- p.iph.ihl = 5;
- p.iph.protocol = IPPROTO_IPIP;
- sprintf(p.name, "dvmrp%d", v->vifc_vifi);
- ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
+ if (!tunnel_dev->netdev_ops->ndo_do_ioctl)
+ goto out;
- if (ops->ndo_do_ioctl) {
- mm_segment_t oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ err = tunnel_dev->netdev_ops->ndo_do_ioctl(tunnel_dev, &ifr,
+ SIOCADDTUNNEL);
+ set_fs(oldfs);
+ if (err)
+ goto out;
- set_fs(KERNEL_DS);
- err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
- set_fs(oldfs);
- } else {
- err = -EOPNOTSUPP;
- }
- dev = NULL;
+ new_dev = __dev_get_by_name(net, p.name);
+ if (!new_dev)
+ goto out;
- if (err == 0 &&
- (dev = __dev_get_by_name(net, p.name)) != NULL) {
- dev->flags |= IFF_MULTICAST;
- if (!ipmr_init_vif_indev(dev))
- goto failure;
- if (dev_open(dev, NULL))
- goto failure;
- dev_hold(dev);
- }
- }
- return dev;
+ new_dev->flags |= IFF_MULTICAST;
+ if (!ipmr_init_vif_indev(new_dev))
+ goto out_unregister;
+ if (dev_open(new_dev, NULL))
+ goto out_unregister;
+ dev_hold(new_dev);
+ return new_dev;
-failure:
- unregister_netdevice(dev);
+out_unregister:
+ unregister_netdevice(new_dev);
+out:
return NULL;
}
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/9] ipv4: consolidate the VIFF_TUNNEL handling in ipmr_new_tunnel
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
2020-05-18 11:46 ` [PATCH 1/9] ipv4: streamline ipmr_new_tunnel Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 11:46 ` [PATCH 3/9] net: add a new ndo_tunnel_ioctl method Christoph Hellwig
` (6 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
Also move the dev_set_allmulti call and the error handling into the
ioctl helper. This allows reusing already looked up tunnel_dev pointer
and the set up argument structure for the deletion in the error handler.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv4/ipmr.c | 53 ++++++++++++-------------------------------------
1 file changed, 13 insertions(+), 40 deletions(-)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index a1169b6941134..cd1a3260a99af 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -421,37 +421,6 @@ static void ipmr_free_table(struct mr_table *mrt)
/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
-static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
-{
- struct net *net = dev_net(dev);
-
- dev_close(dev);
-
- dev = __dev_get_by_name(net, "tunl0");
- if (dev) {
- const struct net_device_ops *ops = dev->netdev_ops;
- struct ifreq ifr;
- struct ip_tunnel_parm p;
-
- memset(&p, 0, sizeof(p));
- p.iph.daddr = v->vifc_rmt_addr.s_addr;
- p.iph.saddr = v->vifc_lcl_addr.s_addr;
- p.iph.version = 4;
- p.iph.ihl = 5;
- p.iph.protocol = IPPROTO_IPIP;
- sprintf(p.name, "dvmrp%d", v->vifc_vifi);
- ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
-
- if (ops->ndo_do_ioctl) {
- mm_segment_t oldfs = get_fs();
-
- set_fs(KERNEL_DS);
- ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
- set_fs(oldfs);
- }
- }
-}
-
/* Initialize ipmr pimreg/tunnel in_device */
static bool ipmr_init_vif_indev(const struct net_device *dev)
{
@@ -509,12 +478,22 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
if (dev_open(new_dev, NULL))
goto out_unregister;
dev_hold(new_dev);
+ err = dev_set_allmulti(new_dev, 1);
+ if (err) {
+ dev_close(new_dev);
+ set_fs(KERNEL_DS);
+ tunnel_dev->netdev_ops->ndo_do_ioctl(tunnel_dev, &ifr,
+ SIOCDELTUNNEL);
+ set_fs(oldfs);
+ dev_put(new_dev);
+ new_dev = ERR_PTR(err);
+ }
return new_dev;
out_unregister:
unregister_netdevice(new_dev);
out:
- return NULL;
+ return ERR_PTR(-ENOBUFS);
}
#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
@@ -866,14 +845,8 @@ static int vif_add(struct net *net, struct mr_table *mrt,
break;
case VIFF_TUNNEL:
dev = ipmr_new_tunnel(net, vifc);
- if (!dev)
- return -ENOBUFS;
- err = dev_set_allmulti(dev, 1);
- if (err) {
- ipmr_del_tunnel(dev, vifc);
- dev_put(dev);
- return err;
- }
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
break;
case VIFF_USE_IFINDEX:
case 0:
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/9] net: add a new ndo_tunnel_ioctl method
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
2020-05-18 11:46 ` [PATCH 1/9] ipv4: streamline ipmr_new_tunnel Christoph Hellwig
2020-05-18 11:46 ` [PATCH 2/9] ipv4: consolidate the VIFF_TUNNEL handling in ipmr_new_tunnel Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 11:46 ` [PATCH 4/9] impr: use ->ndo_tunnel_ctl in ipmr_new_tunnel Christoph Hellwig
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
This method is used to properly allow kernel callers of the IPv4 route
management ioctls. The exsting ip_tunnel_ioctl helper is renamed to
ip_tunnel_ctl to better reflect that it doesn't directly implement ioctls
touching user memory, and is used for the guts of ndo_tunnel_ctl
implementations. A new ip_tunnel_ioctl helper is added that can be wired
up directly to the ndo_do_ioctl method and takes care of the copy to and
from userspace.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/netdevice.h | 6 ++++++
include/net/ip_tunnels.h | 3 ++-
net/ipv4/ip_gre.c | 35 ++++++++++++++---------------------
net/ipv4/ip_tunnel.c | 16 +++++++++++++++-
net/ipv4/ip_vti.c | 32 +++++++++++++-------------------
net/ipv4/ipip.c | 30 +++++++++---------------------
6 files changed, 59 insertions(+), 63 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 6a8f8daef09df..a18f8fdf4260a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -53,6 +53,7 @@ struct netpoll_info;
struct device;
struct phy_device;
struct dsa_port;
+struct ip_tunnel_parm;
struct macsec_context;
struct macsec_ops;
@@ -1274,6 +1275,9 @@ struct netdev_net_notifier {
* Get devlink port instance associated with a given netdev.
* Called with a reference on the netdevice and devlink locks only,
* rtnl_lock is not held.
+ * int (*ndo_tunnel_ctl)(struct net_device *dev, struct ip_tunnel_parm *p,
+ * int cmd);
+ * Add, change, delete or get information on an IPv4 tunnel.
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
@@ -1479,6 +1483,8 @@ struct net_device_ops {
int (*ndo_xsk_wakeup)(struct net_device *dev,
u32 queue_id, u32 flags);
struct devlink_port * (*ndo_get_devlink_port)(struct net_device *dev);
+ int (*ndo_tunnel_ctl)(struct net_device *dev,
+ struct ip_tunnel_parm *p, int cmd);
};
/**
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 236503a50759a..076e5d7db7d3c 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -269,7 +269,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
const struct iphdr *tnl_params, const u8 protocol);
void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
const u8 proto, int tunnel_hlen);
-int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
+int ip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
+int ip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict);
int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 0ce9b91ff55c0..4e31f23e4117e 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -768,45 +768,37 @@ static void ipgre_link_update(struct net_device *dev, bool set_mtu)
}
}
-static int ipgre_tunnel_ioctl(struct net_device *dev,
- struct ifreq *ifr, int cmd)
+static int ipgre_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p,
+ int cmd)
{
- struct ip_tunnel_parm p;
int err;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- return -EFAULT;
-
if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
- if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
- p.iph.ihl != 5 || (p.iph.frag_off & htons(~IP_DF)) ||
- ((p.i_flags | p.o_flags) & (GRE_VERSION | GRE_ROUTING)))
+ if (p->iph.version != 4 || p->iph.protocol != IPPROTO_GRE ||
+ p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)) ||
+ ((p->i_flags | p->o_flags) & (GRE_VERSION | GRE_ROUTING)))
return -EINVAL;
}
- p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
- p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
+ p->i_flags = gre_flags_to_tnl_flags(p->i_flags);
+ p->o_flags = gre_flags_to_tnl_flags(p->o_flags);
- err = ip_tunnel_ioctl(dev, &p, cmd);
+ err = ip_tunnel_ctl(dev, p, cmd);
if (err)
return err;
if (cmd == SIOCCHGTUNNEL) {
struct ip_tunnel *t = netdev_priv(dev);
- t->parms.i_flags = p.i_flags;
- t->parms.o_flags = p.o_flags;
+ t->parms.i_flags = p->i_flags;
+ t->parms.o_flags = p->o_flags;
if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
ipgre_link_update(dev, true);
}
- p.i_flags = gre_tnl_flags_to_gre_flags(p.i_flags);
- p.o_flags = gre_tnl_flags_to_gre_flags(p.o_flags);
-
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- return -EFAULT;
-
+ p->i_flags = gre_tnl_flags_to_gre_flags(p->i_flags);
+ p->o_flags = gre_tnl_flags_to_gre_flags(p->o_flags);
return 0;
}
@@ -924,10 +916,11 @@ static const struct net_device_ops ipgre_netdev_ops = {
.ndo_stop = ipgre_close,
#endif
.ndo_start_xmit = ipgre_xmit,
- .ndo_do_ioctl = ipgre_tunnel_ioctl,
+ .ndo_do_ioctl = ip_tunnel_ioctl,
.ndo_change_mtu = ip_tunnel_change_mtu,
.ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink,
+ .ndo_tunnel_ctl = ipgre_tunnel_ctl,
};
#define GRE_FEATURES (NETIF_F_SG | \
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index cd4b84310d929..f4f1d11eab502 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -860,7 +860,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
netdev_state_change(dev);
}
-int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
+int ip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
{
int err = 0;
struct ip_tunnel *t = netdev_priv(dev);
@@ -960,6 +960,20 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
done:
return err;
}
+EXPORT_SYMBOL_GPL(ip_tunnel_ctl);
+
+int ip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ip_tunnel_parm p;
+ int err;
+
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
+ err = dev->netdev_ops->ndo_tunnel_ctl(dev, &p, cmd);
+ if (!err && copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+ return -EFAULT;
+ return err;
+}
EXPORT_SYMBOL_GPL(ip_tunnel_ioctl);
int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 1b4e6f298648d..c8974360a99f4 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -378,38 +378,31 @@ static int vti4_err(struct sk_buff *skb, u32 info)
}
static int
-vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+vti_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
{
int err = 0;
- struct ip_tunnel_parm p;
-
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- return -EFAULT;
if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
- if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
- p.iph.ihl != 5)
+ if (p->iph.version != 4 || p->iph.protocol != IPPROTO_IPIP ||
+ p->iph.ihl != 5)
return -EINVAL;
}
- if (!(p.i_flags & GRE_KEY))
- p.i_key = 0;
- if (!(p.o_flags & GRE_KEY))
- p.o_key = 0;
+ if (!(p->i_flags & GRE_KEY))
+ p->i_key = 0;
+ if (!(p->o_flags & GRE_KEY))
+ p->o_key = 0;
- p.i_flags = VTI_ISVTI;
+ p->i_flags = VTI_ISVTI;
- err = ip_tunnel_ioctl(dev, &p, cmd);
+ err = ip_tunnel_ctl(dev, p, cmd);
if (err)
return err;
if (cmd != SIOCDELTUNNEL) {
- p.i_flags |= GRE_KEY;
- p.o_flags |= GRE_KEY;
+ p->i_flags |= GRE_KEY;
+ p->o_flags |= GRE_KEY;
}
-
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- return -EFAULT;
return 0;
}
@@ -417,10 +410,11 @@ static const struct net_device_ops vti_netdev_ops = {
.ndo_init = vti_tunnel_init,
.ndo_uninit = ip_tunnel_uninit,
.ndo_start_xmit = vti_tunnel_xmit,
- .ndo_do_ioctl = vti_tunnel_ioctl,
+ .ndo_do_ioctl = ip_tunnel_ioctl,
.ndo_change_mtu = ip_tunnel_change_mtu,
.ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink,
+ .ndo_tunnel_ctl = vti_tunnel_ctl,
};
static void vti_tunnel_setup(struct net_device *dev)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 2f01cf6fa0def..df663baf2516a 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -327,41 +327,29 @@ static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto)
}
static int
-ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ipip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
{
- int err = 0;
- struct ip_tunnel_parm p;
-
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- return -EFAULT;
-
if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
- if (p.iph.version != 4 ||
- !ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) ||
- p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
+ if (p->iph.version != 4 ||
+ !ipip_tunnel_ioctl_verify_protocol(p->iph.protocol) ||
+ p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)))
return -EINVAL;
}
- p.i_key = p.o_key = 0;
- p.i_flags = p.o_flags = 0;
- err = ip_tunnel_ioctl(dev, &p, cmd);
- if (err)
- return err;
-
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- return -EFAULT;
-
- return 0;
+ p->i_key = p->o_key = 0;
+ p->i_flags = p->o_flags = 0;
+ return ip_tunnel_ctl(dev, p, cmd);
}
static const struct net_device_ops ipip_netdev_ops = {
.ndo_init = ipip_tunnel_init,
.ndo_uninit = ip_tunnel_uninit,
.ndo_start_xmit = ipip_tunnel_xmit,
- .ndo_do_ioctl = ipip_tunnel_ioctl,
+ .ndo_do_ioctl = ip_tunnel_ioctl,
.ndo_change_mtu = ip_tunnel_change_mtu,
.ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink,
+ .ndo_tunnel_ctl = ipip_tunnel_ctl,
};
#define IPIP_FEATURES (NETIF_F_SG | \
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/9] impr: use ->ndo_tunnel_ctl in ipmr_new_tunnel
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
` (2 preceding siblings ...)
2020-05-18 11:46 ` [PATCH 3/9] net: add a new ndo_tunnel_ioctl method Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 11:46 ` [PATCH 5/9] sit: refactor ipip6_tunnel_ioctl Christoph Hellwig
` (4 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
Use the new ->ndo_tunnel_ctl instead of overriding the address limit
and using ->ndo_do_ioctl just to do a pointless user copy.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv4/ipmr.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index cd1a3260a99af..d3e9b80a57de2 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -442,8 +442,6 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
{
struct net_device *tunnel_dev, *new_dev;
struct ip_tunnel_parm p = { };
- mm_segment_t oldfs = get_fs();
- struct ifreq ifr;
int err;
tunnel_dev = __dev_get_by_name(net, "tunl0");
@@ -456,15 +454,11 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
p.iph.ihl = 5;
p.iph.protocol = IPPROTO_IPIP;
sprintf(p.name, "dvmrp%d", v->vifc_vifi);
- ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
- if (!tunnel_dev->netdev_ops->ndo_do_ioctl)
+ if (!tunnel_dev->netdev_ops->ndo_tunnel_ctl)
goto out;
-
- set_fs(KERNEL_DS);
- err = tunnel_dev->netdev_ops->ndo_do_ioctl(tunnel_dev, &ifr,
+ err = tunnel_dev->netdev_ops->ndo_tunnel_ctl(tunnel_dev, &p,
SIOCADDTUNNEL);
- set_fs(oldfs);
if (err)
goto out;
@@ -481,10 +475,8 @@ static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
err = dev_set_allmulti(new_dev, 1);
if (err) {
dev_close(new_dev);
- set_fs(KERNEL_DS);
- tunnel_dev->netdev_ops->ndo_do_ioctl(tunnel_dev, &ifr,
+ tunnel_dev->netdev_ops->ndo_tunnel_ctl(tunnel_dev, &p,
SIOCDELTUNNEL);
- set_fs(oldfs);
dev_put(new_dev);
new_dev = ERR_PTR(err);
}
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/9] sit: refactor ipip6_tunnel_ioctl
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
` (3 preceding siblings ...)
2020-05-18 11:46 ` [PATCH 4/9] impr: use ->ndo_tunnel_ctl in ipmr_new_tunnel Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 16:43 ` Jakub Kicinski
2020-05-18 11:46 ` [PATCH 6/9] sit: impement ->ndo_tunnel_ctl Christoph Hellwig
` (3 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
Split the ioctl handler into one function per command instead of having
a all the logic sit in one giant switch statement.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv6/sit.c | 368 ++++++++++++++++++++++++++++---------------------
1 file changed, 210 insertions(+), 158 deletions(-)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 98954830c40ba..2909b2c53eaad 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -83,6 +83,13 @@ struct sit_net {
struct net_device *fb_tunnel_dev;
};
+static inline struct sit_net *dev_to_sit_net(struct net_device *dev)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
+
+ return net_generic(t->net, sit_net_id);
+}
+
/*
* Must be invoked with rcu_read_lock
*/
@@ -291,14 +298,18 @@ __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
}
-static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
- struct ip_tunnel_prl __user *a)
+static int ipip6_tunnel_get_prl(struct net_device *dev, struct ifreq *ifr)
{
+ struct ip_tunnel_prl __user *a = ifr->ifr_ifru.ifru_data;
+ struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_prl kprl, *kp;
struct ip_tunnel_prl_entry *prl;
unsigned int cmax, c = 0, ca, len;
int ret = 0;
+ if (dev == dev_to_sit_net(dev)->fb_tunnel_dev)
+ return -EINVAL;
+
if (copy_from_user(&kprl, a, sizeof(kprl)))
return -EFAULT;
cmax = kprl.datalen / sizeof(kprl);
@@ -441,6 +452,35 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
return err;
}
+static int ipip6_tunnel_prl_ctl(struct net_device *dev, struct ifreq *ifr,
+ int cmd)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
+ struct ip_tunnel_prl prl;
+ int err;
+
+ if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+ if (dev == dev_to_sit_net(dev)->fb_tunnel_dev)
+ return -EINVAL;
+
+ if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case SIOCDELPRL:
+ err = ipip6_tunnel_del_prl(t, &prl);
+ break;
+ case SIOCADDPRL:
+ case SIOCCHGPRL:
+ err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
+ break;
+ }
+ dst_cache_reset(&t->dst_cache);
+ netdev_state_change(dev);
+ return 0;
+}
+
static int
isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t)
{
@@ -1151,7 +1191,53 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
netdev_state_change(t->dev);
return 0;
}
-#endif
+
+static int
+ipip6_tunnel_get6rd(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
+ struct ip_tunnel_6rd ip6rd;
+ struct ip_tunnel_parm p;
+
+ if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
+ t = ipip6_tunnel_locate(t->net, &p, 0);
+ }
+ if (!t)
+ t = netdev_priv(dev);
+
+ ip6rd.prefix = t->ip6rd.prefix;
+ ip6rd.relay_prefix = t->ip6rd.relay_prefix;
+ ip6rd.prefixlen = t->ip6rd.prefixlen;
+ ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, sizeof(ip6rd)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+ipip6_tunnel_6rdctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
+ struct ip_tunnel_6rd ip6rd;
+ int err;
+
+ if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data, sizeof(ip6rd)))
+ return -EFAULT;
+
+ if (cmd != SIOCDEL6RD) {
+ err = ipip6_tunnel_update_6rd(t, &ip6rd);
+ if (err < 0)
+ return err;
+ } else
+ ipip6_tunnel_clone_6rd(dev, dev_to_sit_net(dev));
+ return 0;
+}
+
+#endif /* CONFIG_IPV6_SIT_6RD */
static bool ipip6_valid_ip_proto(u8 ipproto)
{
@@ -1164,185 +1250,151 @@ static bool ipip6_valid_ip_proto(u8 ipproto)
}
static int
-ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+__ipip6_tunnel_ioctl_validate(struct net *net, struct ip_tunnel_parm *p)
{
- int err = 0;
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!ipip6_valid_ip_proto(p->iph.protocol))
+ return -EINVAL;
+ if (p->iph.version != 4 ||
+ p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)))
+ return -EINVAL;
+
+ if (p->iph.ttl)
+ p->iph.frag_off |= htons(IP_DF);
+ return 0;
+}
+
+static int
+ipip6_tunnel_get(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
struct ip_tunnel_parm p;
- struct ip_tunnel_prl prl;
+
+ if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
+ t = ipip6_tunnel_locate(t->net, &p, 0);
+ }
+ if (!t)
+ t = netdev_priv(dev);
+
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+ipip6_tunnel_add(struct net_device *dev, struct ifreq *ifr)
+{
struct ip_tunnel *t = netdev_priv(dev);
- struct net *net = t->net;
- struct sit_net *sitn = net_generic(net, sit_net_id);
-#ifdef CONFIG_IPV6_SIT_6RD
- struct ip_tunnel_6rd ip6rd;
-#endif
+ struct ip_tunnel_parm p;
+ int err;
- switch (cmd) {
- case SIOCGETTUNNEL:
-#ifdef CONFIG_IPV6_SIT_6RD
- case SIOCGET6RD:
-#endif
- if (dev == sitn->fb_tunnel_dev) {
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
- err = -EFAULT;
- break;
- }
- t = ipip6_tunnel_locate(net, &p, 0);
- if (!t)
- t = netdev_priv(dev);
- }
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
+ err = __ipip6_tunnel_ioctl_validate(t->net, &p);
+ if (err)
+ return err;
- err = -EFAULT;
- if (cmd == SIOCGETTUNNEL) {
- memcpy(&p, &t->parms, sizeof(p));
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p,
- sizeof(p)))
- goto done;
-#ifdef CONFIG_IPV6_SIT_6RD
+ t = ipip6_tunnel_locate(t->net, &p, 1);
+ if (!t)
+ return -ENOBUFS;
+
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+ipip6_tunnel_change(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
+ struct ip_tunnel_parm p;
+ int err;
+
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
+ err = __ipip6_tunnel_ioctl_validate(t->net, &p);
+ if (err)
+ return err;
+
+ t = ipip6_tunnel_locate(t->net, &p, 0);
+ if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
+ if (!t)
+ return -ENOENT;
+ } else {
+ if (t) {
+ if (t->dev != dev)
+ return -EEXIST;
} else {
- ip6rd.prefix = t->ip6rd.prefix;
- ip6rd.relay_prefix = t->ip6rd.relay_prefix;
- ip6rd.prefixlen = t->ip6rd.prefixlen;
- ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd,
- sizeof(ip6rd)))
- goto done;
-#endif
+ if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
+ (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
+ return -EINVAL;
+ t = netdev_priv(dev);
}
- err = 0;
- break;
- case SIOCADDTUNNEL:
- case SIOCCHGTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
+ ipip6_tunnel_update(t, &p, t->fwmark);
+ }
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
-
- err = -EINVAL;
- if (!ipip6_valid_ip_proto(p.iph.protocol))
- goto done;
- if (p.iph.version != 4 ||
- p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
- goto done;
- if (p.iph.ttl)
- p.iph.frag_off |= htons(IP_DF);
-
- t = ipip6_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
-
- if (dev != sitn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
- if (t) {
- if (t->dev != dev) {
- err = -EEXIST;
- break;
- }
- } else {
- if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) ||
- (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) {
- err = -EINVAL;
- break;
- }
- t = netdev_priv(dev);
- }
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
+ return -EFAULT;
+ return 0;
+}
- ipip6_tunnel_update(t, &p, t->fwmark);
- }
+static int
+ipip6_tunnel_del(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ip_tunnel *t = netdev_priv(dev);
+ struct ip_tunnel_parm p;
- if (t) {
- err = 0;
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
- err = -EFAULT;
- } else
- err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
- break;
+ if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
- case SIOCDELTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- if (dev == sitn->fb_tunnel_dev) {
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
- err = -ENOENT;
- t = ipip6_tunnel_locate(net, &p, 0);
- if (!t)
- goto done;
- err = -EPERM;
- if (t == netdev_priv(sitn->fb_tunnel_dev))
- goto done;
- dev = t->dev;
- }
- unregister_netdevice(dev);
- err = 0;
- break;
+ if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
+ t = ipip6_tunnel_locate(t->net, &p, 0);
+ if (!t)
+ return -ENOENT;
+ if (t == netdev_priv(dev_to_sit_net(dev)->fb_tunnel_dev))
+ return -EPERM;
+ dev = t->dev;
+ }
+ unregister_netdevice(dev);
+ return 0;
+}
+static int
+ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ return ipip6_tunnel_get(dev, ifr);
+ case SIOCADDTUNNEL:
+ return ipip6_tunnel_add(dev, ifr);
+ case SIOCCHGTUNNEL:
+ return ipip6_tunnel_change(dev, ifr);
+ case SIOCDELTUNNEL:
+ return ipip6_tunnel_del(dev, ifr);
case SIOCGETPRL:
- err = -EINVAL;
- if (dev == sitn->fb_tunnel_dev)
- goto done;
- err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data);
- break;
-
+ return ipip6_tunnel_get_prl(dev, ifr);
case SIOCADDPRL:
case SIOCDELPRL:
case SIOCCHGPRL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
- err = -EINVAL;
- if (dev == sitn->fb_tunnel_dev)
- goto done;
- err = -EFAULT;
- if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl)))
- goto done;
-
- switch (cmd) {
- case SIOCDELPRL:
- err = ipip6_tunnel_del_prl(t, &prl);
- break;
- case SIOCADDPRL:
- case SIOCCHGPRL:
- err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
- break;
- }
- dst_cache_reset(&t->dst_cache);
- netdev_state_change(dev);
- break;
-
+ return ipip6_tunnel_prl_ctl(dev, ifr, cmd);
#ifdef CONFIG_IPV6_SIT_6RD
+ case SIOCGET6RD:
+ return ipip6_tunnel_get6rd(dev, ifr);
case SIOCADD6RD:
case SIOCCHG6RD:
case SIOCDEL6RD:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- err = -EFAULT;
- if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data,
- sizeof(ip6rd)))
- goto done;
-
- if (cmd != SIOCDEL6RD) {
- err = ipip6_tunnel_update_6rd(t, &ip6rd);
- if (err < 0)
- goto done;
- } else
- ipip6_tunnel_clone_6rd(dev, sitn);
-
- err = 0;
- break;
+ return ipip6_tunnel_6rdctl(dev, ifr, cmd);
#endif
-
default:
- err = -EINVAL;
+ return -EINVAL;
}
-
-done:
- return err;
}
static const struct net_device_ops ipip6_netdev_ops = {
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9] sit: refactor ipip6_tunnel_ioctl
2020-05-18 11:46 ` [PATCH 5/9] sit: refactor ipip6_tunnel_ioctl Christoph Hellwig
@ 2020-05-18 16:43 ` Jakub Kicinski
2020-05-18 16:47 ` Christoph Hellwig
0 siblings, 1 reply; 14+ messages in thread
From: Jakub Kicinski @ 2020-05-18 16:43 UTC (permalink / raw)
To: Christoph Hellwig
Cc: David S. Miller, Alexey Kuznetsov, Hideaki YOSHIFUJI,
Steffen Klassert, Herbert Xu, netdev, linux-kernel
On Mon, 18 May 2020 13:46:51 +0200 Christoph Hellwig wrote:
> Split the ioctl handler into one function per command instead of having
> a all the logic sit in one giant switch statement.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
net/ipv6/sit.c: In function ipip6_tunnel_prl_ctl:
net/ipv6/sit.c:460:6: warning: variable err set but not used [-Wunused-but-set-variable]
460 | int err;
| ^~~
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9] sit: refactor ipip6_tunnel_ioctl
2020-05-18 16:43 ` Jakub Kicinski
@ 2020-05-18 16:47 ` Christoph Hellwig
2020-05-18 17:18 ` Jakub Kicinski
0 siblings, 1 reply; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 16:47 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Christoph Hellwig, David S. Miller, Alexey Kuznetsov,
Hideaki YOSHIFUJI, Steffen Klassert, Herbert Xu, netdev,
linux-kernel
On Mon, May 18, 2020 at 09:43:56AM -0700, Jakub Kicinski wrote:
> On Mon, 18 May 2020 13:46:51 +0200 Christoph Hellwig wrote:
> > Split the ioctl handler into one function per command instead of having
> > a all the logic sit in one giant switch statement.
> >
> > Signed-off-by: Christoph Hellwig <hch@lst.de>
>
> net/ipv6/sit.c: In function ipip6_tunnel_prl_ctl:
> net/ipv6/sit.c:460:6: warning: variable err set but not used [-Wunused-but-set-variable]
> 460 | int err;
The warning looks correct, although my compiler doesn't report it :(
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/9] sit: refactor ipip6_tunnel_ioctl
2020-05-18 16:47 ` Christoph Hellwig
@ 2020-05-18 17:18 ` Jakub Kicinski
0 siblings, 0 replies; 14+ messages in thread
From: Jakub Kicinski @ 2020-05-18 17:18 UTC (permalink / raw)
To: Christoph Hellwig
Cc: David S. Miller, Alexey Kuznetsov, Hideaki YOSHIFUJI,
Steffen Klassert, Herbert Xu, netdev, linux-kernel
On Mon, 18 May 2020 18:47:25 +0200 Christoph Hellwig wrote:
> On Mon, May 18, 2020 at 09:43:56AM -0700, Jakub Kicinski wrote:
> > On Mon, 18 May 2020 13:46:51 +0200 Christoph Hellwig wrote:
> > > Split the ioctl handler into one function per command instead of having
> > > a all the logic sit in one giant switch statement.
> > >
> > > Signed-off-by: Christoph Hellwig <hch@lst.de>
> >
> > net/ipv6/sit.c: In function ipip6_tunnel_prl_ctl:
> > net/ipv6/sit.c:460:6: warning: variable err set but not used [-Wunused-but-set-variable]
> > 460 | int err;
>
> The warning looks correct, although my compiler doesn't report it :(
W=1, sorry, should've mentioned that!
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 6/9] sit: impement ->ndo_tunnel_ctl
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
` (4 preceding siblings ...)
2020-05-18 11:46 ` [PATCH 5/9] sit: refactor ipip6_tunnel_ioctl Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 11:46 ` [PATCH 7/9] ipv6: stub out even more of addrconf_set_dstaddr if SIT is disabled Christoph Hellwig
` (2 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
Implement the ->ndo_tunnel_ctl method, and use ip_tunnel_ioctl to
handle userspace requests for the SIOCGETTUNNEL, SIOCADDTUNNEL,
SIOCCHGTUNNEL and SIOCDELTUNNEL ioctls.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv6/sit.c | 73 +++++++++++++++++++++++---------------------------
1 file changed, 34 insertions(+), 39 deletions(-)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 2909b2c53eaad..8a08e4c4ebbbb 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1267,60 +1267,45 @@ __ipip6_tunnel_ioctl_validate(struct net *net, struct ip_tunnel_parm *p)
}
static int
-ipip6_tunnel_get(struct net_device *dev, struct ifreq *ifr)
+ipip6_tunnel_get(struct net_device *dev, struct ip_tunnel_parm *p)
{
struct ip_tunnel *t = netdev_priv(dev);
- struct ip_tunnel_parm p;
- if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- return -EFAULT;
- t = ipip6_tunnel_locate(t->net, &p, 0);
- }
+ if (dev == dev_to_sit_net(dev)->fb_tunnel_dev)
+ t = ipip6_tunnel_locate(t->net, p, 0);
if (!t)
t = netdev_priv(dev);
-
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
- return -EFAULT;
+ memcpy(p, &t->parms, sizeof(*p));
return 0;
}
static int
-ipip6_tunnel_add(struct net_device *dev, struct ifreq *ifr)
+ipip6_tunnel_add(struct net_device *dev, struct ip_tunnel_parm *p)
{
struct ip_tunnel *t = netdev_priv(dev);
- struct ip_tunnel_parm p;
int err;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- return -EFAULT;
- err = __ipip6_tunnel_ioctl_validate(t->net, &p);
+ err = __ipip6_tunnel_ioctl_validate(t->net, p);
if (err)
return err;
- t = ipip6_tunnel_locate(t->net, &p, 1);
+ t = ipip6_tunnel_locate(t->net, p, 1);
if (!t)
return -ENOBUFS;
-
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
- return -EFAULT;
return 0;
}
static int
-ipip6_tunnel_change(struct net_device *dev, struct ifreq *ifr)
+ipip6_tunnel_change(struct net_device *dev, struct ip_tunnel_parm *p)
{
struct ip_tunnel *t = netdev_priv(dev);
- struct ip_tunnel_parm p;
int err;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- return -EFAULT;
- err = __ipip6_tunnel_ioctl_validate(t->net, &p);
+ err = __ipip6_tunnel_ioctl_validate(t->net, p);
if (err)
return err;
- t = ipip6_tunnel_locate(t->net, &p, 0);
+ t = ipip6_tunnel_locate(t->net, p, 0);
if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
if (!t)
return -ENOENT;
@@ -1329,33 +1314,28 @@ ipip6_tunnel_change(struct net_device *dev, struct ifreq *ifr)
if (t->dev != dev)
return -EEXIST;
} else {
- if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
- (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
+ if (((dev->flags & IFF_POINTOPOINT) && !p->iph.daddr) ||
+ (!(dev->flags & IFF_POINTOPOINT) && p->iph.daddr))
return -EINVAL;
t = netdev_priv(dev);
}
- ipip6_tunnel_update(t, &p, t->fwmark);
+ ipip6_tunnel_update(t, p, t->fwmark);
}
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
- return -EFAULT;
return 0;
}
static int
-ipip6_tunnel_del(struct net_device *dev, struct ifreq *ifr)
+ipip6_tunnel_del(struct net_device *dev, struct ip_tunnel_parm *p)
{
struct ip_tunnel *t = netdev_priv(dev);
- struct ip_tunnel_parm p;
if (!ns_capable(t->net->user_ns, CAP_NET_ADMIN))
return -EPERM;
if (dev == dev_to_sit_net(dev)->fb_tunnel_dev) {
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- return -EFAULT;
- t = ipip6_tunnel_locate(t->net, &p, 0);
+ t = ipip6_tunnel_locate(t->net, p, 0);
if (!t)
return -ENOENT;
if (t == netdev_priv(dev_to_sit_net(dev)->fb_tunnel_dev))
@@ -1366,18 +1346,32 @@ ipip6_tunnel_del(struct net_device *dev, struct ifreq *ifr)
return 0;
}
+static int
+ipip6_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
+{
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ return ipip6_tunnel_get(dev, p);
+ case SIOCADDTUNNEL:
+ return ipip6_tunnel_add(dev, p);
+ case SIOCCHGTUNNEL:
+ return ipip6_tunnel_change(dev, p);
+ case SIOCDELTUNNEL:
+ return ipip6_tunnel_del(dev, p);
+ default:
+ return -EINVAL;
+ }
+}
+
static int
ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
switch (cmd) {
case SIOCGETTUNNEL:
- return ipip6_tunnel_get(dev, ifr);
case SIOCADDTUNNEL:
- return ipip6_tunnel_add(dev, ifr);
case SIOCCHGTUNNEL:
- return ipip6_tunnel_change(dev, ifr);
case SIOCDELTUNNEL:
- return ipip6_tunnel_del(dev, ifr);
+ return ip_tunnel_ioctl(dev, ifr, cmd);
case SIOCGETPRL:
return ipip6_tunnel_get_prl(dev, ifr);
case SIOCADDPRL:
@@ -1404,6 +1398,7 @@ static const struct net_device_ops ipip6_netdev_ops = {
.ndo_do_ioctl = ipip6_tunnel_ioctl,
.ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink,
+ .ndo_tunnel_ctl = ipip6_tunnel_ctl,
};
static void ipip6_dev_free(struct net_device *dev)
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 7/9] ipv6: stub out even more of addrconf_set_dstaddr if SIT is disabled
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
` (5 preceding siblings ...)
2020-05-18 11:46 ` [PATCH 6/9] sit: impement ->ndo_tunnel_ctl Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 11:46 ` [PATCH 8/9] ipv6: streamline addrconf_set_dstaddr Christoph Hellwig
2020-05-18 11:46 ` [PATCH 9/9] ipv6: use ->ndo_tunnel_ctl in addrconf_set_dstaddr Christoph Hellwig
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
There is no point in copying the structure from userspace or looking up
a device if SIT support is not disabled and we'll eventually return
-ENODEV anyway.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv6/addrconf.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ab7e839753aed..8300176f91e74 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2794,6 +2794,9 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg)
struct net_device *dev;
int err = -EINVAL;
+ if (!IS_ENABLED(CONFIG_IPV6_SIT))
+ return -ENODEV;
+
rtnl_lock();
err = -EFAULT;
@@ -2806,7 +2809,6 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg)
if (!dev)
goto err_exit;
-#if IS_ENABLED(CONFIG_IPV6_SIT)
if (dev->type == ARPHRD_SIT) {
const struct net_device_ops *ops = dev->netdev_ops;
struct ifreq ifr;
@@ -2842,7 +2844,6 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg)
err = dev_open(dev, NULL);
}
}
-#endif
err_exit:
rtnl_unlock();
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 8/9] ipv6: streamline addrconf_set_dstaddr
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
` (6 preceding siblings ...)
2020-05-18 11:46 ` [PATCH 7/9] ipv6: stub out even more of addrconf_set_dstaddr if SIT is disabled Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
2020-05-18 11:46 ` [PATCH 9/9] ipv6: use ->ndo_tunnel_ctl in addrconf_set_dstaddr Christoph Hellwig
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
Factor out a addrconf_set_sit_dstaddr helper for the actual work if we
found a SIT device, and only hold the rtnl lock around the device lookup
and that new helper, as there is no point in holding it over a
copy_from_user call.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv6/addrconf.c | 87 ++++++++++++++++++++-------------------------
1 file changed, 38 insertions(+), 49 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8300176f91e74..c827edf877414 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2783,6 +2783,38 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
in6_dev_put(in6_dev);
}
+static int addrconf_set_sit_dstaddr(struct net *net, struct net_device *dev,
+ struct in6_ifreq *ireq)
+{
+ struct ip_tunnel_parm p = { };
+ mm_segment_t oldfs = get_fs();
+ struct ifreq ifr;
+ int err;
+
+ if (!(ipv6_addr_type(&ireq->ifr6_addr) & IPV6_ADDR_COMPATv4))
+ return -EADDRNOTAVAIL;
+
+ p.iph.daddr = ireq->ifr6_addr.s6_addr32[3];
+ p.iph.version = 4;
+ p.iph.ihl = 5;
+ p.iph.protocol = IPPROTO_IPV6;
+ p.iph.ttl = 64;
+ ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
+
+ if (!dev->netdev_ops->ndo_do_ioctl)
+ return -EOPNOTSUPP;
+ set_fs(KERNEL_DS);
+ err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
+ set_fs(oldfs);
+ if (err)
+ return err;
+
+ dev = __dev_get_by_name(net, p.name);
+ if (!dev)
+ return -ENOBUFS;
+ return dev_open(dev, NULL);
+}
+
/*
* Set destination address.
* Special case for SIT interfaces where we create a new "virtual"
@@ -2790,62 +2822,19 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
*/
int addrconf_set_dstaddr(struct net *net, void __user *arg)
{
- struct in6_ifreq ireq;
struct net_device *dev;
- int err = -EINVAL;
+ struct in6_ifreq ireq;
+ int err = -ENODEV;
if (!IS_ENABLED(CONFIG_IPV6_SIT))
return -ENODEV;
-
- rtnl_lock();
-
- err = -EFAULT;
if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
- goto err_exit;
+ return -EFAULT;
+ rtnl_lock();
dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
-
- err = -ENODEV;
- if (!dev)
- goto err_exit;
-
- if (dev->type == ARPHRD_SIT) {
- const struct net_device_ops *ops = dev->netdev_ops;
- struct ifreq ifr;
- struct ip_tunnel_parm p;
-
- err = -EADDRNOTAVAIL;
- if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))
- goto err_exit;
-
- memset(&p, 0, sizeof(p));
- p.iph.daddr = ireq.ifr6_addr.s6_addr32[3];
- p.iph.saddr = 0;
- p.iph.version = 4;
- p.iph.ihl = 5;
- p.iph.protocol = IPPROTO_IPV6;
- p.iph.ttl = 64;
- ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
-
- if (ops->ndo_do_ioctl) {
- mm_segment_t oldfs = get_fs();
-
- set_fs(KERNEL_DS);
- err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
- set_fs(oldfs);
- } else
- err = -EOPNOTSUPP;
-
- if (err == 0) {
- err = -ENOBUFS;
- dev = __dev_get_by_name(net, p.name);
- if (!dev)
- goto err_exit;
- err = dev_open(dev, NULL);
- }
- }
-
-err_exit:
+ if (dev && dev->type == ARPHRD_SIT)
+ err = addrconf_set_sit_dstaddr(net, dev, &ireq);
rtnl_unlock();
return err;
}
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 9/9] ipv6: use ->ndo_tunnel_ctl in addrconf_set_dstaddr
2020-05-18 11:46 add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls Christoph Hellwig
` (7 preceding siblings ...)
2020-05-18 11:46 ` [PATCH 8/9] ipv6: streamline addrconf_set_dstaddr Christoph Hellwig
@ 2020-05-18 11:46 ` Christoph Hellwig
8 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2020-05-18 11:46 UTC (permalink / raw)
To: David S. Miller, Jakub Kicinski
Cc: Alexey Kuznetsov, Hideaki YOSHIFUJI, Steffen Klassert,
Herbert Xu, netdev, linux-kernel
Use the new ->ndo_tunnel_ctl instead of overriding the address limit
and using ->ndo_do_ioctl just to do a pointless user copy.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
net/ipv6/addrconf.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c827edf877414..09cfbf5dd7ce0 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2787,8 +2787,6 @@ static int addrconf_set_sit_dstaddr(struct net *net, struct net_device *dev,
struct in6_ifreq *ireq)
{
struct ip_tunnel_parm p = { };
- mm_segment_t oldfs = get_fs();
- struct ifreq ifr;
int err;
if (!(ipv6_addr_type(&ireq->ifr6_addr) & IPV6_ADDR_COMPATv4))
@@ -2799,13 +2797,10 @@ static int addrconf_set_sit_dstaddr(struct net *net, struct net_device *dev,
p.iph.ihl = 5;
p.iph.protocol = IPPROTO_IPV6;
p.iph.ttl = 64;
- ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
- if (!dev->netdev_ops->ndo_do_ioctl)
+ if (!dev->netdev_ops->ndo_tunnel_ctl)
return -EOPNOTSUPP;
- set_fs(KERNEL_DS);
- err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
- set_fs(oldfs);
+ err = dev->netdev_ops->ndo_tunnel_ctl(dev, &p, SIOCADDTUNNEL);
if (err)
return err;
--
2.26.2
^ permalink raw reply related [flat|nested] 14+ messages in thread