diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5235f48be1b..71f3d1a35b7 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -528,6 +528,7 @@ static void tun_net_init(struct net_device *dev) dev->netdev_ops = &tap_netdev_ops; /* Ethernet TAP Device */ ether_setup(dev); + dev->priv_flags &= ~IFF_TX_SKB_SHARING; random_ether_addr(dev->dev_addr); @@ -572,9 +573,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 +601,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 +637,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 +689,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 +752,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 +811,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 +842,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 +874,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; } |