summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/main.c b/main.c
index 579a621..6983725 100644
--- a/main.c
+++ b/main.c
@@ -283,6 +283,70 @@ static ssize_t hello_write(struct file *filp, const char __user *buff, size_t co
}
/*
+ * The ioctl() implementation
+ */
+long hello_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ int retval = 0;
+
+ /*
+ * Extract the type and number bitfields, and don't decode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != HELLO_IOCTL_BASE)
+ return -ENOTTY;
+
+ if (_IOC_NR(cmd) > HELLO_IOCTL_MAXNR)
+ return -ENOTTY;
+
+ /*
+ * The direction is a bitmask, and VERIFY_WRITE catches R/W
+ * transfers. `Type' is user-oriented, while
+ * access_ok is kernel-oriented, so the concept of "read" and
+ * "write" is reversed
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void __user *) arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void __user *) arg, _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ switch (cmd) {
+ case HELLO_IOCTL_RESET:
+ hello_node_chunk_sz = HELLO_NODE_CHUNK_SIZE;
+ break;
+
+ case HELLO_IOCTL_SCHUNK:
+ if (!capable (CAP_SYS_ADMIN))
+ return -EPERM;
+ retval = __get_user(hello_node_chunk_sz, (int __user *) arg);
+ break;
+
+ case HELLO_IOCTL_TCHUNK:
+ if (!capable (CAP_SYS_ADMIN))
+ return -EPERM;
+ hello_node_chunk_sz = arg;
+ break;
+
+ case HELLO_IOCTL_GCHUNK:
+ if (!capable (CAP_SYS_ADMIN))
+ return -EPERM;
+ retval = __put_user(hello_node_chunk_sz, (int __user *) arg);
+ break;
+
+ case HELLO_IOCTL_QCHUNK:
+ return hello_node_chunk_sz;
+
+ default: /* redundant, as cmd was checked against MAXNR */
+ return -ENOTTY;
+ }
+
+ return retval;
+}
+
+/*
* There's a count in filp that gets incremented every time our char device gets
* opened, but note that this function does not get called multiple times,
* instead copies are made, think fork(), or just simple ptr?
@@ -318,6 +382,7 @@ struct file_operations hello_fops = {
.owner = THIS_MODULE,
.read = hello_read,
.write = hello_write,
+ .unlocked_ioctl = hello_ioctl,
.open = hello_open,
.release = hello_release
};