简体   繁体   中英

“Inappropriate ioctl for device” when calling a net device driver in linux kernel 3.12

I am trying to add an ioctl interface to the CAN driver in Linux kernel 3.12 which is a net device.

I have added ioctl handling to the driver in this way

#define C_CAN_SET_FILTERS      _IOW('z', 3, void *)

static int c_can_ioctl(struct net_device *dev, struct ifreq *ifr, int arg)
{
    switch (arg) 
    {
        case C_CAN_SET_FILTERS:
            netdev_err(dev, "CAN: ioctl C_CAN_SET_FILTERS called with arg %d\n", arg);
            break;
        default:
            netdev_err(dev, "CAN: ioctl called with invalid cmd\n");
    }
    return 0;
}

static const struct net_device_ops c_can_netdev_ops = {
    .ndo_open = c_can_open,
    .ndo_stop = c_can_close,
    .ndo_start_xmit = c_can_start_xmit,
    .ndo_do_ioctl = c_can_ioctl,
};

dev->netdev_ops = &c_can_netdev_ops;

I added debugging to make sure that the above code is actually executed when the driver loads and it is.

Then in userspace I have this code...

#define C_CAN_SET_FILTERS               _IOW('z', 3, void *)

if(ioctl(CANConfig[hndl].s, C_CAN_SET_FILTERS, &filterList) < 0) {
    perror("C_CAN install filters failed");
}

I have verified that CANConfig[hndl].s is an integer which evaluates to the open file descriptor for the channel into the CAN driver (ie CAN0). In fact this ioctl call elsewhere in the code does work

if(ioctl(CANConfig[hndl].s, SIOCGIFINDEX, &ifr) < 0)

The response is always ENOTTY AKA "Inappropriate ioctl for device"

It seems that the custom ioctl is not really being registered and so the kernel is rejecting the userspace ioctl call before ever calling the custom ioctl code in the driver. The built in ioctls for net devices such as SIOCGIFINDEX work as expected.

Can anyone please tell me what I am doing wrong here?

2 things that I can see that look wrong but apparently aren't are (1) the 3rd parameter to the c_can_ioctl() definition should be an unsigned long but is an int. It seems that the net device ioctl interface does not conform to the ioctl interface for non net devices. And (2) there is a .ndo_do_ioctl slot in the net_device_ops structure but there is no .ndo_do_unlocked_ioctl.

Your ndo_do_ioctl is called from core/dev.c, there look for:

ndo_do_ioctl is called under the following conditions:

static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) {
      /* Code Snipped */

      switch(cmd) {
      /* Code Snipped */

      default:       
            if ((cmd >= SIOCDEVPRIVATE &&
                cmd <= SIOCDEVPRIVATE + 15) ||
                cmd == SIOCBONDENSLAVE ||
                cmd == SIOCBONDRELEASE ||
                cmd == SIOCBONDSETHWADDR ||
                cmd == SIOCBONDSLAVEINFOQUERY ||
                cmd == SIOCBONDINFOQUERY ||
                cmd == SIOCBONDCHANGEACTIVE ||
                cmd == SIOCGMIIPHY ||
                cmd == SIOCGMIIREG ||
                cmd == SIOCSMIIREG ||
                cmd == SIOCBRADDIF ||
                cmd == SIOCBRDELIF ||
                cmd == SIOCSHWTSTAMP ||
                cmd == SIOCWANDEV) {
                    err = -EOPNOTSUPP;
                    if (ops->ndo_do_ioctl) {
                            if (netif_device_present(dev))
                                    err = ops->ndo_do_ioctl(dev, ifr, cmd);
                            else
                                    err = -ENODEV;
                    }
            } else
                    err = -EINVAL;

     } /* [end of switch] */
     return err;
}

So either you have to be executing one of the specified cmd or something between SIOCDEVPRIVATE and SIOCDEVPRIVATE+15.

Hope this helps :^)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM