【问题标题】:"Inappropriate ioctl for device" when calling a net device driver in linux kernel 3.12在 linux 内核 3.12 中调用网络设备驱动程序时出现“设备不合适的 ioctl”
【发布时间】:2015-01-31 09:19:17
【问题描述】:

我正在尝试将 ioctl 接口添加到 Linux 内核 3.12 中的 CAN 驱动程序,这是一个网络设备。

我已经以这种方式向驱动程序添加了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;

我添加了调试以确保上述代码在驱动程序加载时实际执行。

然后在用户空间我有这段代码...

#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");
}

我已经验证 CANConfig[hndl].s 是一个整数,它评估为进入 CAN 驱动程序(即 CAN0)的通道的打开文件描述符。事实上,代码中其他地方的这个 ioctl 调用确实有效

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

响应始终是 ENOTTY AKA“设备不合适的 ioctl”

似乎自定义 ioctl 并未真正注册,因此内核在调用驱动程序中的自定义 ioctl 代码之前拒绝了用户空间 ioctl 调用。用于网络设备(如 SIOCGIFINDEX)的内置 ioctl 按预期工作。

谁能告诉我我在这里做错了什么?

我可以看到看起来有问题但显然不是的两件事是 (1) c_can_ioctl() 定义的第三个参数应该是一个无符号长整数,但它是一个整数。似乎网络设备ioctl接口不符合非网络设备的ioctl接口。并且 (2) net_device_ops 结构中有一个 .ndo_do_ioctl 插槽但没有 .ndo_do_unlocked_ioctl。

【问题讨论】:

  • 你试过让 C_CAN_SET_FILTERS 等于 SIOCDEVPRIVATE + 1 吗?

标签: linux linux-kernel ioctl


【解决方案1】:

你的 ndo_do_ioctl 是从 core/dev.c 调用的,在那里寻找:

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;
}

因此,要么您必须执行指定的 cmd 之一,要么执行 SIOCDEVPRIVATE 和 SIOCDEVPRIVATE+15 之间的某个命令。

希望这会有所帮助:^)

【讨论】:

    猜你喜欢
    • 2015-02-03
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 2017-03-02
    • 2019-03-10
    • 2011-07-29
    • 2010-12-08
    • 1970-01-01
    相关资源
    最近更新 更多