* attached to a device. The returned object works like a packet socket, it
* can be used for sock_sendmsg/sock_recvmsg. The caller is responsible for
* holding a reference to the file for as long as the socket is in use. */
-struct socket *tun_get_socket(struct file *file)
+struct socket *tun_get_socket(struct file *file, size_t *hlen)
{
struct tun_file *tfile;
if (file->f_op != &tun_fops)
tfile = file->private_data;
if (!tfile)
return ERR_PTR(-EBADFD);
+
+ if (hlen) {
+ struct tun_struct *tun = tun_get(tfile);
+ size_t len = 0;
+
+ if (!tun)
+ return ERR_PTR(-ENOTCONN);
+ if (tun->flags & IFF_VNET_HDR)
+ len += READ_ONCE(tun->vnet_hdr_sz);
+ if (!(tun->flags & IFF_NO_PI))
+ len += sizeof(struct tun_pi);
+ tun_put(tun);
+ *hlen = len;
+ }
return &tfile->socket;
}
EXPORT_SYMBOL_GPL(tun_get_socket);
vq_log = unlikely(vhost_has_feature(vq, VHOST_F_LOG_ALL)) ?
vq->log : NULL;
- mergeable = vhost_has_feature(vq, VIRTIO_NET_F_MRG_RXBUF);
+ mergeable = vhost_has_feature(vq, VIRTIO_NET_F_MRG_RXBUF) &&
+ (vhost_hlen || sock_hlen >= sizeof(num_buffers));
do {
sock_len = vhost_net_rx_peek_head_len(net, sock->sk,
}
} else {
/* Header came from socket; we'll need to patch
- * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
+ * ->num_buffers over the last two bytes if
+ * VIRTIO_NET_F_MRG_RXBUF is enabled.
*/
- iov_iter_advance(&fixup, sizeof(hdr));
+ iov_iter_advance(&fixup, sock_hlen - 2);
}
/* TODO: Should check and handle checksum. */
return 0;
}
-static struct socket *get_raw_socket(int fd)
+static struct socket *get_raw_socket(int fd, size_t *hlen)
{
int r;
struct socket *sock = sockfd_lookup(fd, &r);
r = -EPFNOSUPPORT;
goto err;
}
+ *hlen = 0;
return sock;
err:
sockfd_put(sock);
return ring;
}
-static struct socket *get_tap_socket(int fd)
+static struct socket *get_tap_socket(int fd, size_t *hlen)
{
struct file *file = fget(fd);
struct socket *sock;
if (!file)
return ERR_PTR(-EBADF);
- sock = tun_get_socket(file);
+ sock = tun_get_socket(file, hlen);
if (!IS_ERR(sock))
return sock;
- sock = tap_get_socket(file);
+ sock = tap_get_socket(file, hlen);
if (IS_ERR(sock))
fput(file);
return sock;
}
-static struct socket *get_socket(int fd)
+static struct socket *get_socket(int fd, size_t *hlen)
{
struct socket *sock;
/* special case to disable backend */
if (fd == -1)
return NULL;
- sock = get_raw_socket(fd);
+ sock = get_raw_socket(fd, hlen);
if (!IS_ERR(sock))
return sock;
- sock = get_tap_socket(fd);
+ sock = get_tap_socket(fd, hlen);
if (!IS_ERR(sock))
return sock;
return ERR_PTR(-ENOTSOCK);
r = -EFAULT;
goto err_vq;
}
- sock = get_socket(fd);
+ sock = get_socket(fd, &nvq->sock_hlen);
if (IS_ERR(sock)) {
r = PTR_ERR(sock);
goto err_vq;
static int vhost_net_set_features(struct vhost_net *n, u64 features)
{
- size_t vhost_hlen, sock_hlen, hdr_len;
+ size_t vhost_hlen, hdr_len;
int i;
hdr_len = (features & ((1ULL << VIRTIO_NET_F_MRG_RXBUF) |
if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
/* vhost provides vnet_hdr */
vhost_hlen = hdr_len;
- sock_hlen = 0;
} else {
- /* socket provides vnet_hdr */
vhost_hlen = 0;
- sock_hlen = hdr_len;
}
mutex_lock(&n->dev.mutex);
if ((features & (1 << VHOST_F_LOG_ALL)) &&
mutex_lock(&n->vqs[i].vq.mutex);
n->vqs[i].vq.acked_features = features;
n->vqs[i].vhost_hlen = vhost_hlen;
- n->vqs[i].sock_hlen = sock_hlen;
mutex_unlock(&n->vqs[i].vq.mutex);
}
mutex_unlock(&n->dev.mutex);