Search code examples
linux-kerneldriverioctl

Has there been any change between kernel 5.15 and 5.4.0 concerning ioctl valid commands?


We have some custom driver working on 5.4.0. It's pretty old and the original developers are no longer supporting it, so we have to maintain it in our systems. When upgrading to Ubuntu 22 (Kernel 5.15), the driver suddenly stopped working, and sending ioctl with the command SIOCDEVPRIVATE (which used to work in kernel 5.4.0, and in fact is used to get some necessary device information)now gives "ioctl: Operation not supported" error with no extra information anywhere on the logs.

So... has something changed between those two kernels? We did have to adapt some of the structures used to register the driver, but I can't see anything concerning registering valid operations there. Do I have to register valid operations somewhere now? Alternatively, does somebody know what part of the kernel code is checking for the operation to be supported? I've been trying to find it from ioctl.c, but I can't seem to find where that particular error comes from.

The driver code that supposedly takes care of this (doesn't even reach first line on 5.15):

static int u50_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) {
    struct u50_priv *priv = netdev_priv(dev);
    if (cmd == SIOCDEVPRIVATE) {
        memcpy(&ifr->ifr_data, priv->tty->name, strlen(priv->tty->name));
    }
    return 0;
}

And the attempt to access it that does no longer work:

    struct ifreq ifr = {0};
    struct ifaddrs *ifaddr, *ifa;
    getifaddrs(&ifaddr);
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
      memcpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
        if (ioctl(lonsd, SIOCDEVPRIVATE, &ifr) < 0) {
            perror("ioctl");
            syslog(LOG_ERR, "Ioctl:%d: %s\n", __LINE__, strerror(errno));
        }
...

and structure for registration

static const struct net_device_ops u50_netdev_ops = {
    .ndo_init = u50_dev_init,
    .ndo_uninit = u50_dev_uninit,
    .ndo_open = u50_dev_open,
    .ndo_stop = u50_dev_stop,
    .ndo_start_xmit = u50_dev_xmit,
    .ndo_do_ioctl = u50_dev_ioctl,
    .ndo_set_mac_address = U50SetHWAddr,
};

Solution

  • If you need some code to respond to SIOCDEVPRIVATE, you used to be able to do it via ndo_do_ioctl (writing a compatible function, then linking it in a net_device_ops struct in 5.4). However, in 5.15 it was changed so now you have to implement a ndo_siocdevprivate function, rather than ndo_do_ioctl, which is no longer called, according to the kernel documentation.

    source: https://elixir.bootlin.com/linux/v5.15.57/source/include/linux/netdevice.h

    Patch that did this: spinics.net/lists/netdev/msg698158.html