我们有一些在 5.4.0 上运行的自定义驱动程序。它已经很旧了,最初的开发人员不再支持它,所以我们必须在我们的系统中维护它。 当升级到 Ubuntu 22(内核 5.15)时,驱动程序突然停止工作,并使用命令 SIOCDEVPRIVATE 发送 ioctl(该命令曾经在内核 5.4.0 中工作,实际上用于获取一些必要的设备信息)现在给出“ioctl” :不支持操作”错误,日志中没有任何额外信息。
那么...这两个内核之间有什么变化吗?我们确实必须调整一些用于注册驱动程序的结构,但我看不到任何有关在那里注册有效操作的信息。我现在必须在某个地方注册有效的操作吗? 或者,有人知道内核代码的哪一部分正在检查要支持的操作吗?我一直试图从 ioctl.c 中找到它,但我似乎无法找到该特定错误的来源。
据说可以处理此问题的驱动程序代码(甚至没有到达 5.15 的第一行):
static int u50_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) {
struct u50_priv *priv = netdev_priv(dev);
if (cmd == SIOCDEVPRIVATE) {
memcpy(&ifr->ifr_data, priv->tty->name, strlen(priv->tty->name));
}
return 0;
}
并且尝试访问它不再起作用:
struct ifreq ifr = {0};
struct ifaddrs *ifaddr, *ifa;
getifaddrs(&ifaddr);
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
memcpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
if (ioctl(lonsd, SIOCDEVPRIVATE, &ifr) < 0) {
perror("ioctl");
syslog(LOG_ERR, "Ioctl:%d: %s\n", __LINE__, strerror(errno));
}
...
和注册结构
static const struct net_device_ops u50_netdev_ops = {
.ndo_init = u50_dev_init,
.ndo_uninit = u50_dev_uninit,
.ndo_open = u50_dev_open,
.ndo_stop = u50_dev_stop,
.ndo_start_xmit = u50_dev_xmit,
.ndo_do_ioctl = u50_dev_ioctl,
.ndo_set_mac_address = U50SetHWAddr,
};
如果您需要一些代码来响应 SIOCDEVPRIVATE,您过去可以通过 ndo_do_ioctl 来完成(编写兼容函数,然后将其链接到 5.4 中的 net_device_ops 结构中)。然而,在 5.15 中它被改变了,所以现在你必须实现一个 ndo_siocdevprivate 函数,而不是 ndo_do_ioctl,根据内核文档,它不再被调用。
来源: https://elixir.bootlin.com/linux/v5.15.57/source/include/linux/netdevice.h
执行此操作的补丁:spinics.net/lists/netdev/msg698158.html
我需要修复,但无法发表评论。我正在开发相同的 u50 (U60) 驱动程序。此更改有效,我无需修改守护进程 lonifd。
根据这里的答案,在 U50Driver.c 中,我更改了:
static const struct net_device_ops u50_netdev_ops = {
.ndo_init = u50_dev_init,
.ndo_uninit = u50_dev_uninit,
.ndo_open = u50_dev_open,
.ndo_stop = u50_dev_stop,
.ndo_start_xmit = u50_dev_xmit,
//WAS .ndo_do_ioctl = u50_dev_ioctl,
.ndo_siocdevprivate = u50_dev_ioctl,
.ndo_set_mac_address = U50SetHWAddr,
};
static int u50_dev_ioctl(struct net_device *dev, struct ifreq *ifr, void __user *data, int cmd) {
struct u50_priv *priv = netdev_priv(dev);
LDDebugInform("%s", __func__);
if (cmd == SIOCDEVPRIVATE) {
memcpy(&ifr->ifr_data, priv->tty->name, strlen(priv->tty->name));
}
return 0;
}