diff options
author | Kyle K <kylek389@gmail.com> | 2013-02-01 09:46:37 -0600 |
---|---|---|
committer | Kyle Kaminski <kyle@kkaminsk.com> | 2013-02-01 09:46:37 -0600 |
commit | 5d414a8b60c907307d501bd6ee65c7a8a2f8c587 (patch) | |
tree | 511fa1829ce03f1df83347806e5faf171eeabf6a /main.c | |
parent | 2a64bd55f015dde0b32c752377d5820d9d280873 (diff) | |
download | kernelhello-5d414a8b60c907307d501bd6ee65c7a8a2f8c587.tar.gz kernelhello-5d414a8b60c907307d501bd6ee65c7a8a2f8c587.tar.bz2 kernelhello-5d414a8b60c907307d501bd6ee65c7a8a2f8c587.zip |
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 65 |
1 files changed, 65 insertions, 0 deletions
@@ -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 }; |