static int opiocset(void __user *argp, DATA *data) { struct opiocdesc op; struct device_node *dp; char *str, *tmp; int err; if (copy_from_user(&op, argp, sizeof(op))) return -EFAULT; dp = get_node(op.op_nodeid, data); if (!dp) return -EINVAL; err = copyin_string(op.op_name, op.op_namelen, &str); if (err) return err; err = copyin_string(op.op_buf, op.op_buflen, &tmp); if (err) { kfree(str); return err; } err = of_set_property(dp, str, tmp, op.op_buflen); kfree(str); kfree(tmp); return err; }
/* * NetBSD /dev/openprom ioctl calls. */ static int opiocget(void __user *argp, DATA *data) { struct opiocdesc op; struct device_node *dp; char *str; void *pval; int err, len; if (copy_from_user(&op, argp, sizeof(op))) return -EFAULT; dp = get_node(op.op_nodeid, data); err = copyin_string(op.op_name, op.op_namelen, &str); if (err) return err; pval = of_get_property(dp, str, &len); err = 0; if (!pval || len > op.op_buflen) { err = -EINVAL; } else { op.op_buflen = len; if (copy_to_user(argp, &op, sizeof(op)) || copy_to_user(op.op_buf, pval, len)) err = -EFAULT; } kfree(str); return err; }
static int opiocnextprop(void __user *argp, DATA *data) { struct opiocdesc op; struct device_node *dp; struct property *prop; char *str; int err, len; if (copy_from_user(&op, argp, sizeof(op))) return -EFAULT; dp = get_node(op.op_nodeid, data); if (!dp) return -EINVAL; err = copyin_string(op.op_name, op.op_namelen, &str); if (err) return err; if (str[0] == '\0') { prop = dp->properties; } else { prop = of_find_property(dp, str, NULL); if (prop) prop = prop->next; } kfree(str); if (!prop) len = 0; else len = prop->length; if (len > op.op_buflen) len = op.op_buflen; if (copy_to_user(argp, &op, sizeof(op))) return -EFAULT; if (len && copy_to_user(op.op_buf, prop->value, len)) return -EFAULT; return 0; }
/* * NetBSD /dev/openprom ioctl calls. */ static int openprom_bsd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { DATA *data = (DATA *) file->private_data; struct opiocdesc op; unsigned long flags; int error, node, len; char *str, *tmp; char buffer[64]; static int cnt; switch (cmd) { case OPIOCGET: if (copy_from_user(&op, (void *)arg, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; error = copyin_string(op.op_name, op.op_namelen, &str); if (error) return error; save_and_cli(flags); len = prom_getproplen(op.op_nodeid,str); restore_flags(flags); if (len > op.op_buflen) { kfree(str); return -ENOMEM; } op.op_buflen = len; if (len <= 0) { kfree(str); /* Verified by the above copy_from_user */ if (__copy_to_user((void *)arg, &op, sizeof(op))) return -EFAULT; return 0; } tmp = kmalloc(len + 1, GFP_KERNEL); if (!tmp) { kfree(str); return -ENOMEM; } save_and_cli(flags); prom_getproperty(op.op_nodeid, str, tmp, len); restore_flags(flags); tmp[len] = '\0'; error = __copy_to_user((void *)arg, &op, sizeof(op)); if (!error) error = copy_to_user(op.op_buf, tmp, len); kfree(tmp); kfree(str); return error; case OPIOCNEXTPROP: if (copy_from_user(&op, (void *)arg, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; error = copyin_string(op.op_name, op.op_namelen, &str); if (error) return error; save_and_cli(flags); tmp = prom_nextprop(op.op_nodeid,str,buffer); restore_flags(flags); if (tmp) { len = strlen(tmp); if (len > op.op_buflen) len = op.op_buflen; else op.op_buflen = len; } else { len = op.op_buflen = 0; } error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(op)); if (error) { kfree(str); return error; } error = verify_area(VERIFY_WRITE, op.op_buf, len); if (error) { kfree(str); return error; } error = __copy_to_user((void *)arg, &op, sizeof(op)); if (!error) error = __copy_to_user(op.op_buf, tmp, len); kfree(str); return error; case OPIOCSET: if (copy_from_user(&op, (void *)arg, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; error = copyin_string(op.op_name, op.op_namelen, &str); if (error) return error; error = copyin_string(op.op_buf, op.op_buflen, &tmp); if (error) { kfree(str); return error; } save_and_cli(flags); len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1); restore_flags(flags); if (len != op.op_buflen) return -EINVAL; kfree(str); kfree(tmp); return 0; case OPIOCGETOPTNODE: if (copy_to_user((void *)arg, &options_node, sizeof(int))) return -EFAULT; return 0; case OPIOCGETNEXT: case OPIOCGETCHILD: if (copy_from_user(&node, (void *)arg, sizeof(int))) return -EFAULT; save_and_cli(flags); if (cmd == OPIOCGETNEXT) node = __prom_getsibling(node); else node = __prom_getchild(node); restore_flags(flags); if (__copy_to_user((void *)arg, &node, sizeof(int))) return -EFAULT; return 0; default: if (cnt++ < 10) printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd); return -EINVAL; } }