net: split out SIOCDEVPRIVATE handling from dev_ioctl

SIOCDEVPRIVATE ioctl commands are mainly used in really old
drivers, and they have a number of problems:

- They hide behind the normal .ndo_do_ioctl function that
  is also used for other things in modern drivers, so it's
  hard to spot a driver that actually uses one of these

- Since drivers use a number different calling conventions,
  it is impossible to support compat mode for them in
  a generic way.

- With all drivers using the same 16 commands codes, there
  is no way to introspect the data being passed through
  things like strace.

Add a new net_device_ops callback pointer, to address the
first two of these. Separating them from .ndo_do_ioctl
makes it easy to grep for drivers with a .ndo_siocdevprivate
callback, and the unwieldy name hopefully makes it easier
to spot in code review.

By passing the ifreq structure and the ifr_data pointer
separately, it is no longer necessary to overload these,
and the driver can use either one for a given command.

Cc: Cong Wang <cong.wang@bytedance.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Arnd Bergmann 2021-07-27 15:44:47 +02:00 committed by David S. Miller
parent 2fba2eae30
commit b9067f5dc4
3 changed files with 32 additions and 3 deletions

View file

@ -259,6 +259,23 @@ static int dev_do_ioctl(struct net_device *dev,
return err;
}
static int dev_siocdevprivate(struct net_device *dev,
struct ifreq *ifr, unsigned int cmd)
{
const struct net_device_ops *ops = dev->netdev_ops;
void __user *data = ifr->ifr_data;
if (ops->ndo_siocdevprivate) {
if (netif_device_present(dev))
return ops->ndo_siocdevprivate(dev, ifr, data, cmd);
else
return -ENODEV;
}
/* fall back to do_ioctl for drivers not yet converted */
return dev_do_ioctl(dev, ifr, cmd);
}
/*
* Perform the SIOCxIFxxx calls, inside rtnl_lock()
*/
@ -336,9 +353,11 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
* Unknown or private ioctl
*/
default:
if ((cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) ||
cmd == SIOCBONDENSLAVE ||
if (cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15)
return dev_siocdevprivate(dev, ifr, cmd);
if (cmd == SIOCBONDENSLAVE ||
cmd == SIOCBONDRELEASE ||
cmd == SIOCBONDSETHWADDR ||
cmd == SIOCBONDSLAVEINFOQUERY ||