Linux Kernel Module/IOCTL: inappropriate ioctl for device

Asked
Active3 hr before
Viewed126 times

6 Answers

modulelinux
90%

Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers ,I am in the process of writing a Linux Kernel Module (LKM) serving as a pseudo-driver - I am unable to figure out how to make IOCTL calls between the LKM (wait.c) and the user-level program (user.c).,In Linux kernel 2.6.x the declaration for _ioctl calls changed from,The user-mode application can open/close a file descriptor pointing to the device: /dev/wait but the case/switch statement isn't accepting the IOCTL call. Any suggestions?

In Linux kernel 2.6.x the declaration for _ioctl calls changed from

static long wait_ioctl(struct inode * , struct file * , unsigned int, unsigned long);
load more v
88%

Here’s the release implementation for /dev/scullpriv, which closes the discussion of device methods., When the device isn’t accessible, returning an error is usually the most sensible approach, but there are situations in which the user would prefer to wait for the device.,One of the last things we need to cover in this chapter is the llseek method, which is useful (for some devices) and easy to implement.,Controlling by write is definitely the way to go for those devices that don’t transfer data but just respond to commands, such as robotic devices.

/* Use 'k' as magic number */
#define SCULL_IOC_MAGIC 'k'
/* Please use a different 8-bit number in your code */

#define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0)

/*
 * S means "Set" through a ptr,
 * T means "Tell" directly with the argument value
 * G means "Get": reply by setting through a pointer
 * Q means "Query": response is on the return value
 * X means "eXchange": switch G and S atomically
 * H means "sHift": switch T and Q atomically
 */
#define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int)
#define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int)
#define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3)
#define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4)
#define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int)
#define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int)
#define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7)
#define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8)
#define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)
#define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC, 10, int)
#define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11)
#define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12)

#define SCULL_IOC_MAXNR 14
load more v
72%

I have added ioctl handling to the driver in this way,I am trying to add an ioctl interface to the CAN driver in Linux kernel 3.12 which is a net device.,I added debugging to make sure that the above code is actually executed when the driver loads and it is.,ndo_do_ioctl is called under the following conditions:

I have added ioctl handling to the driver in this way

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

Then in userspace I have this code...

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

I have verified that CANConfig[hndl].s is an integer which evaluates to the open file descriptor for the channel into the CAN driver (i.e. CAN0). In fact this ioctl call elsewhere in the code does work

if (ioctl(CANConfig[hndl].s, SIOCGIFINDEX, & ifr) < 0)
load more v
65%

ioctl() is the most common way for applications to interface with device drivers. It is flexible and easily extended by adding new commands and can be passed through character devices, block devices as well as sockets and other special file descriptors.,debugfs is used for ad-hoc interfaces for debugging functionality that does not need to be exposed as a stable interface to applications.,Applications written for one driver are more likely to work for another one in the same subsystem if there are no subtle differences in the user space ABI.,It is more likely to be reviewed by experienced developers that can spot problems in the interface when the ioctl is shared between multiple drivers than when it is only used in a single driver.

struct foo {
   __u32 a;
   __u64 b;
   __u32 c;
};
75%

ioctl vs kernel модули в Linux , Получение ENOTTY на ioctl для модуля Linux Kernel ,В Linux kernel 2.6.x объявление для вызовов _ioctl изменилось с

Вызов IOCTL, который я пытаюсь использовать, это:

#include <sys/ioctl.h>
#define KERN_IOCTL_CREATE_EVENT   _IOWR(WAIT_DEVICE_MAGIC, 1, int)

int main(){
int ret;
int fd;
fd = open("/dev/wait", 0);
if(fd < 0){
    return -1;
}
ret = ioctl(fd, KERN_IOCTL_CREATE_EVENT, 0);

Ошибка:

[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl
for device

Вот результат # uname -a

Linux vagrant - ubuntu - trusty - 64 3.13 .11 .11 + #1 SMP Mon Dec 1 20:50:23 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

wait.c

#include <linux/miscdevice.h>
#include <linux/moduleparam.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/fs.h>

#include "wait.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tyler Fisher <tyler@tylerfisher.org>");
MODULE_DESCRIPTION("In-kernel wait queue");

static unsigned long event_table_size = 50;
module_param(event_table_size, ulong, (S_IRUSR | S_IRGRP | S_IROTH));
MODULE_PARM_DESC(event_table_size, "Size of event table (i.e. how many processes can be blocking)");

/* IOCTL function headers */
static int wait_open(struct inode *, struct file *);
static int wait_close(struct inode *, struct file *);
static long wait_ioctl(struct inode *, struct file *, unsigned int, unsigned long);

/* other function headers */
static long event_open(int event_id);

/* file operations */
static struct file_operations wait_fops = {
    .owner = THIS_MODULE,
    .open = wait_open,
    .release = wait_close,
    .llseek = noop_llseek,
    .unlocked_ioctl = wait_ioctl
};

/* device handler */
static struct miscdevice wait_misc_device = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = WAIT_DEVICE_NAME,
  .fops = &wait_fops
};

/* open wait device */
static int wait_open(struct inode *inode, struct file *file){
    dev_t node = iminor(inode);
    if(MINOR(node) != WAIT_DEVICE_MINOR){
        return -ENODEV;
    }
    return 0;
}

static int wait_close(struct inode *inode, struct file *file){
    return 0;
}

static long wait_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long sub_cmd){
switch(cmd){
    case KERN_IOCTL_CREATE_EVENT:
        printk(KERN_INFO "[wait device]: create event %lu\n", sub_cmd);
        return event_open(sub_cmd);

    default:
        return -ENOENT;
    }
}

static long event_open(int id){
    return 0;
}

static long __init wait_init(void){
    if(misc_register(&wait_misc_device) < 0){
        printk(KERN_ERR "[wait device] failed to register device\n");
        return -1;
    }
    printk(KERN_INFO "[wait device] has been registered\n");
    return 0;
}

static void __exit wait_exit(void){
    misc_deregister(&wait_misc_device);
    printk(KERN_INFO "[wait device] has been unregistered\n");
}

module_init(wait_init);
module_exit(wait_exit);

wait.h

#include <linux /ioctl.h>

   #define WAIT_DEVICE_NAME "wait"
   #define WAIT_DEVICE_MAGIC 0xBF
   #define WAIT_DEVICE_MAJOR 200
   #define WAIT_DEVICE_MINOR 0

   #define KERN_IOCTL_CREATE_EVENT _IOWR(WAIT_DEVICE_MAGIC, 0x01, int)

   #define MAX_WAITING 5

user.c

#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>

#define WAIT_DEVICE_MAGIC   0xBF
#define KERN_IOCTL_CREATE_EVENT   _IOWR(WAIT_DEVICE_MAGIC, 0x01, int)
#define KERN_IOCTL_DESTROY_EVENT  _IOWR(WAIT_DEVICE_MAGIC, 0x02, int)
#define KERN_IOCTL_LOCK_EVENT     _IOWR(WAIT_DEVICE_MAGIC, 0x03, int)
#define KERN_IOCTL_UNLOCK_EVENT   _IOWR(WAIT_DEVICE_MAGIC, 0x04, int)

int main(){
    int fd;
    if(fd = open("/dev/wait", O_RDWR) < 0){
        perror("failed to open /dev/wait");
        return -1;
    }

    /* test IOCTL: event creation */
    if(ioctl(fd, KERN_IOCTL_CREATE_EVENT, 0) < 0){
        perror("[fail]: KERN_IOCTL_CREATE_EVENT");
        return -1;
    }
    return 0;
}

Makefile

obj - m += wait.o
CFLAGS_wait.o += -DDEBUG

all:
   make - C / lib / modules / $(shell uname - r) / build M = $(PWD) modules

clean:
   make - C / lib / modules / $(shell uname - r) / build M = $(PWD) clean

Для того, чтобы проверить LKM - четкие команды dmesg, составить & выполнить user.c w/GCC:

# dmesg - c > /dev/null
2 > & 1
# make
# rmmod wait.ko
# insmod wait.ko
# gcc user.c - o user && . / user

Количество ошибок отладки просто смущает. Я чувствую себя плохо из - за того, что делюсь этим-и понимаю, что это может привести к тому, что проблема будет закрыта/низведена в небытие.

# sh test.sh[+] cleared dmesg
make - C / lib / modules / 3.13 .11 .11 + /build M=/home / vagrant / PROG40000 - kernel - synchronization modules
make[1]: Entering directory `/home/vagrant/ubuntu-trusty'
  CC [M]  /home/vagrant/PROG40000-kernel-synchronization/wait.o
/home/vagrant/PROG40000-kernel-synchronization/wait.c:61:1: warning: initialization from incompatible pointer type [enabled by default]
 };
 ^
/home/vagrant/PROG40000-kernel-synchronization/wait.c:61:1: warning: (near initialization for ‘wait_fops.unlocked_ioctl’) [enabled by default]
In file included from include/linux/moduleparam.h:4:0,
                 from /home/vagrant/PROG40000-kernel-synchronization/wait.c:11:
/home/vagrant/PROG40000-kernel-synchronization/wait.c: In function ‘__inittest’:
include/linux/init.h:297:4: warning: return from incompatible pointer type [enabled by default]
  { return initfn; }     \
    ^
/home/vagrant/PROG40000-kernel-synchronization/wait.c:167:1: note: in expansion of macro ‘module_init’
 module_init(wait_init);
 ^
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/vagrant/PROG40000-kernel-synchronization/wait.mod.o
  LD [M]  /home/vagrant/PROG40000-kernel-synchronization/wait.ko
make[1]: Leaving directory ` / home / vagrant / ubuntu - trusty ' [--dmesg--]
   [13112.810008][wait device] has been unregistered[13112.819049][wait device] has been registered[-/dmesg--] [+] compiled user - mode program
      -- -- - [fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl
      for device[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl
      for device[+] executed user - mode program
      -- -- - [--dmesg--]
      [13112.810008][wait device] has been unregistered[13112.819049][wait device] has been registered[13112.893049] SOMEONE DARE READ FROM ME! ? [13112.893057][wait device] invalid magic number : 0: 0: 191[13112.893535][wait device] invalid magic number: 0: 0: 191[-/dmesg--]
load more v
40%

ioctl() is the most common way for applications to interface with device drivers. It is flexible and easily extended by adding new commands and can be passed through character devices, block devices as well as sockets and other special file descriptors.,This is generally a bad idea, since changes to existing commands tend to break existing applications.,debugfs is used for ad-hoc interfaces for debugging functionality that does not need to be exposed as a stable interface to applications.,Applications written for one driver are more likely to work for another one in the same subsystem if there are no subtle differences in the user space ABI.

struct foo {
   __u32 a;
   __u64 b;
   __u32 c;
};

Other "module-linux" queries related to "Linux Kernel Module/IOCTL: inappropriate ioctl for device"