/* * Give out the data that's requested from the buffer that we have * queued up. */ ssize_t fill_readbuf(struct crypto_device *crdev, char *out_buf, size_t out_count) { struct crypto_vq_buffer *buf; debug("Entering\n"); if (!out_count || !device_has_data(crdev)) return 0; buf = crdev->inbuf; out_count = min(out_count, buf->len - buf->offset); memcpy(out_buf, buf->buf + buf->offset, out_count); buf->offset += out_count; if (buf->offset == buf->len) { /* * FIXME: We're done using all the data in this buffer. * Re-queue so that the Host can send us more data. */ crdev->inbuf = NULL; if (add_inbuf(crdev->ivq, buf) < 0) printk(KERN_WARNING "failed add_buf\n"); } debug("Leaving\n"); /* Return the number of bytes actually copied */ return out_count; }
long crypto_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct crypto_device *crdev; struct crypto_data *cr_data; ssize_t ret; size_t cnt; crdev = filp->private_data; cr_data = kzalloc(sizeof(crypto_data), GFP_KERNEL); if (!cr_data) return -ENOMEM; cr_data->cmd = cmd; switch (cmd) { /* get the metadata for every operation * from userspace and send the buffer * to the host */ case CIOCGSESSION: /* ? */ ret = copy_from_user(&cr_data->op.sess, (void __user *)arg, sizeof(struct session_op)); if (ret < 0) goto free_buf; if (cr_data->op.sess.keylen > CRYPTO_CIPHER_MAX_KEY_LEN) { printk(KERN_WARNING "Ooops: Key size bigger than eligible!"); return -EINVAL; } else { ret = copy_from_user(cr_data->keyp,cr_data->op.sess.key,cr_data->op.sess.keylen); if (ret < 0) goto free_buf; } cnt = send_buf(crdev,cr_data,sizeof(cr_data),(filp->f_flags & O_NONBLOCK)); if (cnt != sizeof(cr_data)) { debug("Buffer was not sent completely!"); return -1; } if (!device_has_data(crdev)) { debug("sleeping in CIOCGSESSION\n"); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; /* Go to sleep unti we have data. */ ret = wait_event_interruptible(crdev->i_wq, device_has_data(crdev)); if (ret < 0) goto free_buf; } printk(KERN_ALERT "woke up in CIOCGSESSION\n"); if (!device_has_data(crdev)) return -ENOTTY; ret = fill_readbuf(crdev, (char *)cr_data, sizeof(crypto_data)); /* copy the response to userspace */ /* ? */ ret = copy_to_user((void __user *)arg,&cr_data->op.sess,sizeof(struct session_op)); if (ret < 0) goto free_buf; break; case CIOCCRYPT: /* ? */ ret = copy_from_user(&cr_data->op.crypt, (void __user *)arg, sizeof(struct crypt_op)); if (ret < 0) goto free_buf; if (cr_data->op.crypt.len > CRYPTO_DATA_MAX_LEN) { printk(KERN_WARNING "Ooops: Data size bigger than eligible!"); return -EINVAL; } else { ret = copy_from_user(cr_data->srcp,cr_data->op.crypt.src,cr_data->op.crypt.len); if (ret < 0) goto free_buf; } ret = copy_from_user(cr_data->ivp,cr_data->op.crypt.iv,16); if (ret < 0) goto free_buf; cnt = send_buf(crdev,cr_data,sizeof(cr_data),(filp->f_flags & O_NONBLOCK)); if (cnt != sizeof(cr_data)) { debug("Buffer was not sent completely!"); return -1; } if (!device_has_data(crdev)) { printk(KERN_WARNING "sleeping in CIOCCRYPTO\n"); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; /* Go to sleep until we have data. */ ret = wait_event_interruptible(crdev->i_wq, device_has_data(crdev)); if (ret < 0) goto free_buf; } ret = fill_readbuf(crdev, (char *)cr_data, sizeof(crypto_data)); ret = copy_to_user((void __user *)arg, &cr_data->op.crypt, sizeof(struct crypt_op)); if (ret < 0) goto free_buf; /* copy the response to userspace */ /* ? */ ret = copy_to_user((void __user *)((struct crypt_op *)arg)->dst, cr_data->dstp, cr_data->op.crypt.len); if (ret < 0) goto free_buf; break; case CIOCFSESSION: /* ? */ ret = copy_from_user(&cr_data->op.sess_id, (void __user *)arg, sizeof(uint32_t)); if (ret < 0) goto free_buf; cnt = send_buf(crdev,cr_data,sizeof(cr_data),(filp->f_flags & O_NONBLOCK)); if (cnt != sizeof(cr_data)) { debug("Buffer was not sent completely!"); return -1; } if (!device_has_data(crdev)) { printk(KERN_WARNING "PORT HAS NOT DATA!!!\n"); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; /* Go to sleep until we have data. */ ret = wait_event_interruptible(crdev->i_wq, device_has_data(crdev)); if (ret < 0) goto free_buf; } ret = fill_readbuf(crdev, (char *)cr_data, sizeof(crypto_data)); /* copy the response to userspace */ /* ? */ ret = copy_to_user((void __user *)arg,&cr_data->op.sess_id,sizeof(uint32_t)); if (ret < 0) goto free_buf; break; default: return -EINVAL; } kfree(cr_data); return 0; free_buf: kfree(cr_data); return ret; }
long crypto_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct crypto_device *crdev; struct crypto_data *cr_data; ssize_t ret; struct session_op *temp; struct crypt_op *temp1 ; __u32 *temp2; char *temp_iv; char *temp_dst; char *temp_src; char *temp_key; crdev = filp->private_data; cr_data = kzalloc(sizeof(crypto_data), GFP_KERNEL); if (!cr_data) return -ENOMEM; cr_data->cmd = cmd; switch (cmd) { /* get the metadata for every operation * from userspace and send the buffer * to the host */ case CIOCGSESSION: { temp =(struct session_op *) arg; temp_key = (char *)temp->key; ret = insist_copy_from_user((char *)&(cr_data->op),(char *)temp,sizeof(struct session_op)); ret = insist_copy_from_user((char *)cr_data->keyp,(char *)temp_key,CRYPTO_CIPHER_MAX_KEY_LEN); send_buf(crdev,cr_data,sizeof(struct crypto_data),false); if (!device_has_data(crdev)) { debug("sleeping in CIOCGSESSION\n"); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; /* Go to sleep unti we have data. */ ret = wait_event_interruptible(crdev->i_wq,device_has_data(crdev)); if (ret < 0) goto free_buf; } printk(KERN_ALERT "woke up in CIOCGSESSION\n"); if (!device_has_data(crdev)) return -ENOTTY; ret = fill_readbuf(crdev, (char *)cr_data, sizeof(crypto_data)); ret = insist_copy_to_user((char *)temp, (char *)&(cr_data->op.sess), sizeof(struct session_op)); ret = insist_copy_to_user((char *)temp_key, (char *)cr_data->keyp,temp->keylen); break; } case CIOCCRYPT: { temp1 =(struct crypt_op *) arg; temp_src = (char *)temp1->src; temp_dst = (char *)temp1->dst; temp_iv=(char *)temp1->iv; ret = insist_copy_from_user((char *)&(cr_data->op),(char *)temp1,sizeof(struct crypt_op)); ret = insist_copy_from_user((char *)(cr_data->srcp),(char *)temp_src,CRYPTO_DATA_MAX_LEN); ret = insist_copy_from_user((char *)(cr_data->dstp),(char *)temp_dst,CRYPTO_DATA_MAX_LEN); ret = insist_copy_from_user((char *)(cr_data->ivp),(char *)temp_iv,CRYPTO_BLOCK_MAX_LEN); if ((send_buf(crdev,cr_data,sizeof(struct crypto_data),false))==0) { debug("Send_buf returns 0-possible failure\n"); return -1; } if (!device_has_data(crdev)) { printk(KERN_WARNING "sleeping in CIOCCRYPTO\n"); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; /* Go to sleep until we have data. */ ret = wait_event_interruptible(crdev->i_wq,device_has_data(crdev)); if (ret < 0) goto free_buf; } /* copy the response to userspace */ ret = fill_readbuf(crdev, (char *)cr_data, sizeof(struct crypto_data)); if (ret) goto free_buf; ret = insist_copy_to_user((char *)temp1,(char *)&(cr_data->op.crypt),sizeof(struct crypt_op)); ret = insist_copy_to_user((char *)temp_src,(char *)(cr_data->srcp),CRYPTO_DATA_MAX_LEN); ret = insist_copy_to_user((char *)temp_dst,(char *)(cr_data->dstp),CRYPTO_DATA_MAX_LEN); ret = insist_copy_to_user((char *)temp_iv,(char *)(cr_data->ivp),CRYPTO_BLOCK_MAX_LEN); break; } case CIOCFSESSION: { temp2 =(__u32 *) arg; ret = insist_copy_from_user((char *)&(cr_data->op.sess_id),(char *)temp2,sizeof(__u32)); if ((send_buf(crdev,cr_data,sizeof(struct crypto_data),false))==0) { debug("Send_buf returns 0-possible failure\n"); return -1; } if (!device_has_data(crdev)) { printk(KERN_WARNING "PORT HAS NOT DATA!!!\n"); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; /* Go to sleep until we have data. */ ret = wait_event_interruptible(crdev->i_wq, device_has_data(crdev)); if (ret < 0) goto free_buf; } ret = fill_readbuf(crdev, (char *)cr_data, sizeof(crypto_data)); break; } default: return -EINVAL; } return 0; free_buf: kfree(cr_data); return ret; }