&引用;设备的ioctl不合适“;在linux内核3.12中调用网络设备驱动程序时

&引用;设备的ioctl不合适“;在linux内核3.12中调用网络设备驱动程序时,linux,linux-kernel,ioctl,Linux,Linux Kernel,Ioctl,我正在尝试向Linux内核3.12中的CAN驱动程序添加一个ioctl接口,这是一个网络设备 我以这种方式向驱动程序添加了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_FILT

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

我以这种方式向驱动程序添加了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");
}
#定义C#u可以#u设置#u过滤器#w('z',3,void*)
if(ioctl(CANConfig[hndl].s,C\u可以设置过滤器和过滤器列表)<0){
perror(“C_可安装过滤器失败”);
}
我已经验证了CANConfig[hndl].s是一个整数,其计算结果为进入CAN驱动程序的通道的打开文件描述符(即CAN0)。事实上,代码中其他地方的ioctl调用确实有效

if(ioctl(CANConfig[hndl].s, SIOCGIFINDEX, &ifr) < 0)
if(ioctl(CANConfig[hndl].s、SIOCGIFINDEX和ifr)<0)
响应总是ENOTTY,也称为“设备的ioctl不适当”

似乎定制ioctl没有真正注册,因此内核在调用驱动程序中的定制ioctl代码之前拒绝了userspace ioctl调用。用于网络设备(如SIOCGIFINDEX)的内置IOCTL工作正常

谁能告诉我我做错了什么


我可以看到两件看起来错误但显然不正确的事情:(1)c_can_ioctl()定义的第三个参数应该是无符号long,但却是int。对于非网络设备,网络设备ioctl接口似乎不符合ioctl接口。(2)在网络设备操作结构中有一个.ndo\u do\u ioctl插槽,但没有.ndo\u do\u unlocked\u ioctl。

您的ndo\u do\u ioctl是从core/dev.c调用的,您可以在其中查找:

在以下条件下调用
ndo\u do\u 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;
}
static int dev_ifsioc(struct net*net,struct ifreq*ifr,unsigned int cmd){
/*代码截取*/
开关(cmd){
/*代码截取*/
违约:
如果((cmd>=SIOCDEVPRIVATE&&
cmd ndo_do_ioctl){
如果(网络设备存在(开发))
err=ops->ndo\u do\u ioctl(dev、ifr、cmd);
其他的
err=-ENODEV;
}
}否则
err=-EINVAL;
}/*[开关末端]*/
返回错误;
}
因此,要么执行一个指定的cmd,要么执行SIOCDEVPRIVATE和SIOCDEVPRIVATE+15之间的某个命令


希望这有帮助:^)

您是否尝试过将C_CAN_SET_过滤器设置为等于SIOCDEVPRIVATE+1?