我正在尝试将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&#34;设备不适当的ioctl&#34;
似乎自定义ioctl并未真正注册,因此内核在调用驱动程序中的自定义ioctl代码之前拒绝用户空间ioctl调用。用于网络设备(如SIOCGIFINDEX)的内置ioctls可按预期工作。
有谁能告诉我这里我做错了什么?
我能看到的两件事看起来不对,但显然不是(1)c_can_ioctl()定义的第3个参数应该是unsigned long但是是int。似乎网络设备ioctl接口不符合非网络设备的ioctl接口。 (2)net_device_ops结构中有一个.ndo_do_ioctl槽,但没有.ndo_do_unlocked_ioctl。
答案 0 :(得分:1)
你的核心/ dev.c调用你的ndo_do_ioctl,那里寻找:
在以下条件下调用 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之间的某些内容。
希望这会有所帮助:^)