How to send and receive a struct through netlink? - c

I'm trying to send a struct from user-space to my module in kernel space using netlink, my struct in the user-space is:
struct test{
unsigned int length;
char name[MAX_NAME_LENGTH];
};
and in the kernel space is:
struct test{
__u32 length;
char name[MAX_NAME_LENGTH];
};
where MAX_NAME_LENGTH is a macro defined to be equal 50.
In the user-space, I've the function main which send my struct to the kernel with the following code:
int main(){
struct iovec iov[2];
int sock_fd;
struct sockaddr_nl src_add;
struct sockaddr_nl dest_add;
struct nlmsghdr * nl_hdr = NULL;
struct msghdr msg;
struct test message;
memset(&message, 0, sizeof(struct test));
message.length = 18;
strcpy(message.name, "Just a test\0");
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
if (sock_fd < 0){
printf("Netlink socket creation failed\n");
return -1;
}
memset(&src_add, 0, sizeof(src_add));
src_add.nl_family = AF_NETLINK;
src_add.nl_pid = getpid();
memset(&dest_add, 0, sizeof(dest_add));
dest_add.nl_family = AF_NETLINK;
dest_add.nl_pid = 0; // Send to linux kernel
dest_add.nl_groups = 0; // Unicast
bind(sock_fd,(struct sockaddr *)&src_add,sizeof(src_add));
nl_hdr = (struct nlmsghdr *) malloc(NLMSG_SPACE(sizeof(struct test)));
memset(nl_hdr, 0, NLMSG_SPACE(sizeof (struct test)));
nl_hdr->nlmsg_len = NLMSG_SPACE(sizeof(struct test));
nl_hdr->nlmsg_pid = getpid();
nl_hdr->nlmsg_flags = 0;
iov[0].iov_base = (void *)nl_hdr;
iov[0].iov_len = nl_hdr->nlmsg_len;
iov[1].iov_base = &message;
iov[1].iov_len = sizeof(struct test);
memset(&msg,0, sizeof(msg));
msg.msg_name = (void *)&dest_add;
msg.msg_namelen = sizeof(dest_add);
msg.msg_iov = &iov[0];
msg.msg_iovlen = 2;
sendmsg(sock_fd,&msg,0);
close(sock_fd);
return 0;
}
And in the kernel side I've registered a function called callback to be called every time that a message is received, this is the callback function:
static void callback(struct sk_buff *skb){
struct nlmsghdr *nl_hdr;
struct test * msg_rcv;
nl_hdr = (struct nlmsghdr*)skb->data;
msg_rcv = (struct test*) nlmsg_data(nl_hdr);
printk(KERN_INFO "Priting the length and name in the struct:%u, %s\n",msg_rcv->length, msg_rcv->name);
}
When I run these codes and see the dmesg output I receive the following message: Priting the length and name in the struct:0,, so why the fields of the struct filled in the user-space side aren't being sent to the kernel?
Btw, NETLINK_USER is defined as 31.

DON'T DO THAT. YOUR CODE HAS BUGS BY DESIGN.
I'm going to first explain the one superfluous issue that prevents your code from doing what you want, then explain why what you want is a bad idea, then explain the right solution.
1. Doing what you want
You "want" to send a packet consisting of a netlink header followed by a struct. In other words, this:
+-----------------+-------------+
| struct nlmsghdr | struct test |
| (16 bytes) | (54 bytes) |
+-----------------+-------------+
The problem is that's not what you're telling your iovec. According to your iovec code, the packet looks like this:
+-----------------+--------------+-------------+
| struct nlmsghdr | struct test | struct test |
| (16 bytes) | (54 bytes) | (54 bytes) |
| (data) | (all zeroes) | (data) |
+-----------------+--------------+-------------+
This line:
iov[0].iov_len = nl_hdr->nlmsg_len;
Should be this:
iov[0].iov_len = NLMSG_HDRLEN;
Because your first iovec slot is just the Netlink header; not the whole packet.
2. Why what you want is bad
C has a gotcha called "data structure padding." Don't skip this lecture; I'd argue that anyone who deals with the C language MUST read it ASAP: http://www.catb.org/esr/structure-packing/
The gist of it is that C compilers are allowed to introduce garbage between the members of any structure. Thus, when you declare this:
struct test {
unsigned int length;
char name[MAX_NAME_LENGTH];
};
The compiler is technically allowed to mutate that during implementation into something like
struct test {
unsigned int length;
unsigned char garbage[4];
char name[MAX_NAME_LENGTH];
};
See the problem? If your kernel module and your userspace client were generated by different compilers, or by the same compiler but with slightly different flags, or even by slightly different versions of the same compiler, the structures might differ and the kernel will receive garbage, no matter how correct your code looks.
Update: Someone asked me to elaborate on that, so here it goes:
Suppose you have the following structure:
struct example {
__u8 value8;
__u16 value16;
};
In userspace, the compiler decides to leave it as is. However, in kernelspace the compiler "randomly" decides to convert it to:
struct example {
__u8 value8;
__u8 garbage;
__u16 value16;
};
In your userspace client, you then write this code:
struct example x;
x.value8 = 0x01;
x.value16 = 0x0203;
In memory, the structure will look like this:
01 <- value8
02 <- First byte of value16
03 <- Second byte of value16
When you send that to the kernel, the kernel will, of course, receive the same thing:
01
02
03
But it will interpret it differently:
01 <- value8
02 <- garbage
03 <- First byte of value16
junk <- Second byte of value16
(End of Update)
In your case the problem is aggravated by the fact that you define test.length as unsigned int in userspace, yet for some reason you change it into __u32 in kernelspace. Your code is problematic even before structure padding; if your userspace defines basic integers as 64-bit, the bug will also inevitably trigger.
And there's another problem: "Btw, NETLINK_USER is defined as 31" tells me you're following tutorials or code samples long obsolete or written by people who don't know what they are doing. Do you know where that 31 comes from? It's the identifier of your "Netlink family." They define it as 31 because that's the highest possible value it can have (0-31), and therefore, it's the most unlikely one to collide with other Netlink families defined by the kernel. (Because they are numbered monotonically.) But most careless Netlink users are following the tutorials, and therefore most of their Netlink families identify as 31. Therefore, your kernel module will be unable to coexist with any of them. netlink_kernel_create() will kick you out because 31 is already claimed.
And you might be wondering, "well shit. There are only 32 available slots, 23 of them are already taken by the kernel and there's an unknown but likely large number of additional people wanting to register different Netlink families. What do I do?!"
3. The proper way
It's 2020. We don't use Netlink anymore. We use better-Netlink: Generic Netlink.
Generic Netlink uses strings and dynamic integers as family identifiers, and drives you to use Netlink's "attribute" framework by default. (The latter encourages you to serialize and deserialize structures in a portable way, which is the real solution to your original problem.)
This code needs to be visible to both your userspace client and kernel module:
#define SAMPLE_FAMILY "Sample Family"
enum sample_operations {
SO_TEST, /* from your "struct test" */
/* List more here for different request types. */
};
enum sample_attribute_ids {
/* Numbering must start from 1 */
SAI_LENGTH = 1, /* From your test.length */
SAI_NAME, /* From your test.name */
/* This is a special one; don't list any more after this. */
SAI_COUNT,
#define SAI_MAX (SAI_COUNT - 1)
};
This is the kernel module:
#include <linux/module.h>
#include <linux/version.h>
#include <net/genetlink.h>
#include "../include/protocol.h"
/*
* A "policy" is a bunch of rules. The kernel will validate the request's fields
* match these data types (and other defined constraints) for us.
*/
struct nla_policy const sample_policy[SAI_COUNT] = {
[SAI_LENGTH] = { .type = NLA_U32 },
[SAI_NAME] = { .type = NLA_STRING },
};
/*
* This is the function the kernel calls whenever the client sends SO_TEST
* requests.
*/
static int handle_test_operation(struct sk_buff *skb, struct genl_info *info)
{
if (!info->attrs[SAI_LENGTH]) {
pr_err("Invalid request: Missing length attribute.\n");
return -EINVAL;
}
if (!info->attrs[SAI_NAME]) {
pr_err("Invalid request: Missing name attribute.\n");
return -EINVAL;
}
pr_info("Printing the length and name: %u, '%s'\n",
nla_get_u32(info->attrs[SAI_LENGTH]),
(unsigned char *)nla_data(info->attrs[SAI_NAME]));
return 0;
}
static const struct genl_ops ops[] = {
/*
* This is what tells the kernel to use the function above whenever
* userspace sends SO_TEST requests.
* Add more array entries if you define more sample_operations.
*/
{
.cmd = SO_TEST,
.doit = handle_test_operation,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
/* Before kernel 5.2, each op had its own policy. */
.policy = sample_policy,
#endif
},
};
/* Descriptor of our Generic Netlink family */
static struct genl_family sample_family = {
.name = SAMPLE_FAMILY,
.version = 1,
.maxattr = SAI_MAX,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
/* Since kernel 5.2, the policy is family-wide. */
.policy = sample_policy,
#endif
.module = THIS_MODULE,
.ops = ops,
.n_ops = ARRAY_SIZE(ops),
};
/* Called by the kernel when the kernel module is inserted */
static int test_init(void)
{
return genl_register_family(&sample_family);
}
/* Called by the kernel when the kernel module is removed */
static void test_exit(void)
{
genl_unregister_family(&sample_family);
}
module_init(test_init);
module_exit(test_exit);
And here's the userspace client (You need to install libnl-genl-3 --sudo apt install libnl-genl-3-dev on Debian/Ubuntu):
#include <errno.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>
#include "../include/protocol.h"
static struct nl_sock *sk;
static int genl_family;
static void prepare_socket(void)
{
sk = nl_socket_alloc();
genl_connect(sk);
genl_family = genl_ctrl_resolve(sk, SAMPLE_FAMILY);
}
static struct nl_msg *prepare_message(void)
{
struct nl_msg *msg;
msg = nlmsg_alloc();
genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family, 0, 0, SO_TEST, 1);
/*
* The nla_put* functions ensure that your data will be stored in a
* portable way.
*/
nla_put_u32(msg, SAI_LENGTH, 18);
nla_put_string(msg, SAI_NAME, "Just a test");
return msg;
}
int main(int argc, char **argv)
{
struct nl_msg *msg;
prepare_socket();
msg = prepare_message();
nl_send_auto(sk, msg); /* Send message */
nlmsg_free(msg);
nl_socket_free(sk);
return 0;
}
This code should work starting from kernel 4.10. (I tested it in 4.15.) The kernel API was somewhat different before that.
I left a pocket version of my test environment (with makefiles and proper error handling and everything) in my Dropbox, so you can run it easily.

Related

C struct being passed thru a linux msg queue failing intermittently

I have a client process that builds an IPC message struct queue_msg that is being sent to a server via the linux IPC msg queue. 68 bytes in size. struct is defined as:
struct FOO_TYPE {
long mtype;
struct {
int sev;
char msg[32];
char bt[32];
} foomsg;
};
the client declares a pointer to the a struct of FOO_TYPE locally in the function and mallocs space for it. the code then loads the sev, msg and bt fields.
static struct FOO_TYPE *FooEntry = NULL;
...code clipped
if (FooEntry == NULL)
FooEntry = malloc(sizeof(struct FOO_TYPE));
memset(FooEntry, 0, sizeof(struct FOO_TYPE));
...code clipped
MsgSize = sizeof(FooEntry) - sizeof(long);
FooEntry->mtype = CHANGESTATUS;
FooEntry->foomsg.sev = serr->serr_data->sev;
strcpy(FooEntry->syserrmsg.emsg, elog);
strcpy(FooEntry->syserrmsg.bt, btlog);
... code clipped
result = msg_snd(FooExchange, FooEntry, MsgSize, IPC_WAIT);
the server receiving the IPC msg is getting 68 bytes (ie: sizeof FOO_TYPE), however intermittently, the fields inside are either missing or garbage.
do I have to malloc space for the fields in the struct inside the structure as well??
This is at least one bug:
MsgSize = sizeof(FooEntry) - sizeof(long);
FooEntry is a pointer defined here:
static struct FOO_TYPE *FooEntry = NULL;
so sizeof(FooEntry) gives you the size of a pointer - not the size of a struct.
You probably want
MsgSize = sizeof(*FooEntry) - sizeof(long);
or perhaps just
MsgSize = sizeof(FooEntry->foomsg);

What kinds of data in a device driver can be shared among processes?

In device drivers, how can we tell what data is shared among processes and what is local to a process? The Linux Device Drivers book mentions
Any time that a hardware or software resource is shared beyond a single thread of execution, and the possibility exists that one thread could encounter an inconsistent view of that resource, you must explicitly manage access to that resource.
But what kinds of software resources can be shared among threads and what kinds of data cannot be shared? I know that global variables are generally considered as shared memory but what other kinds of things need to be protected?
For example, is the struct inode and struct file types passed in file operations like open, release, read, write, etc. considered to be shared?
In the open call inside main.c , why is dev (in the line dev = container_of(inode->i_cdev, struct scull_dev, cdev);) not protected with a lock if it points to a struct scull_dev entry in the global array scull_devices?
In scull_write, why isn't the line int quantum = dev->quantum, qset = dev->qset; locked with a semaphore since it's accessing a global variable?
/* In scull.h */
struct scull_qset {
void **data; /* pointer to an array of pointers which each point to a quantum buffer */
struct scull_qset *next;
};
struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
/* In main.c */
struct scull_dev *scull_devices; /* allocated in scull_init_module */
int scull_major = SCULL_MAJOR;
int scull_minor = 0;
int scull_nr_devs = SCULL_NR_DEVS;
int scull_quantum = SCULL_QUANTUM;
int scull_qset = SCULL_QSET;
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data; /* flip->private_data assigned in scull_open */
struct scull_qset *dptr;
int quantum = dev->quantum, qset = dev->qset;
int itemsize = quantum * qset;
int item; /* item in linked list */
int s_pos; /* position in qset data array */
int q_pos; /* position in quantum */
int rest;
ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
/* find listitem, qset index and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum;
/* follow the list up to the right position */
dptr = scull_follow(dev, item);
if (dptr == NULL)
goto out;
if (!dptr->data) {
dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
if (!dptr->data)
goto out;
memset(dptr->data, 0, qset * sizeof(char *));
}
if (!dptr->data[s_pos]) {
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
if (!dptr->data[s_pos])
goto out;
}
/* write only up to the end of this quantum */
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
/* update the size */
if (dev->size < *f_pos)
dev->size = *f_pos;
out:
up(&dev->sem);
return retval;
}
int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
/* Question: Why was the lock not placed here? */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
scull_trim(dev); /* ignore errors */
up(&dev->sem);
}
return 0; /* success */
}
int scull_init_module(void)
{
int result, i;
dev_t dev = 0;
/* assigns major and minor numbers (left out for brevity) */
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
if (!scull_devices) {
result = -ENOMEM;
goto fail; /* isn't this redundant? */
}
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));
/* Initialize each device. */
for (i = 0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
init_MUTEX(&scull_devices[i].sem);
scull_setup_cdev(&scull_devices[i], i);
}
/* some other stuff (left out for brevity) */
return 0; /* succeed */
fail:
scull_cleanup_module(); /* left out for brevity */
return result;
}
/*
* Set up the char_dev structure for this device.
*/
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, scull_minor + index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops; /* isn't this redundant? */
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
All data in memory can be considered a "shared resource" if both threads are able to access it*. The only resource they wouldn't be shared between processors is the data in the registers, which is abstracted away in C.
There are two reasons that you would not practically consider two resources to be shared (even though they do not actually mean that two threads could not theoretically access them, some nightmarish code could sometimes bypass these).
Only one thread can/does access it. Clearly if only one thread accesses a variable then there can be no race conditions. This is the reason local variables and single threaded programs do not need locking mechanisms.
The value is constant. You can't get different results based on order of access if the value can never change.
The program you have shown here is incomplete, so it is hard to say, but each of the variables accessed without locking must meet one of the criteria for this program to be thread safe.
There are some non-obvious ways to meet the criteria, such as if a variable is constant or limited to one thread only in a specific context.
You gave two examples of lines that were not locked. For the first line.
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
This line does not actually access any variables, it just computes where the struct containing cdev would be. There can be no race conditions because nobody else has access to your pointers (though they have access to what they point to), they are only accessible within the function (this is not true of what they point to). This meets criteria (1).
The other example is
int quantum = dev->quantum, qset = dev->qset;
This one is a bit harder to say without context, but my best guess is that it is assumed that dev->quantum and dev->qset will never change during the function call. This seems supported by the fact that they are only called in scull_init_module which should only be called once at the very beginning. I believe this fits criteria (2).
Which brings up another way that you might change a shared variable without locking, if you know that other threads will not try to access it until you are done for some other reason (eg they are not extant yet)
In short, all memory is shared, but sometimes you can get away with acting like its not.
*There are embedded systems where each processor has some amount of RAM that only it could use, but this is not the typical case.

Reading data from socket with readv

I'm having problems with a client-server communication made with writev()/readv().
I have two struct, header and data defined like this:
typedef struct {
int op;
int key;
} message_hdr_t;
typedef struct {
int len;
char *data;
} message_data_t;
The server does (in short):
message_hdr_t h = {1, 11};
message_data_t d;
d.len = 3;
strcpy(d.data, "msg");
struct iovec tosend[2];
tosend[0].iov_base = &h;
tosend[0].iov_len = sizeof(message_hdr_t);
tosend[1].iov_base = &d;
tosend[1].iov_len = sizeof(message_data_t);
writev(socket, tosend, 2);
close(socket);
The client (in short):
struct iovec received[2];
readv(socket, received, 2);
message_hdr_t header;
header.op = ((message_hdr_t *) received[0].iov_base)->op;
header.key = ((message_hdr_t *) received[0].iov_base)->key;
printf("Received op: %i, key: %i\n",header.op,header.key;
close(socket);
But the client gets a segfault because received[0].iov_base is NULL. Why?
The socket is correctly opened and the client is correctly connected to the server. It's an AF_UNIX socket.
First, in your server code, you are writing a pointer. This makes no sense. You don't want to transmit pointers over the wire. To transmit a string, you have to do something like this:
char* message = ...;
message_hdr_t h = {1, 11};
uint32_t message_length = strlen(message);
struct iovec tosend[3];
tosend[0].iov_base = &h;
tosend[0].iov_len = sizeof(message_hdr_t);
tosend[1].iov_base = &message_length;
tosend[1].iov_len = sizeof(message_length);
tosend[2].iov_base = message;
tosend[2].iov_len = message_length;
(You may want to move the string length to the message header and save one element of the vector, and make the protocol more readable).
Second, readv won't allocate memory for you, or divine out how many bytes you want to read. It's your job to correctly initialize iov_base and iov_len in the IO vector passed to readv. In order to read a dynamically-allocated variable-size string, you probably want to read twice. First, read a part of the message that contains the length of the string, then allocate the string, and read the rest of the message.

How to create a simple sysfs class attribute in Linux kernel v3.2

I'm learning how to use sysfs in my Linux modules, but I'm having the hardest time finding current documentation on these topics. The Linux Device Drivers 3rd Edition book I've been using seems to be rather dated in this area unfortunately (e.g. the class_device structure appears to be completely gone in current Linux versions).
I'm simply trying to get an attribute to appear, under the respective sysfs class for my module, that will allow me to read the value of a module variable from kernel space.
In my code, I have a class created that allows udev to create a device node at /dev/foo for my module:
dev_t foo_dev;
alloc_chrdev_region(&foo_dev, 0, 1, "bar");
struct class *bar = class_create(THIS_MODULE, "bar");
device_create(bar, NULL, foo_dev, NULL, "foo");
struct cdev foo_dev_file;
cdev_init(&foo_dev_file, &fops); /* fops defined earlier */
cdev_add(&foo_dev_file, foo_dev, 1);
When I insert the module I get a sysfs class directory created and populated with some default attributes at /sys/class/bar/foo/. How can I create attributes that show up under this new directory?
I have the concepts down pretty well I believe -- create attribute structure, define sysfs_ops functions, etc -- my problem is that I don't know which particular kernel structure to use (class_attribute?), nor how to make these attributes appear under the right sysfs directory.
Would anyone point me to a tutorial or article detailing the process for current Linux kernels?
Even though my knowledge is still fairly low on the topic, I'm going to post an answer just because of the age of this question. If somebody else has a better answer, please post! :)
First off, I'm going to assume that you've read that whole chapter (specifically about kobjects & ksets). So just about every struct in the device driver model has these cutely included in them. If you want to manipulate the kobject for the class its self (not sure if that's wise or not), that's your struct class's dev_kobj member.
However, you want to manipulate the attributes of that class. I believe you do this by defining a (usually static), NULL-terminated array of them as follows and then assigning its address to the struct class's class_attrs member (taken from drivers/uwb/driver.c):
static struct class_attribute uwb_class_attrs[] = {
__ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO,
beacon_timeout_ms_show, beacon_timeout_ms_store),
__ATTR_NULL,
};
/** Device model classes */
struct class uwb_rc_class = {
.name = "uwb_rc",
.class_attrs = uwb_class_attrs,
};
When I don't know how to use something, I usually git grep the repository for somebody else who has used it and try to learn from it that way. It would seem that this is why they tend to say kernel "hackers" and not "developers".
Minimal runnable example
Usage:
insmod /sysfs.ko
cd /sys/kernel/lkmc_sysfs
printf 12345 >foo
cat foo
# => 1234
dd if=foo bs=1 count=2 skip=1 status=none
# => 23
sysfs.c
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <uapi/linux/stat.h> /* S_IRUSR, S_IWUSR */
enum { FOO_SIZE_MAX = 4 };
static int foo_size;
static char foo_tmp[FOO_SIZE_MAX];
static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buff)
{
strncpy(buff, foo_tmp, foo_size);
return foo_size;
}
static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buff, size_t count)
{
foo_size = min(count, (size_t)FOO_SIZE_MAX);
strncpy(foo_tmp, buff, foo_size);
return count;
}
static struct kobj_attribute foo_attribute =
__ATTR(foo, S_IRUGO | S_IWUSR, foo_show, foo_store);
static struct attribute *attrs[] = {
&foo_attribute.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static struct kobject *kobj;
static int myinit(void)
{
int ret;
kobj = kobject_create_and_add("lkmc_sysfs", kernel_kobj);
if (!kobj)
return -ENOMEM;
ret = sysfs_create_group(kobj, &attr_group);
if (ret)
kobject_put(kobj);
return ret;
}
static void myexit(void)
{
kobject_put(kobj);
}
module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");
GitHub upstream.
Tested with Linux kernel 5.0.
There is a good tutorial in the link below
http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html
parrot_driver.c:
/*
* Linux 2.6 and 3.0 'parrot' sample device driver
*
* Copyright (c) 2011, Pete Batard <pete#akeo.ie>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/kfifo.h>
#include "parrot_driver.h"
/* Module information */
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCRIPTION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
/* Device variables */
static struct class* parrot_class = NULL;
static struct device* parrot_device = NULL;
static int parrot_major;
/* Flag used with the one_shot mode */
static bool message_read;
/* A mutex will ensure that only one process accesses our device */
static DEFINE_MUTEX(parrot_device_mutex);
/* Use a Kernel FIFO for read operations */
static DECLARE_KFIFO(parrot_msg_fifo, char, PARROT_MSG_FIFO_SIZE);
/* This table keeps track of each message length in the FIFO */
static unsigned int parrot_msg_len[PARROT_MSG_FIFO_MAX];
/* Read and write index for the table above */
static int parrot_msg_idx_rd, parrot_msg_idx_wr;
/* Module parameters that can be provided on insmod */
static bool debug = false; /* print extra debug info */
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "enable debug info (default: false)");
static bool one_shot = true; /* only read a single message after open() */
module_param(one_shot, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "disable the readout of multiple messages at once (default: true)");
static int parrot_device_open(struct inode* inode, struct file* filp)
{
dbg("");
/* Our sample device does not allow write access */
if ( ((filp->f_flags & O_ACCMODE) == O_WRONLY)
|| ((filp->f_flags & O_ACCMODE) == O_RDWR) ) {
warn("write access is prohibited\n");
return -EACCES;
}
/* Ensure that only one process has access to our device at any one time
* For more info on concurrent accesses, see http://lwn.net/images/pdf/LDD3/ch05.pdf */
if (!mutex_trylock(&parrot_device_mutex)) {
warn("another process is accessing the device\n");
return -EBUSY;
}
message_read = false;
return 0;
}
static int parrot_device_close(struct inode* inode, struct file* filp)
{
dbg("");
mutex_unlock(&parrot_device_mutex);
return 0;
}
static ssize_t parrot_device_read(struct file* filp, char __user *buffer, size_t length, loff_t* offset)
{
int retval;
unsigned int copied;
/* The default from 'cat' is to issue multiple reads until the FIFO is depleted
* one_shot avoids that */
if (one_shot && message_read) return 0;
dbg("");
if (kfifo_is_empty(&parrot_msg_fifo)) {
dbg("no message in fifo\n");
return 0;
}
retval = kfifo_to_user(&parrot_msg_fifo, buffer, parrot_msg_len[parrot_msg_idx_rd], &copied);
/* Ignore short reads (but warn about them) */
if (parrot_msg_len[parrot_msg_idx_rd] != copied) {
warn("short read detected\n");
}
/* loop into the message length table */
parrot_msg_idx_rd = (parrot_msg_idx_rd+1)%PARROT_MSG_FIFO_MAX;
message_read = true;
return retval ? retval : copied;
}
/* The file_operation scructure tells the kernel which device operations are handled.
* For a list of available file operations, see http://lwn.net/images/pdf/LDD3/ch03.pdf */
static struct file_operations fops = {
.read = parrot_device_read,
.open = parrot_device_open,
.release = parrot_device_close
};
/* Placing data into the read FIFO is done through sysfs */
static ssize_t sys_add_to_fifo(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
unsigned int copied;
dbg("");
if (kfifo_avail(&parrot_msg_fifo) < count) {
warn("not enough space left on fifo\n");
return -ENOSPC;
}
if ((parrot_msg_idx_wr+1)%PARROT_MSG_FIFO_MAX == parrot_msg_idx_rd) {
/* We've looped into our message length table */
warn("message length table is full\n");
return -ENOSPC;
}
/* The buffer is already in kernel space, so no need for ..._from_user() */
copied = kfifo_in(&parrot_msg_fifo, buf, count);
parrot_msg_len[parrot_msg_idx_wr] = copied;
if (copied != count) {
warn("short write detected\n");
}
parrot_msg_idx_wr = (parrot_msg_idx_wr+1)%PARROT_MSG_FIFO_MAX;
return copied;
}
/* This sysfs entry resets the FIFO */
static ssize_t sys_reset(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
dbg("");
/* Ideally, we would have a mutex around the FIFO, to ensure that we don't reset while in use.
* To keep this sample simple, and because this is a sysfs operation, we don't do that */
kfifo_reset(&parrot_msg_fifo);
parrot_msg_idx_rd = parrot_msg_idx_wr = 0;
return count;
}
/* Declare the sysfs entries. The macros create instances of dev_attr_fifo and dev_attr_reset */
static DEVICE_ATTR(fifo, S_IWUSR, NULL, sys_add_to_fifo);
static DEVICE_ATTR(reset, S_IWUSR, NULL, sys_reset);
/* Module initialization and release */
static int __init parrot_module_init(void)
{
int retval;
dbg("");
/* First, see if we can dynamically allocate a major for our device */
parrot_major = register_chrdev(0, DEVICE_NAME, &fops);
if (parrot_major < 0) {
err("failed to register device: error %d\n", parrot_major);
retval = parrot_major;
goto failed_chrdevreg;
}
/* We can either tie our device to a bus (existing, or one that we create)
* or use a "virtual" device class. For this example, we choose the latter */
parrot_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(parrot_class)) {
err("failed to register device class '%s'\n", CLASS_NAME);
retval = PTR_ERR(parrot_class);
goto failed_classreg;
}
/* With a class, the easiest way to instantiate a device is to call device_create() */
parrot_device = device_create(parrot_class, NULL, MKDEV(parrot_major, 0), NULL, CLASS_NAME "_" DEVICE_NAME);
if (IS_ERR(parrot_device)) {
err("failed to create device '%s_%s'\n", CLASS_NAME, DEVICE_NAME);
retval = PTR_ERR(parrot_device);
goto failed_devreg;
}
/* Now we can create the sysfs endpoints (don't care about errors).
* dev_attr_fifo and dev_attr_reset come from the DEVICE_ATTR(...) earlier */
retval = device_create_file(parrot_device, &dev_attr_fifo);
if (retval < 0) {
warn("failed to create write /sys endpoint - continuing without\n");
}
retval = device_create_file(parrot_device, &dev_attr_reset);
if (retval < 0) {
warn("failed to create reset /sys endpoint - continuing without\n");
}
mutex_init(&parrot_device_mutex);
/* This device uses a Kernel FIFO for its read operation */
INIT_KFIFO(parrot_msg_fifo);
parrot_msg_idx_rd = parrot_msg_idx_wr = 0;
return 0;
failed_devreg:
class_unregister(parrot_class);
class_destroy(parrot_class);
failed_classreg:
unregister_chrdev(parrot_major, DEVICE_NAME);
failed_chrdevreg:
return -1;
}
static void __exit parrot_module_exit(void)
{
dbg("");
device_remove_file(parrot_device, &dev_attr_fifo);
device_remove_file(parrot_device, &dev_attr_reset);
device_destroy(parrot_class, MKDEV(parrot_major, 0));
class_unregister(parrot_class);
class_destroy(parrot_class);
unregister_chrdev(parrot_major, DEVICE_NAME);
}
/* Let the kernel know the calls for module init and exit */
module_init(parrot_module_init);
module_exit(parrot_module_exit);
parrot_driver.h:
/*
* Linux 2.6 and 3.0 'parrot' sample device driver
*
* Copyright (c) 2011, Pete Batard <pete#akeo.ie>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DEVICE_NAME "device"
#define CLASS_NAME "parrot"
#define PARROT_MSG_FIFO_SIZE 1024
#define PARROT_MSG_FIFO_MAX 128
#define AUTHOR "Pete Batard <pete#akeo.ie>"
#define DESCRIPTION "'parrot' sample device driver"
#define VERSION "0.3"
/* We'll use our own macros for printk */
#define dbg(format, arg...) do { if (debug) pr_info(CLASS_NAME ": %s: " format , __FUNCTION__ , ## arg); } while (0)
#define err(format, arg...) pr_err(CLASS_NAME ": " format, ## arg)
#define info(format, arg...) pr_info(CLASS_NAME ": " format, ## arg)
#define warn(format, arg...) pr_warn(CLASS_NAME ": " format, ## arg)

Issue with SPI (Serial Port Comm), stuck on ioctl()

I'm trying to access a SPI sensor using the SPIDEV driver but my code gets stuck on IOCTL.
I'm running embedded Linux on the SAM9X5EK (mounting AT91SAM9G25). The device is connected to SPI0. I enabled CONFIG_SPI_SPIDEV and CONFIG_SPI_ATMEL in menuconfig and added the proper code to the BSP file:
static struct spi_board_info spidev_board_info[] {
{
.modalias = "spidev",
.max_speed_hz = 1000000,
.bus_num = 0,
.chips_select = 0,
.mode = SPI_MODE_3,
},
...
};
spi_register_board_info(spidev_board_info, ARRAY_SIZE(spidev_board_info));
1MHz is the maximum accepted by the sensor, I tried 500kHz but I get an error during Linux boot (too slow apparently). .bus_num and .chips_select should correct (I also tried all other combinations). SPI_MODE_3 I checked the datasheet for it.
I get no error while booting and devices appear correctly as /dev/spidevX.X. I manage to open the file and obtain a valid file descriptor. I'm now trying to access the device with the following code (inspired by examples I found online).
#define MY_SPIDEV_DELAY_USECS 100
// #define MY_SPIDEV_SPEED_HZ 1000000
#define MY_SPIDEV_BITS_PER_WORD 8
int spidevReadRegister(int fd,
unsigned int num_out_bytes,
unsigned char *out_buffer,
unsigned int num_in_bytes,
unsigned char *in_buffer)
{
struct spi_ioc_transfer mesg[2] = { {0}, };
uint8_t num_tr = 0;
int ret;
// Write data
mesg[0].tx_buf = (unsigned long)out_buffer;
mesg[0].rx_buf = (unsigned long)NULL;
mesg[0].len = num_out_bytes;
// mesg[0].delay_usecs = MY_SPIDEV_DELAY_USECS,
// mesg[0].speed_hz = MY_SPIDEV_SPEED_HZ;
mesg[0].bits_per_word = MY_SPIDEV_BITS_PER_WORD;
mesg[0].cs_change = 0;
num_tr++;
// Read data
mesg[1].tx_buf = (unsigned long)NULL;
mesg[1].rx_buf = (unsigned long)in_buffer;
mesg[1].len = num_in_bytes;
// mesg[1].delay_usecs = MY_SPIDEV_DELAY_USECS,
// mesg[1].speed_hz = MY_SPIDEV_SPEED_HZ;
mesg[1].bits_per_word = MY_SPIDEV_BITS_PER_WORD;
mesg[1].cs_change = 1;
num_tr++;
// Do the actual transmission
if(num_tr > 0)
{
ret = ioctl(fd, SPI_IOC_MESSAGE(num_tr), mesg);
if(ret == -1)
{
printf("Error: %d\n", errno);
return -1;
}
}
return 0;
}
Then I'm using this function:
#define OPTICAL_SENSOR_ADDR "/dev/spidev0.0"
...
int fd;
fd = open(OPTICAL_SENSOR_ADDR, O_RDWR);
if (fd<=0) {
printf("Device not found\n");
exit(1);
}
uint8_t buffer1[1] = {0x3a};
uint8_t buffer2[1] = {0};
spidevReadRegister(fd, 1, buffer1, 1, buffer2);
When I run it, the code get stuck on IOCTL!
I did this way because, in order to read a register on the sensor, I need to send a byte with its address in it and then get the answer back without changing CS (however, when I tried using write() and read() functions, while learning, I got the same result, stuck on them).
I'm aware that specifying .speed_hz causes a ENOPROTOOPT error on Atmel (I checked spidev.c) so I commented that part.
Why does it get stuck? I though it can be as the device is created but it actually doesn't "feel" any hardware. As I wasn't sure if hardware SPI0 corresponded to bus_num 0 or 1, I tried both, but still no success (btw, which one is it?).
UPDATE: I managed to have the SPI working! Half of it.. MOSI is transmitting the right data, but CLK doesn't start... any idea?
When I'm working with SPI I always use an oscyloscope to see the output of the io's. If you have a 4 channel scope ypu can easily debug the issue, and find out if you're axcessing the right io's, using the right speed, etc. I usually compare the signal I get to the datasheet diagram.
I think there are several issues here. First of all SPI is bidirectional. So if yo want to send something over the bus you also get something. Therefor always you have to provide a valid buffer to rx_buf and tx_buf.
Second, all members of the struct spi_ioc_transfer have to be initialized with a valid value. Otherwise they just point to some memory address and the underlying process is accessing arbitrary data, thus leading to unknown behavior.
Third, why do you use a for loop with ioctl? You already tell ioctl you haven an array of spi_ioc_transfer structs. So all defined transaction will be performed with one ioctl call.
Fourth ioctl needs a pointer to your struct array. So ioctl should look like this:
ret = ioctl(fd, SPI_IOC_MESSAGE(num_tr), &mesg);
You see there is room for improvement in your code.
This is how I do it in a c++ library for the raspberry pi. The whole library will soon be on github. I'll update my answer when it is done.
void SPIBus::spiReadWrite(std::vector<std::vector<uint8_t> > &data, uint32_t speed,
uint16_t delay, uint8_t bitsPerWord, uint8_t cs_change)
{
struct spi_ioc_transfer transfer[data.size()];
int i = 0;
for (std::vector<uint8_t> &d : data)
{
//see <linux/spi/spidev.h> for details!
transfer[i].tx_buf = reinterpret_cast<__u64>(d.data());
transfer[i].rx_buf = reinterpret_cast<__u64>(d.data());
transfer[i].len = d.size(); //number of bytes in vector
transfer[i].speed_hz = speed;
transfer[i].delay_usecs = delay;
transfer[i].bits_per_word = bitsPerWord;
transfer[i].cs_change = cs_change;
i++
}
int status = ioctl(this->fileDescriptor, SPI_IOC_MESSAGE(data.size()), &transfer);
if (status < 0)
{
std::string errMessage(strerror(errno));
throw std::runtime_error("Failed to do full duplex read/write operation "
"on SPI Bus " + this->deviceNode + ". Error message: " +
errMessage);
}
}

Resources