简体   繁体   English

在Linux内核3.12中调用网络设备驱动程序时,“设备不适当的ioctl”

[英]“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. 我正在尝试将ioctl接口添加到Linux内核3.12中的CAN驱动程序中,这是一个网络设备。

I have added ioctl handling to the driver in this way 我已经以这种方式向驱动程序添加了ioctl处理

#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). 我已经验证CANConfig [hndl] .s是一个整数,该整数将评估进入CAN驱动程序(即CAN0)的通道的打开文件描述符。 In fact this ioctl call elsewhere in the code does work 实际上,此ioctl调用在代码的其他地方确实有效

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

The response is always ENOTTY AKA "Inappropriate ioctl for device" 响应始终是ENOTTY AKA“设备的ioctl不正确”

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. 似乎自定义ioctl并未真正注册,因此内核在曾经在驱动程序中调用自定义ioctl代码之前就拒绝了用户空间ioctl调用。 The built in ioctls for net devices such as SIOCGIFINDEX work as expected. 用于SIOCGIFINDEX等网络设备的内置ioctl可以正常工作。

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. 我可以看到的两件事看起来似乎是错误的,但显然不是:(1)c_can_ioctl()定义的第三个参数应为无符号长整数,但应为int。 It seems that the net device ioctl interface does not conform to the ioctl interface for non net devices. 似乎网络设备的ioctl接口与非网络设备的ioctl接口不一致。 And (2) there is a .ndo_do_ioctl slot in the net_device_ops structure but there is no .ndo_do_unlocked_ioctl. (2)net_device_ops结构中有一个.ndo_do_ioctl插槽,但没有.ndo_do_unlocked_ioctl。

Your ndo_do_ioctl is called from core/dev.c, there look for: 您的ndo_do_ioctl是从core / dev.c调用的,在那里寻找:

ndo_do_ioctl is called under the following conditions: 在以下条件下调用ndo_do_ioctl

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. 因此,要么必须执行指定的cmd之一,要么执行SIOCDEVPRIVATE和SIOCDEVPRIVATE + 15之间的某个操作。

Hope this helps :^) 希望这会有所帮助:^)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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