Exemple #1
0
/*
 * 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;	
}