Commit 1a200b51 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-virtio-vsock'

parents cd356010 7e699d2a
...@@ -241,21 +241,18 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, ...@@ -241,21 +241,18 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
} }
static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs, static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
struct sk_buff *skb) u32 len)
{ {
if (vvs->rx_bytes + skb->len > vvs->buf_alloc) if (vvs->rx_bytes + len > vvs->buf_alloc)
return false; return false;
vvs->rx_bytes += skb->len; vvs->rx_bytes += len;
return true; return true;
} }
static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs, static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs,
struct sk_buff *skb) u32 len)
{ {
int len;
len = skb_headroom(skb) - sizeof(struct virtio_vsock_hdr) - skb->len;
vvs->rx_bytes -= len; vvs->rx_bytes -= len;
vvs->fwd_cnt += len; vvs->fwd_cnt += len;
} }
...@@ -367,7 +364,7 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, ...@@ -367,7 +364,7 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
spin_lock_bh(&vvs->rx_lock); spin_lock_bh(&vvs->rx_lock);
while (total < len && !skb_queue_empty(&vvs->rx_queue)) { while (total < len && !skb_queue_empty(&vvs->rx_queue)) {
skb = __skb_dequeue(&vvs->rx_queue); skb = skb_peek(&vvs->rx_queue);
bytes = len - total; bytes = len - total;
if (bytes > skb->len) if (bytes > skb->len)
...@@ -388,10 +385,11 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, ...@@ -388,10 +385,11 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
skb_pull(skb, bytes); skb_pull(skb, bytes);
if (skb->len == 0) { if (skb->len == 0) {
virtio_transport_dec_rx_pkt(vvs, skb); u32 pkt_len = le32_to_cpu(virtio_vsock_hdr(skb)->len);
virtio_transport_dec_rx_pkt(vvs, pkt_len);
__skb_unlink(skb, &vvs->rx_queue);
consume_skb(skb); consume_skb(skb);
} else {
__skb_queue_head(&vvs->rx_queue, skb);
} }
} }
...@@ -437,17 +435,17 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, ...@@ -437,17 +435,17 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,
while (!msg_ready) { while (!msg_ready) {
struct virtio_vsock_hdr *hdr; struct virtio_vsock_hdr *hdr;
size_t pkt_len;
skb = __skb_dequeue(&vvs->rx_queue); skb = __skb_dequeue(&vvs->rx_queue);
if (!skb) if (!skb)
break; break;
hdr = virtio_vsock_hdr(skb); hdr = virtio_vsock_hdr(skb);
pkt_len = (size_t)le32_to_cpu(hdr->len);
if (dequeued_len >= 0) { if (dequeued_len >= 0) {
size_t pkt_len;
size_t bytes_to_copy; size_t bytes_to_copy;
pkt_len = (size_t)le32_to_cpu(hdr->len);
bytes_to_copy = min(user_buf_len, pkt_len); bytes_to_copy = min(user_buf_len, pkt_len);
if (bytes_to_copy) { if (bytes_to_copy) {
...@@ -466,7 +464,6 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, ...@@ -466,7 +464,6 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,
dequeued_len = err; dequeued_len = err;
} else { } else {
user_buf_len -= bytes_to_copy; user_buf_len -= bytes_to_copy;
skb_pull(skb, bytes_to_copy);
} }
spin_lock_bh(&vvs->rx_lock); spin_lock_bh(&vvs->rx_lock);
...@@ -484,7 +481,7 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, ...@@ -484,7 +481,7 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,
msg->msg_flags |= MSG_EOR; msg->msg_flags |= MSG_EOR;
} }
virtio_transport_dec_rx_pkt(vvs, skb); virtio_transport_dec_rx_pkt(vvs, pkt_len);
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -1040,7 +1037,7 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk, ...@@ -1040,7 +1037,7 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk,
spin_lock_bh(&vvs->rx_lock); spin_lock_bh(&vvs->rx_lock);
can_enqueue = virtio_transport_inc_rx_pkt(vvs, skb); can_enqueue = virtio_transport_inc_rx_pkt(vvs, len);
if (!can_enqueue) { if (!can_enqueue) {
free_pkt = true; free_pkt = true;
goto out; goto out;
......
...@@ -860,6 +860,114 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts) ...@@ -860,6 +860,114 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
close(fd); close(fd);
} }
#define INV_BUF_TEST_DATA_LEN 512
static void test_inv_buf_client(const struct test_opts *opts, bool stream)
{
unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
ssize_t ret;
int fd;
if (stream)
fd = vsock_stream_connect(opts->peer_cid, 1234);
else
fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
if (fd < 0) {
perror("connect");
exit(EXIT_FAILURE);
}
control_expectln("SENDDONE");
/* Use invalid buffer here. */
ret = recv(fd, NULL, sizeof(data), 0);
if (ret != -1) {
fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
exit(EXIT_FAILURE);
}
if (errno != ENOMEM) {
fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
exit(EXIT_FAILURE);
}
ret = recv(fd, data, sizeof(data), MSG_DONTWAIT);
if (stream) {
/* For SOCK_STREAM we must continue reading. */
if (ret != sizeof(data)) {
fprintf(stderr, "expected recv(2) success, got %zi\n", ret);
exit(EXIT_FAILURE);
}
/* Don't check errno in case of success. */
} else {
/* For SOCK_SEQPACKET socket's queue must be empty. */
if (ret != -1) {
fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
exit(EXIT_FAILURE);
}
if (errno != EAGAIN) {
fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
exit(EXIT_FAILURE);
}
}
control_writeln("DONE");
close(fd);
}
static void test_inv_buf_server(const struct test_opts *opts, bool stream)
{
unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
ssize_t res;
int fd;
if (stream)
fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
else
fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
if (fd < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
res = send(fd, data, sizeof(data), 0);
if (res != sizeof(data)) {
fprintf(stderr, "unexpected send(2) result %zi\n", res);
exit(EXIT_FAILURE);
}
control_writeln("SENDDONE");
control_expectln("DONE");
close(fd);
}
static void test_stream_inv_buf_client(const struct test_opts *opts)
{
test_inv_buf_client(opts, true);
}
static void test_stream_inv_buf_server(const struct test_opts *opts)
{
test_inv_buf_server(opts, true);
}
static void test_seqpacket_inv_buf_client(const struct test_opts *opts)
{
test_inv_buf_client(opts, false);
}
static void test_seqpacket_inv_buf_server(const struct test_opts *opts)
{
test_inv_buf_server(opts, false);
}
static struct test_case test_cases[] = { static struct test_case test_cases[] = {
{ {
.name = "SOCK_STREAM connection reset", .name = "SOCK_STREAM connection reset",
...@@ -920,6 +1028,16 @@ static struct test_case test_cases[] = { ...@@ -920,6 +1028,16 @@ static struct test_case test_cases[] = {
.run_client = test_seqpacket_bigmsg_client, .run_client = test_seqpacket_bigmsg_client,
.run_server = test_seqpacket_bigmsg_server, .run_server = test_seqpacket_bigmsg_server,
}, },
{
.name = "SOCK_STREAM test invalid buffer",
.run_client = test_stream_inv_buf_client,
.run_server = test_stream_inv_buf_server,
},
{
.name = "SOCK_SEQPACKET test invalid buffer",
.run_client = test_seqpacket_inv_buf_client,
.run_server = test_seqpacket_inv_buf_server,
},
{}, {},
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment