diff options
Diffstat (limited to 'drivers/net/tun.c')
| -rw-r--r-- | drivers/net/tun.c | 32 | 
1 files changed, 18 insertions, 14 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5235f48be1b..9a6b3824da1 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -572,9 +572,9 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)  /* prepad is the amount to reserve at front.  len is length after that.   * linear is a hint as to how much to copy (usually headers). */ -static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, -					    size_t prepad, size_t len, -					    size_t linear, int noblock) +static struct sk_buff *tun_alloc_skb(struct tun_struct *tun, +				     size_t prepad, size_t len, +				     size_t linear, int noblock)  {  	struct sock *sk = tun->socket.sk;  	struct sk_buff *skb; @@ -600,13 +600,13 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun,  }  /* Get packet from user space buffer */ -static __inline__ ssize_t tun_get_user(struct tun_struct *tun, -				       const struct iovec *iv, size_t count, -				       int noblock) +static ssize_t tun_get_user(struct tun_struct *tun, +			    const struct iovec *iv, size_t count, +			    int noblock)  {  	struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };  	struct sk_buff *skb; -	size_t len = count, align = 0; +	size_t len = count, align = NET_SKB_PAD;  	struct virtio_net_hdr gso = { 0 };  	int offset = 0; @@ -636,7 +636,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,  	}  	if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) { -		align = NET_IP_ALIGN; +		align += NET_IP_ALIGN;  		if (unlikely(len < ETH_HLEN ||  			     (gso.hdr_len && gso.hdr_len < ETH_HLEN)))  			return -EINVAL; @@ -688,7 +688,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,  	case TUN_TAP_DEV:  		skb->protocol = eth_type_trans(skb, tun->dev);  		break; -	}; +	}  	if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {  		pr_debug("GSO!\n"); @@ -751,9 +751,9 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,  }  /* Put packet to the user space buffer */ -static __inline__ ssize_t tun_put_user(struct tun_struct *tun, -				       struct sk_buff *skb, -				       const struct iovec *iv, int len) +static ssize_t tun_put_user(struct tun_struct *tun, +			    struct sk_buff *skb, +			    const struct iovec *iv, int len)  {  	struct tun_pi pi = { 0, skb->protocol };  	ssize_t total = 0; @@ -810,6 +810,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,  			gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;  			gso.csum_start = skb_checksum_start_offset(skb);  			gso.csum_offset = skb->csum_offset; +		} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { +			gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;  		} /* else everything is zero */  		if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, @@ -839,7 +841,8 @@ static ssize_t tun_do_read(struct tun_struct *tun,  	tun_debug(KERN_INFO, tun, "tun_chr_read\n"); -	add_wait_queue(&tun->wq.wait, &wait); +	if (unlikely(!noblock)) +		add_wait_queue(&tun->wq.wait, &wait);  	while (len) {  		current->state = TASK_INTERRUPTIBLE; @@ -870,7 +873,8 @@ static ssize_t tun_do_read(struct tun_struct *tun,  	}  	current->state = TASK_RUNNING; -	remove_wait_queue(&tun->wq.wait, &wait); +	if (unlikely(!noblock)) +		remove_wait_queue(&tun->wq.wait, &wait);  	return ret;  }  |