内核 5.15 和 5.4.0 之间关于 ioctl 有效命令是否有任何变化?

问题描述 投票:0回答:2

我们有一些在 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,
};
linux-kernel driver ioctl
2个回答
1
投票

如果您需要一些代码来响应 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


0
投票

我需要修复,但无法发表评论。我正在开发相同的 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;
}
© www.soinside.com 2019 - 2024. All rights reserved.