| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * VMware vSockets Driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2007-2013 VMware, Inc. All rights reserved. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 7 | | - * under the terms of the GNU General Public License as published by the Free |
|---|
| 8 | | - * Software Foundation version 2 and no later version. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 13 | | - * more details. |
|---|
| 14 | 6 | */ |
|---|
| 15 | 7 | |
|---|
| 16 | 8 | #include <linux/types.h> |
|---|
| .. | .. |
|---|
| 65 | 57 | static u16 vmci_transport_new_proto_supported_versions(void); |
|---|
| 66 | 58 | static bool vmci_transport_proto_to_notify_struct(struct sock *sk, u16 *proto, |
|---|
| 67 | 59 | bool old_pkt_proto); |
|---|
| 60 | +static bool vmci_check_transport(struct vsock_sock *vsk); |
|---|
| 68 | 61 | |
|---|
| 69 | 62 | struct vmci_transport_recv_pkt_info { |
|---|
| 70 | 63 | struct work_struct work; |
|---|
| .. | .. |
|---|
| 81 | 74 | static u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; |
|---|
| 82 | 75 | |
|---|
| 83 | 76 | static int PROTOCOL_OVERRIDE = -1; |
|---|
| 84 | | - |
|---|
| 85 | | -#define VMCI_TRANSPORT_DEFAULT_QP_SIZE_MIN 128 |
|---|
| 86 | | -#define VMCI_TRANSPORT_DEFAULT_QP_SIZE 262144 |
|---|
| 87 | | -#define VMCI_TRANSPORT_DEFAULT_QP_SIZE_MAX 262144 |
|---|
| 88 | | - |
|---|
| 89 | | -/* The default peer timeout indicates how long we will wait for a peer response |
|---|
| 90 | | - * to a control message. |
|---|
| 91 | | - */ |
|---|
| 92 | | -#define VSOCK_DEFAULT_CONNECT_TIMEOUT (2 * HZ) |
|---|
| 93 | 77 | |
|---|
| 94 | 78 | /* Helper function to convert from a VMCI error code to a VSock error code. */ |
|---|
| 95 | 79 | |
|---|
| .. | .. |
|---|
| 663 | 647 | static bool vmci_transport_stream_allow(u32 cid, u32 port) |
|---|
| 664 | 648 | { |
|---|
| 665 | 649 | static const u32 non_socket_contexts[] = { |
|---|
| 666 | | - VMADDR_CID_RESERVED, |
|---|
| 650 | + VMADDR_CID_LOCAL, |
|---|
| 667 | 651 | }; |
|---|
| 668 | 652 | int i; |
|---|
| 669 | 653 | |
|---|
| .. | .. |
|---|
| 1020 | 1004 | return -ECONNREFUSED; |
|---|
| 1021 | 1005 | } |
|---|
| 1022 | 1006 | |
|---|
| 1023 | | - pending = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL, |
|---|
| 1024 | | - sk->sk_type, 0); |
|---|
| 1007 | + pending = vsock_create_connected(sk); |
|---|
| 1025 | 1008 | if (!pending) { |
|---|
| 1026 | 1009 | vmci_transport_send_reset(sk, pkt); |
|---|
| 1027 | 1010 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 1034 | 1017 | vsock_addr_init(&vpending->remote_addr, pkt->dg.src.context, |
|---|
| 1035 | 1018 | pkt->src_port); |
|---|
| 1036 | 1019 | |
|---|
| 1020 | + err = vsock_assign_transport(vpending, vsock_sk(sk)); |
|---|
| 1021 | + /* Transport assigned (looking at remote_addr) must be the same |
|---|
| 1022 | + * where we received the request. |
|---|
| 1023 | + */ |
|---|
| 1024 | + if (err || !vmci_check_transport(vpending)) { |
|---|
| 1025 | + vmci_transport_send_reset(sk, pkt); |
|---|
| 1026 | + sock_put(pending); |
|---|
| 1027 | + return err; |
|---|
| 1028 | + } |
|---|
| 1029 | + |
|---|
| 1037 | 1030 | /* If the proposed size fits within our min/max, accept it. Otherwise |
|---|
| 1038 | 1031 | * propose our own size. |
|---|
| 1039 | 1032 | */ |
|---|
| 1040 | | - if (pkt->u.size >= vmci_trans(vpending)->queue_pair_min_size && |
|---|
| 1041 | | - pkt->u.size <= vmci_trans(vpending)->queue_pair_max_size) { |
|---|
| 1033 | + if (pkt->u.size >= vpending->buffer_min_size && |
|---|
| 1034 | + pkt->u.size <= vpending->buffer_max_size) { |
|---|
| 1042 | 1035 | qp_size = pkt->u.size; |
|---|
| 1043 | 1036 | } else { |
|---|
| 1044 | | - qp_size = vmci_trans(vpending)->queue_pair_size; |
|---|
| 1037 | + qp_size = vpending->buffer_size; |
|---|
| 1045 | 1038 | } |
|---|
| 1046 | 1039 | |
|---|
| 1047 | 1040 | /* Figure out if we are using old or new requests based on the |
|---|
| .. | .. |
|---|
| 1105 | 1098 | } |
|---|
| 1106 | 1099 | |
|---|
| 1107 | 1100 | vsock_add_pending(sk, pending); |
|---|
| 1108 | | - sk->sk_ack_backlog++; |
|---|
| 1101 | + sk_acceptq_added(sk); |
|---|
| 1109 | 1102 | |
|---|
| 1110 | 1103 | pending->sk_state = TCP_SYN_SENT; |
|---|
| 1111 | 1104 | vmci_trans(vpending)->produce_size = |
|---|
| 1112 | 1105 | vmci_trans(vpending)->consume_size = qp_size; |
|---|
| 1113 | | - vmci_trans(vpending)->queue_pair_size = qp_size; |
|---|
| 1106 | + vpending->buffer_size = qp_size; |
|---|
| 1114 | 1107 | |
|---|
| 1115 | 1108 | vmci_trans(vpending)->notify_ops->process_request(pending); |
|---|
| 1116 | 1109 | |
|---|
| .. | .. |
|---|
| 1404 | 1397 | vsk->ignore_connecting_rst = false; |
|---|
| 1405 | 1398 | |
|---|
| 1406 | 1399 | /* Verify that we're OK with the proposed queue pair size */ |
|---|
| 1407 | | - if (pkt->u.size < vmci_trans(vsk)->queue_pair_min_size || |
|---|
| 1408 | | - pkt->u.size > vmci_trans(vsk)->queue_pair_max_size) { |
|---|
| 1400 | + if (pkt->u.size < vsk->buffer_min_size || |
|---|
| 1401 | + pkt->u.size > vsk->buffer_max_size) { |
|---|
| 1409 | 1402 | err = -EINVAL; |
|---|
| 1410 | 1403 | goto destroy; |
|---|
| 1411 | 1404 | } |
|---|
| .. | .. |
|---|
| 1510 | 1503 | vsk->sent_request = false; |
|---|
| 1511 | 1504 | vsk->ignore_connecting_rst = true; |
|---|
| 1512 | 1505 | |
|---|
| 1513 | | - err = vmci_transport_send_conn_request( |
|---|
| 1514 | | - sk, vmci_trans(vsk)->queue_pair_size); |
|---|
| 1506 | + err = vmci_transport_send_conn_request(sk, vsk->buffer_size); |
|---|
| 1515 | 1507 | if (err < 0) |
|---|
| 1516 | 1508 | err = vmci_transport_error_to_vsock_error(err); |
|---|
| 1517 | 1509 | else |
|---|
| .. | .. |
|---|
| 1595 | 1587 | INIT_LIST_HEAD(&vmci_trans(vsk)->elem); |
|---|
| 1596 | 1588 | vmci_trans(vsk)->sk = &vsk->sk; |
|---|
| 1597 | 1589 | spin_lock_init(&vmci_trans(vsk)->lock); |
|---|
| 1598 | | - if (psk) { |
|---|
| 1599 | | - vmci_trans(vsk)->queue_pair_size = |
|---|
| 1600 | | - vmci_trans(psk)->queue_pair_size; |
|---|
| 1601 | | - vmci_trans(vsk)->queue_pair_min_size = |
|---|
| 1602 | | - vmci_trans(psk)->queue_pair_min_size; |
|---|
| 1603 | | - vmci_trans(vsk)->queue_pair_max_size = |
|---|
| 1604 | | - vmci_trans(psk)->queue_pair_max_size; |
|---|
| 1605 | | - } else { |
|---|
| 1606 | | - vmci_trans(vsk)->queue_pair_size = |
|---|
| 1607 | | - VMCI_TRANSPORT_DEFAULT_QP_SIZE; |
|---|
| 1608 | | - vmci_trans(vsk)->queue_pair_min_size = |
|---|
| 1609 | | - VMCI_TRANSPORT_DEFAULT_QP_SIZE_MIN; |
|---|
| 1610 | | - vmci_trans(vsk)->queue_pair_max_size = |
|---|
| 1611 | | - VMCI_TRANSPORT_DEFAULT_QP_SIZE_MAX; |
|---|
| 1612 | | - } |
|---|
| 1613 | 1590 | |
|---|
| 1614 | 1591 | return 0; |
|---|
| 1615 | 1592 | } |
|---|
| .. | .. |
|---|
| 1733 | 1710 | if (!dg) |
|---|
| 1734 | 1711 | return -ENOMEM; |
|---|
| 1735 | 1712 | |
|---|
| 1736 | | - memcpy_from_msg(VMCI_DG_PAYLOAD(dg), msg, len); |
|---|
| 1713 | + err = memcpy_from_msg(VMCI_DG_PAYLOAD(dg), msg, len); |
|---|
| 1714 | + if (err) { |
|---|
| 1715 | + kfree(dg); |
|---|
| 1716 | + return err; |
|---|
| 1717 | + } |
|---|
| 1737 | 1718 | |
|---|
| 1738 | 1719 | dg->dst = vmci_make_handle(remote_addr->svm_cid, |
|---|
| 1739 | 1720 | remote_addr->svm_port); |
|---|
| .. | .. |
|---|
| 1825 | 1806 | |
|---|
| 1826 | 1807 | if (vmci_transport_old_proto_override(&old_pkt_proto) && |
|---|
| 1827 | 1808 | old_pkt_proto) { |
|---|
| 1828 | | - err = vmci_transport_send_conn_request( |
|---|
| 1829 | | - sk, vmci_trans(vsk)->queue_pair_size); |
|---|
| 1809 | + err = vmci_transport_send_conn_request(sk, vsk->buffer_size); |
|---|
| 1830 | 1810 | if (err < 0) { |
|---|
| 1831 | 1811 | sk->sk_state = TCP_CLOSE; |
|---|
| 1832 | 1812 | return err; |
|---|
| .. | .. |
|---|
| 1834 | 1814 | } else { |
|---|
| 1835 | 1815 | int supported_proto_versions = |
|---|
| 1836 | 1816 | vmci_transport_new_proto_supported_versions(); |
|---|
| 1837 | | - err = vmci_transport_send_conn_request2( |
|---|
| 1838 | | - sk, vmci_trans(vsk)->queue_pair_size, |
|---|
| 1817 | + err = vmci_transport_send_conn_request2(sk, vsk->buffer_size, |
|---|
| 1839 | 1818 | supported_proto_versions); |
|---|
| 1840 | 1819 | if (err < 0) { |
|---|
| 1841 | 1820 | sk->sk_state = TCP_CLOSE; |
|---|
| .. | .. |
|---|
| 1886 | 1865 | static bool vmci_transport_stream_is_active(struct vsock_sock *vsk) |
|---|
| 1887 | 1866 | { |
|---|
| 1888 | 1867 | return !vmci_handle_is_invalid(vmci_trans(vsk)->qp_handle); |
|---|
| 1889 | | -} |
|---|
| 1890 | | - |
|---|
| 1891 | | -static u64 vmci_transport_get_buffer_size(struct vsock_sock *vsk) |
|---|
| 1892 | | -{ |
|---|
| 1893 | | - return vmci_trans(vsk)->queue_pair_size; |
|---|
| 1894 | | -} |
|---|
| 1895 | | - |
|---|
| 1896 | | -static u64 vmci_transport_get_min_buffer_size(struct vsock_sock *vsk) |
|---|
| 1897 | | -{ |
|---|
| 1898 | | - return vmci_trans(vsk)->queue_pair_min_size; |
|---|
| 1899 | | -} |
|---|
| 1900 | | - |
|---|
| 1901 | | -static u64 vmci_transport_get_max_buffer_size(struct vsock_sock *vsk) |
|---|
| 1902 | | -{ |
|---|
| 1903 | | - return vmci_trans(vsk)->queue_pair_max_size; |
|---|
| 1904 | | -} |
|---|
| 1905 | | - |
|---|
| 1906 | | -static void vmci_transport_set_buffer_size(struct vsock_sock *vsk, u64 val) |
|---|
| 1907 | | -{ |
|---|
| 1908 | | - if (val < vmci_trans(vsk)->queue_pair_min_size) |
|---|
| 1909 | | - vmci_trans(vsk)->queue_pair_min_size = val; |
|---|
| 1910 | | - if (val > vmci_trans(vsk)->queue_pair_max_size) |
|---|
| 1911 | | - vmci_trans(vsk)->queue_pair_max_size = val; |
|---|
| 1912 | | - vmci_trans(vsk)->queue_pair_size = val; |
|---|
| 1913 | | -} |
|---|
| 1914 | | - |
|---|
| 1915 | | -static void vmci_transport_set_min_buffer_size(struct vsock_sock *vsk, |
|---|
| 1916 | | - u64 val) |
|---|
| 1917 | | -{ |
|---|
| 1918 | | - if (val > vmci_trans(vsk)->queue_pair_size) |
|---|
| 1919 | | - vmci_trans(vsk)->queue_pair_size = val; |
|---|
| 1920 | | - vmci_trans(vsk)->queue_pair_min_size = val; |
|---|
| 1921 | | -} |
|---|
| 1922 | | - |
|---|
| 1923 | | -static void vmci_transport_set_max_buffer_size(struct vsock_sock *vsk, |
|---|
| 1924 | | - u64 val) |
|---|
| 1925 | | -{ |
|---|
| 1926 | | - if (val < vmci_trans(vsk)->queue_pair_size) |
|---|
| 1927 | | - vmci_trans(vsk)->queue_pair_size = val; |
|---|
| 1928 | | - vmci_trans(vsk)->queue_pair_max_size = val; |
|---|
| 1929 | 1868 | } |
|---|
| 1930 | 1869 | |
|---|
| 1931 | 1870 | static int vmci_transport_notify_poll_in( |
|---|
| .. | .. |
|---|
| 2083 | 2022 | return vmci_get_context_id(); |
|---|
| 2084 | 2023 | } |
|---|
| 2085 | 2024 | |
|---|
| 2086 | | -static const struct vsock_transport vmci_transport = { |
|---|
| 2025 | +static struct vsock_transport vmci_transport = { |
|---|
| 2026 | + .module = THIS_MODULE, |
|---|
| 2087 | 2027 | .init = vmci_transport_socket_init, |
|---|
| 2088 | 2028 | .destruct = vmci_transport_destruct, |
|---|
| 2089 | 2029 | .release = vmci_transport_release, |
|---|
| .. | .. |
|---|
| 2110 | 2050 | .notify_send_pre_enqueue = vmci_transport_notify_send_pre_enqueue, |
|---|
| 2111 | 2051 | .notify_send_post_enqueue = vmci_transport_notify_send_post_enqueue, |
|---|
| 2112 | 2052 | .shutdown = vmci_transport_shutdown, |
|---|
| 2113 | | - .set_buffer_size = vmci_transport_set_buffer_size, |
|---|
| 2114 | | - .set_min_buffer_size = vmci_transport_set_min_buffer_size, |
|---|
| 2115 | | - .set_max_buffer_size = vmci_transport_set_max_buffer_size, |
|---|
| 2116 | | - .get_buffer_size = vmci_transport_get_buffer_size, |
|---|
| 2117 | | - .get_min_buffer_size = vmci_transport_get_min_buffer_size, |
|---|
| 2118 | | - .get_max_buffer_size = vmci_transport_get_max_buffer_size, |
|---|
| 2119 | 2053 | .get_local_cid = vmci_transport_get_local_cid, |
|---|
| 2120 | 2054 | }; |
|---|
| 2055 | + |
|---|
| 2056 | +static bool vmci_check_transport(struct vsock_sock *vsk) |
|---|
| 2057 | +{ |
|---|
| 2058 | + return vsk->transport == &vmci_transport; |
|---|
| 2059 | +} |
|---|
| 2060 | + |
|---|
| 2061 | +static void vmci_vsock_transport_cb(bool is_host) |
|---|
| 2062 | +{ |
|---|
| 2063 | + int features; |
|---|
| 2064 | + |
|---|
| 2065 | + if (is_host) |
|---|
| 2066 | + features = VSOCK_TRANSPORT_F_H2G; |
|---|
| 2067 | + else |
|---|
| 2068 | + features = VSOCK_TRANSPORT_F_G2H; |
|---|
| 2069 | + |
|---|
| 2070 | + vsock_core_register(&vmci_transport, features); |
|---|
| 2071 | +} |
|---|
| 2121 | 2072 | |
|---|
| 2122 | 2073 | static int __init vmci_transport_init(void) |
|---|
| 2123 | 2074 | { |
|---|
| .. | .. |
|---|
| 2135 | 2086 | pr_err("Unable to create datagram handle. (%d)\n", err); |
|---|
| 2136 | 2087 | return vmci_transport_error_to_vsock_error(err); |
|---|
| 2137 | 2088 | } |
|---|
| 2138 | | - |
|---|
| 2139 | 2089 | err = vmci_event_subscribe(VMCI_EVENT_QP_RESUMED, |
|---|
| 2140 | 2090 | vmci_transport_qp_resumed_cb, |
|---|
| 2141 | 2091 | NULL, &vmci_transport_qp_resumed_sub_id); |
|---|
| .. | .. |
|---|
| 2146 | 2096 | goto err_destroy_stream_handle; |
|---|
| 2147 | 2097 | } |
|---|
| 2148 | 2098 | |
|---|
| 2149 | | - err = vsock_core_init(&vmci_transport); |
|---|
| 2099 | + /* Register only with dgram feature, other features (H2G, G2H) will be |
|---|
| 2100 | + * registered when the first host or guest becomes active. |
|---|
| 2101 | + */ |
|---|
| 2102 | + err = vsock_core_register(&vmci_transport, VSOCK_TRANSPORT_F_DGRAM); |
|---|
| 2150 | 2103 | if (err < 0) |
|---|
| 2151 | 2104 | goto err_unsubscribe; |
|---|
| 2152 | 2105 | |
|---|
| 2106 | + err = vmci_register_vsock_callback(vmci_vsock_transport_cb); |
|---|
| 2107 | + if (err < 0) |
|---|
| 2108 | + goto err_unregister; |
|---|
| 2109 | + |
|---|
| 2153 | 2110 | return 0; |
|---|
| 2154 | 2111 | |
|---|
| 2112 | +err_unregister: |
|---|
| 2113 | + vsock_core_unregister(&vmci_transport); |
|---|
| 2155 | 2114 | err_unsubscribe: |
|---|
| 2156 | 2115 | vmci_event_unsubscribe(vmci_transport_qp_resumed_sub_id); |
|---|
| 2157 | 2116 | err_destroy_stream_handle: |
|---|
| .. | .. |
|---|
| 2177 | 2136 | vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; |
|---|
| 2178 | 2137 | } |
|---|
| 2179 | 2138 | |
|---|
| 2180 | | - vsock_core_exit(); |
|---|
| 2139 | + vmci_register_vsock_callback(NULL); |
|---|
| 2140 | + vsock_core_unregister(&vmci_transport); |
|---|
| 2181 | 2141 | } |
|---|
| 2182 | 2142 | module_exit(vmci_transport_exit); |
|---|
| 2183 | 2143 | |
|---|