Questions about this topic? Sign up to ask in the talk tab.

LKM/chardev.c

From NetSec
Jump to: navigation, search
 
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dade Murphy");
MODULE_DESCRIPTION("A simple character driver that creates a device that can be written to and read from.");
MODULE_VERSION("0.1");
 
/*
*	To test this module, load it and try:
*	$ cat /dev/mod0
*	$ cat filename.txt > /dev/mod0
*	$ cat /dev/mod0
*	Effectively whatever is sent to the device is stored and returned next time the device is read.
*	The buffer used is only 50 bytes, but there's no reason you can't increase that. It's written to be overflow-safe.
*/
 
//handle parameters for device name
 
static char *devno = "0";
module_param(devno, charp, 0664);
MODULE_PARM_DESC(devno, "The device number, e.g. a value of 2 will create /dev/mod2");
 
//initialize variables used by the driver
 
static int majorNumber;
char cur_value[50] = { 'n', 'o', 'n', 'e', '\n', 0 };
static struct class* myModule_class = NULL;
static struct device* myModule_device = NULL;
static ssize_t recvd = 0;
static ssize_t sent = 0;
 
//function prototypes for our file operations struct
 
static int device_open(struct inode *, struct file *);
static ssize_t device_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t device_write(struct file *, char __user *, size_t, loff_t *);
static ssize_t device_release(struct inode *, struct file *);
 
//mapping our custom functions to the file operations in <linux/fs.h>
 
static struct file_operations fops =
{
	.open = device_open,
	.read = device_read,
	.write = device_write,
	.release = device_release,
};
 
//init function: register major number, class and device
 
static int __init myModule_init(void)
{
	char *name = kmalloc(10, GFP_KERNEL);
	strncpy(name, "mod0", 4);
	name[3] = devno[0];
	name[4] = 0x00;
	majorNumber = register_chrdev(0, "myModule", &fops);
	myModule_class = class_create(THIS_MODULE, "myModule");
	myModule_device = device_create(myModule_class, NULL, MKDEV(majorNumber, 0), NULL, name);
	printk(KERN_INFO "Hello, my major number is %d.\n", majorNumber);
	return 0;
}
 
//exit function - destroy device and clean up
 
static void __exit myModule_exit(void)
{
	device_destroy(myModule_class, MKDEV(majorNumber, 0));
	class_unregister(myModule_class);
	class_destroy(myModule_class);
	unregister_chrdev(majorNumber, "myModule");
	printk(KERN_INFO "This device, class and major number were successfully destroyed.\n");
}
 
//file operation functions begin here
 
static int device_open(struct inode *inode_pointer, struct file *file_pointer)
{
	printk(KERN_INFO "The device was just opened!\n");
	return 0;
}
 
static ssize_t device_release(struct inode *inode_pointer, struct file *file_pointer)
{
	printk(KERN_INFO "The device was just released!\n");
	return 0;
}
 
 
static ssize_t device_read(struct file *file_ptr, char __user *usr_ptr, size_t size_ptr, loff_t *offset_ptr)
{
	printk(KERN_INFO "The device was just read! Sending it some data....\n");
	int error = copy_to_user(usr_ptr, cur_value, strlen(cur_value));
	ssize_t bytes = size_ptr - (*offset_ptr);
	(*offset_ptr) += bytes;
	return bytes;
}
 
static ssize_t device_write(struct file *file_ptr, char __user *usr_ptr, size_t size_ptr, loff_t *offset_ptr)
{
	static char buf[50] = {0};
	//strncpy(buf, usr_ptr, 50);
	copy_from_user(buf, usr_ptr, 50);
	buf[49] = 0x00;
	printk(KERN_INFO "The device was just written!\n");
	printk(KERN_INFO "The message was: %s", buf);
	strncpy(cur_value, buf, 50);
	ssize_t bytes = size_ptr - (*offset_ptr);
	(*offset_ptr) += bytes;
	return bytes;
}
 
 
module_init(myModule_init);
module_exit(myModule_exit);