Exemplo n.º 1
0
/* Readv */
static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
			    unsigned long count, loff_t *pos)
{
	struct tun_struct *tun = (struct tun_struct *)file->private_data;
	DECLARE_WAITQUEUE(wait, current);
	struct sk_buff *skb;
	ssize_t len, ret = 0;
	unsigned long i;

	if (!tun)
		return -EBADFD;

	DBG(KERN_INFO "%s: tun_chr_read\n", tun->name);

	for (i = 0, len = 0; i < count; i++) {
		if (verify_area(VERIFY_WRITE, iv[i].iov_base, iv[i].iov_len))
			return -EFAULT;
		len += iv[i].iov_len;
	}

	add_wait_queue(&tun->read_wait, &wait);
	while (len) {
		current->state = TASK_INTERRUPTIBLE;

		/* Read frames from the queue */
		if (!(skb=skb_dequeue(&tun->readq))) {
			if (file->f_flags & O_NONBLOCK) {
				ret = -EAGAIN;
				break;
			}
			if (signal_pending(current)) {
				ret = -ERESTARTSYS;
				break;
			}

			/* Nothing to read, let's sleep */
			schedule();
			continue;
		}
		netif_start_queue(&tun->dev);

		ret = tun_put_user(tun, skb, (struct iovec *) iv, len);

		kfree_skb(skb);
		break;
	}

	current->state = TASK_RUNNING;
	remove_wait_queue(&tun->read_wait, &wait);

	return ret;
}
Exemplo n.º 2
0
/* Read */
static ssize_t tun_chr_read(struct file * file, char * buf, 
			    size_t count, loff_t *pos)
{
	struct tun_struct *tun = (struct tun_struct *)file->private_data;
	DECLARE_WAITQUEUE(wait, current);
	struct sk_buff *skb;
	ssize_t ret = 0;

	DBG(KERN_INFO "%s: tun_chr_read\n", tun->name);

	add_wait_queue(&tun->read_wait, &wait);
	while (count) {
		current->state = TASK_INTERRUPTIBLE;

		/* Read frames from device queue */
		if (!(skb=skb_dequeue(&tun->txq))) {
			if (file->f_flags & O_NONBLOCK) {
				ret = -EAGAIN;
				break;
			}
			if (signal_pending(current)) {
				ret = -ERESTARTSYS;
				break;
			}

			/* Nothing to read, let's sleep */
			schedule();
			continue;
		}
		netif_start_queue(&tun->dev);

		if (!verify_area(VERIFY_WRITE, buf, count))
			ret = tun_put_user(tun, skb, buf, count);
		else
			ret = -EFAULT;

		kfree_skb(skb);
		break;
	}

	current->state = TASK_RUNNING;
	remove_wait_queue(&tun->read_wait, &wait);

	return ret;
}