get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/806078/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 806078,
    "url": "http://patchwork.ozlabs.org/api/patches/806078/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/PS1P15301MB00117CF517E0EFF548C9F572BF980@PS1P15301MB0011.APCP153.PROD.OUTLOOK.COM/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<PS1P15301MB00117CF517E0EFF548C9F572BF980@PS1P15301MB0011.APCP153.PROD.OUTLOOK.COM>",
    "list_archive_url": null,
    "date": "2017-08-26T04:52:43",
    "name": "[v3,net-next,1/1] hv_sock: implements Hyper-V transport for Virtual Sockets (AF_VSOCK)",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "85ef4d78919a84e242e9941d0ca5e25465c2af02",
    "submitter": {
        "id": 64601,
        "url": "http://patchwork.ozlabs.org/api/people/64601/?format=api",
        "name": "Dexuan Cui",
        "email": "decui@microsoft.com"
    },
    "delegate": {
        "id": 34,
        "url": "http://patchwork.ozlabs.org/api/users/34/?format=api",
        "username": "davem",
        "first_name": "David",
        "last_name": "Miller",
        "email": "davem@davemloft.net"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/PS1P15301MB00117CF517E0EFF548C9F572BF980@PS1P15301MB0011.APCP153.PROD.OUTLOOK.COM/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/806078/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/806078/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@ozlabs.org",
        "Delivered-To": "patchwork-incoming@ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=microsoft.com header.i=@microsoft.com\n\theader.b=\"bU1HjsyI\"; dkim-atps=neutral",
            "spf=none (sender IP is )\n\tsmtp.mailfrom=decui@microsoft.com; "
        ],
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xfQfs4bKSz9t4c\n\tfor <patchwork-incoming@ozlabs.org>;\n\tSat, 26 Aug 2017 14:54:13 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751232AbdHZEx4 (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tSat, 26 Aug 2017 00:53:56 -0400",
            "from mail-sg2apc01on0117.outbound.protection.outlook.com\n\t([104.47.125.117]:46000\n\t\"EHLO APC01-SG2-obe.outbound.protection.outlook.com\"\n\trhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP\n\tid S1750736AbdHZExy (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tSat, 26 Aug 2017 00:53:54 -0400",
            "from PS1P15301MB0011.APCP153.PROD.OUTLOOK.COM (10.170.183.149) by\n\tPS1P15301MB0076.APCP153.PROD.OUTLOOK.COM (10.170.184.148) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n\t15.20.13.6; Sat, 26 Aug 2017 04:53:23 +0000",
            "from PS1P15301MB0011.APCP153.PROD.OUTLOOK.COM\n\t([fe80::9c80:79a:9437:5e62]) by\n\tPS1P15301MB0011.APCP153.PROD.OUTLOOK.COM\n\t([fe80::9c80:79a:9437:5e62%4]) with mapi id 15.20.0013.008;\n\tSat, 26 Aug 2017 04:52:44 +0000"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n\ts=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version;\n\tbh=0zLna+cWtcQ2ZURsvbjSWCx40hrSAOuCbYhQe3r10KA=;\n\tb=bU1HjsyIPC59s7stTWlF4RzKk1AdaeieBy2SmuoDatXu1Dwtw+a/erksMfLL1IWHAl8JhXe7s9Ti7rO42We+wPnHNmCtLMKxp9kCxaHgQgYIDsrxl42r1xtiM0Z5QM0NIoYimgyZmpxCJtqUVyrGIrBeHmgSVVEqPeC+N+WtOn8=",
        "From": "Dexuan Cui <decui@microsoft.com>",
        "To": "\"'Jorgen S. Hansen'\" <jhansen@vmware.com>,\n\t'Stefan Hajnoczi' <stefanha@redhat.com>,\n\t\"'davem@davemloft.net'\" <davem@davemloft.net>,\n\t\"'netdev@vger.kernel.org'\" <netdev@vger.kernel.org>",
        "CC": "'Michal Kubecek' <mkubecek@suse.cz>, \"'olaf@aepfle.de'\" <olaf@aepfle.de>,\n\tStephen Hemminger <sthemmin@microsoft.com>,\n\t'Rolf Neugebauer' <rolf.neugebauer@docker.com>,\n\t\"'jasowang@redhat.com'\" <jasowang@redhat.com>,\n\t'Dave Scott' <dave.scott@docker.com>,\n\t\"'linux-kernel@vger.kernel.org'\" <linux-kernel@vger.kernel.org>,\n\t\"'apw@canonical.com'\" <apw@canonical.com>,\n\t'Marcelo Cerri' <marcelo.cerri@canonical.com>,\n\t'Dan Carpenter' <dan.carpenter@oracle.com>,\n\t\"'gregkh@linuxfoundation.org'\" <gregkh@linuxfoundation.org>,\n\t\"'joe@perches.com'\" <joe@perches.com>,\n\t\"'devel@linuxdriverproject.org'\" <devel@linuxdriverproject.org>,\n\t\"'Vitaly Kuznetsov'\" <vkuznets@redhat.com>,\n\tHaiyang Zhang <haiyangz@microsoft.com>,\n\t'George Zhang' <georgezhang@vmware.com>",
        "Subject": "[PATCH v3 net-next 1/1] hv_sock: implements Hyper-V transport for\n\tVirtual Sockets (AF_VSOCK)",
        "Thread-Topic": "[PATCH v3 net-next 1/1] hv_sock: implements Hyper-V transport\n\tfor Virtual Sockets (AF_VSOCK)",
        "Thread-Index": "AdMeJv9CmVKlGgJbTG2KNeXKIjymJg==",
        "Date": "Sat, 26 Aug 2017 04:52:43 +0000",
        "Message-ID": "<PS1P15301MB00117CF517E0EFF548C9F572BF980@PS1P15301MB0011.APCP153.PROD.OUTLOOK.COM>",
        "Accept-Language": "en-US",
        "Content-Language": "en-US",
        "X-MS-Has-Attach": "",
        "X-MS-TNEF-Correlator": "",
        "msip_labels": "MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Enabled=True;\n\tMSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_SiteId=72f988bf-86f1-41af-91ab-2d7cd011db47;\n\tMSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Ref=https://api.informationprotection.azure.com/api/72f988bf-86f1-41af-91ab-2d7cd011db47;\n\tMSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Owner=decui@microsoft.com;\n\tMSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_SetDate=2017-08-25T21:52:39.9656808-07:00;\n\tMSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Name=General;\n\tMSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Application=Microsoft\n\tAzure Information Protection;\n\tMSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Extended_MSFT_Method=Automatic;\n\tSensitivity=General",
        "authentication-results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=microsoft.com header.i=@microsoft.com\n\theader.b=\"bU1HjsyI\"; dkim-atps=neutral",
            "spf=none (sender IP is )\n\tsmtp.mailfrom=decui@microsoft.com; "
        ],
        "x-originating-ip": "[167.220.1.93]",
        "x-ms-publictraffictype": "Email",
        "x-microsoft-exchange-diagnostics": "1; PS1P15301MB0076;\n\t6:/1jVNY2GYY02B90+tVydBtf/OQeZ0imQajxzMZtmNOW2+kNtRqyuaUU3kz8km3w6E/vUayHDxu+JpyZZQoJbf6XkSVT8kM5JfluU+LlaNGv6jo1+voptS8DC94E7j3Y+5q9ebULr2+nIpmL8Q6vOgQuoOvH5ZzHuSSVGjPYoRW2NgAddlkvRHNrkCMSEqzBPctz2GiUFGkne4txXuN32YVPzG32sgnidLHR11SKdsAgjIiuByF471UfQAwjHZMrnjs+MiXU1WVbXXukfEGdL+4mQra9Pc8GjWAAPsuh7rN/8V6rTxrf/VF6XEvl8/aTQoT4BZhECOAAEN7TGChPTnw==;\n\t5:H0ORSesVCv3llAyEuqSeF/zQ/36QbhymIfvnuvSX2/yF1VrwgC9xwmhL7iUoV4Px3RWR+l6+lM1d6Ls4QTe0n/iv+YH9pPWo63RZlxh+stBZHufrmDQ8PlEY4PNgxfQO4/ipDvjarjGkoU/zefwiXg==;\n\t24:5QYu4XoQxntlcCmHk3BhCFcnDee7orkfoMTiv9V/VqKXIhpkvl375HgvjXqpP5la5KmkuJ0yjlr7MLcaFfiy3paUaBMZSx9aWYlBd4iGLGM=;\n\t7:94+KOIabbQRV/vvVfcTnpbav5OsMc8X61iIN39uY8SBHG6qUWdQrrj/fm2w9odY8Yez4pmqXtGUvDdixarKQEM0kYww2bDEvzhI2pYkNymIwkvhz9vqWfxkN0N6M9+p5LSHMRecJxPOKMX51No8vwPSxfZ9lV3/9MFYc/vLd+dSoliw0RhEsKjHwo0z34u7NyTh0lkFQw4/+TMkEyhCdx9QEJFf8QCEnYeQ1utZ4WSg=",
        "x-ms-exchange-antispam-srfa-diagnostics": "SSOS;",
        "x-ms-office365-filtering-correlation-id": "a11eeb48-2dfe-406e-d897-08d4ec3e4a0f",
        "x-ms-office365-filtering-ht": "Tenant",
        "x-microsoft-antispam": "UriScan:; BCL:0; PCL:0;\n\tRULEID:(300000500095)(300135000095)(300000501095)(300135300095)(22001)(300000502095)(300135100095)(2017030254152)(48565401081)(300000503095)(300135400095)(2017052603199)(201703131423075)(201703031133081)(201702281549075)(300000504095)(300135200095)(300000505095)(300135600095)(300000506095)(300135500095);\n\tSRVR:PS1P15301MB0076; ",
        "x-ms-traffictypediagnostic": "PS1P15301MB0076:",
        "x-exchange-antispam-report-test": "UriScan:(61668805478150)(158342451672863)(278428928389397)(89211679590171)(21532816269658)(198206253151910);",
        "x-microsoft-antispam-prvs": "<PS1P15301MB0076C3EA5F29B389D12474A3BF980@PS1P15301MB0076.APCP153.PROD.OUTLOOK.COM>",
        "x-exchange-antispam-report-cfa-test": "BCL:0; PCL:0;\n\tRULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(61425038)(6040450)(2401047)(5005006)(8121501046)(10201501046)(3002001)(93006095)(93001095)(100000703101)(100105400095)(6055026)(61426038)(61427038)(6041248)(20161123562025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123560025)(20161123555025)(20161123564025)(20161123558100)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);\n\tSRVR:PS1P15301MB0076; BCL:0; PCL:0;\n\tRULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);\n\tSRVR:PS1P15301MB0076; ",
        "x-forefront-prvs": "04111BAC64",
        "x-forefront-antispam-report": "SFV:NSPM;\n\tSFS:(10019020)(6009001)(39860400002)(47760400005)(199003)(189002)(3905003)(3280700002)(106356001)(81156014)(86612001)(7416002)(81166006)(3660700001)(14454004)(5005710100001)(3846002)(5250100002)(7696004)(6116002)(7736002)(102836003)(2906002)(8990500004)(4326008)(305945005)(478600001)(105586002)(10290500003)(25786009)(55016002)(53936002)(966005)(33656002)(5660300001)(66066001)(9686003)(6306002)(2900100001)(54906002)(575784001)(68736007)(86362001)(101416001)(189998001)(97736004)(50986999)(53946003)(6506006)(74316002)(10090500001)(8936002)(6436002)(54356999)(8676002)(2004002)(491001)(579004)(559001);\n\tDIR:OUT; SFP:1102; SCL:1; SRVR:PS1P15301MB0076;\n\tH:PS1P15301MB0011.APCP153.PROD.OUTLOOK.COM; FPR:; SPF:None;\n\tPTR:InfoNoRecords; A:1; MX:1; LANG:en; ",
        "received-spf": "None (protection.outlook.com: microsoft.com does not designate\n\tpermitted sender hosts)",
        "spamdiagnosticoutput": "1:99",
        "spamdiagnosticmetadata": "NSPM",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "quoted-printable",
        "MIME-Version": "1.0",
        "X-OriginatorOrg": "microsoft.com",
        "X-MS-Exchange-CrossTenant-originalarrivaltime": "26 Aug 2017 04:52:43.5147\n\t(UTC)",
        "X-MS-Exchange-CrossTenant-fromentityheader": "Hosted",
        "X-MS-Exchange-CrossTenant-id": "72f988bf-86f1-41af-91ab-2d7cd011db47",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "PS1P15301MB0076",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "Hyper-V Sockets (hv_sock) supplies a byte-stream based communication\nmechanism between the host and the guest. It uses VMBus ringbuffer as the\ntransportation layer.\n\nWith hv_sock, applications between the host (Windows 10, Windows Server\n2016 or newer) and the guest can talk with each other using the traditional\nsocket APIs.\n\nMore info about Hyper-V Sockets is available here:\n\n\"Make your own integration services\":\nhttps://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service\n\nThe patch implements the necessary support in Linux guest by introducing a new\nvsock transport for AF_VSOCK.\n\nSigned-off-by: Dexuan Cui <decui@microsoft.com>\nCc: K. Y. Srinivasan <kys@microsoft.com>\nCc: Haiyang Zhang <haiyangz@microsoft.com>\nCc: Stephen Hemminger <sthemmin@microsoft.com>\nCc: Andy King <acking@vmware.com>\nCc: Dmitry Torokhov <dtor@vmware.com>\nCc: George Zhang <georgezhang@vmware.com>\nCc: Jorgen Hansen <jhansen@vmware.com>\nCc: Reilly Grant <grantr@vmware.com>\nCc: Asias He <asias@redhat.com>\nCc: Stefan Hajnoczi <stefanha@redhat.com>\nCc: Vitaly Kuznetsov <vkuznets@redhat.com>\nCc: Cathy Avery <cavery@redhat.com>\nCc: Rolf Neugebauer <rolf.neugebauer@docker.com>\nCc: Marcelo Cerri <marcelo.cerri@canonical.com>\n\n---\n\nChanges in v2:\n\tfixed hvs_stream_allow() for cid and the comments\n\t\tThanks Stefan Hajnoczi!\n\n\tadded proper locking when using vsock_enqueue_accept()\n\t\tThanks Stefan Hajnoczi and Jorgen Hansen!\n\t\t\n\n\tThe previous v1 patch is not needed any more:\n \t[PATCH net-next 2/3] vsock: fix vsock_dequeue/enqueue_accept race\n\n\tAnother previous v1 patch is being discussed in another thread:\n\t    vsock: only load vmci transport on VMware hypervisor by default\n\nChanges in v3 (addressed David Millers's comments):\n\tused better naming: VMBUS_PKT_TRAILER_SIZE\n\tbetter handled fin_sent: removed atomic\n\tremoved \"inline\" tags\n\tbetter handled uuid service_id assignments: avoid pointers\n\n MAINTAINERS                      |   1 +\n net/vmw_vsock/Kconfig            |  12 +\n net/vmw_vsock/Makefile           |   3 +\n net/vmw_vsock/hyperv_transport.c | 904 +++++++++++++++++++++++++++++++++++++++\n 4 files changed, 920 insertions(+)\n create mode 100644 net/vmw_vsock/hyperv_transport.c",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 2db0f8c..dae0573 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -6279,6 +6279,7 @@ F:\tdrivers/net/hyperv/\n F:\tdrivers/scsi/storvsc_drv.c\n F:\tdrivers/uio/uio_hv_generic.c\n F:\tdrivers/video/fbdev/hyperv_fb.c\n+F:\tnet/vmw_vsock/hyperv_transport.c\n F:\tinclude/linux/hyperv.h\n F:\ttools/hv/\n F:\tDocumentation/ABI/stable/sysfs-bus-vmbus\ndiff --git a/net/vmw_vsock/Kconfig b/net/vmw_vsock/Kconfig\nindex a7ae09d..3f52929 100644\n--- a/net/vmw_vsock/Kconfig\n+++ b/net/vmw_vsock/Kconfig\n@@ -46,3 +46,15 @@ config VIRTIO_VSOCKETS_COMMON\n \t  This option is selected by any driver which needs to access\n \t  the virtio_vsock.  The module will be called\n \t  vmw_vsock_virtio_transport_common.\n+\n+config HYPERV_VSOCKETS\n+\ttristate \"Hyper-V transport for Virtual Sockets\"\n+\tdepends on VSOCKETS && HYPERV\n+\thelp\n+\t  This module implements a Hyper-V transport for Virtual Sockets.\n+\n+\t  Enable this transport if your Virtual Machine host supports Virtual\n+\t  Sockets over Hyper-V VMBus.\n+\n+\t  To compile this driver as a module, choose M here: the module will be\n+\t  called hv_sock. If unsure, say N.\ndiff --git a/net/vmw_vsock/Makefile b/net/vmw_vsock/Makefile\nindex 09fc2eb..e63d574 100644\n--- a/net/vmw_vsock/Makefile\n+++ b/net/vmw_vsock/Makefile\n@@ -2,6 +2,7 @@ obj-$(CONFIG_VSOCKETS) += vsock.o\n obj-$(CONFIG_VMWARE_VMCI_VSOCKETS) += vmw_vsock_vmci_transport.o\n obj-$(CONFIG_VIRTIO_VSOCKETS) += vmw_vsock_virtio_transport.o\n obj-$(CONFIG_VIRTIO_VSOCKETS_COMMON) += vmw_vsock_virtio_transport_common.o\n+obj-$(CONFIG_HYPERV_VSOCKETS) += hv_sock.o\n \n vsock-y += af_vsock.o af_vsock_tap.o vsock_addr.o\n \n@@ -11,3 +12,5 @@ vmw_vsock_vmci_transport-y += vmci_transport.o vmci_transport_notify.o \\\n vmw_vsock_virtio_transport-y += virtio_transport.o\n \n vmw_vsock_virtio_transport_common-y += virtio_transport_common.o\n+\n+hv_sock-y += hyperv_transport.o\ndiff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c\nnew file mode 100644\nindex 0000000..14ed5a3\n--- /dev/null\n+++ b/net/vmw_vsock/hyperv_transport.c\n@@ -0,0 +1,904 @@\n+/*\n+ * Hyper-V transport for vsock\n+ *\n+ * Hyper-V Sockets supplies a byte-stream based communication mechanism\n+ * between the host and the VM. This driver implements the necessary\n+ * support in the VM by introducing the new vsock transport.\n+ *\n+ * Copyright (c) 2017, Microsoft Corporation.\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms and conditions of the GNU General Public License,\n+ * version 2, as published by the Free Software Foundation.\n+ *\n+ * This program is distributed in the hope it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n+ * more details.\n+ *\n+ */\n+#include <linux/module.h>\n+#include <linux/vmalloc.h>\n+#include <linux/hyperv.h>\n+#include <net/sock.h>\n+#include <net/af_vsock.h>\n+\n+/* The host side's design of the feature requires 6 exact 4KB pages for\n+ * recv/send rings respectively -- this is suboptimal considering memory\n+ * consumption, however unluckily we have to live with it, before the\n+ * host comes up with a better design in the future.\n+ */\n+#define PAGE_SIZE_4K\t\t4096\n+#define RINGBUFFER_HVS_RCV_SIZE (PAGE_SIZE_4K * 6)\n+#define RINGBUFFER_HVS_SND_SIZE (PAGE_SIZE_4K * 6)\n+\n+/* The MTU is 16KB per the host side's design */\n+#define HVS_MTU_SIZE\t\t(1024 * 16)\n+\n+struct vmpipe_proto_header {\n+\tu32 pkt_type;\n+\tu32 data_size;\n+};\n+\n+/* For recv, we use the VMBus in-place packet iterator APIs to directly copy\n+ * data from the ringbuffer into the userspace buffer.\n+ */\n+struct hvs_recv_buf {\n+\t/* The header before the payload data */\n+\tstruct vmpipe_proto_header hdr;\n+\n+\t/* The payload */\n+\tu8 data[HVS_MTU_SIZE];\n+};\n+\n+/* We can send up to HVS_MTU_SIZE bytes of payload to the host, but let's use\n+ * a small size, i.e. HVS_SEND_BUF_SIZE, to minimize the dynamically-allocated\n+ * buffer, because tests show there is no significant performance difference.\n+ *\n+ * Note: the buffer can be eliminated in the future when we add new VMBus\n+ * ringbuffer APIs that allow us to directly copy data from userspace buffer\n+ * to VMBus ringbuffer.\n+ */\n+#define HVS_SEND_BUF_SIZE (PAGE_SIZE_4K - sizeof(struct vmpipe_proto_header))\n+\n+struct hvs_send_buf {\n+\t/* The header before the payload data */\n+\tstruct vmpipe_proto_header hdr;\n+\n+\t/* The payload */\n+\tu8 data[HVS_SEND_BUF_SIZE];\n+};\n+\n+#define HVS_HEADER_LEN\t(sizeof(struct vmpacket_descriptor) + \\\n+\t\t\t sizeof(struct vmpipe_proto_header))\n+\n+/* See 'prev_indices' in hv_ringbuffer_read(), hv_ringbuffer_write(), and\n+ * __hv_pkt_iter_next().\n+ */\n+#define VMBUS_PKT_TRAILER_SIZE\t(sizeof(u64))\n+\n+#define HVS_PKT_LEN(payload_len)\t(HVS_HEADER_LEN + \\\n+\t\t\t\t\t ALIGN((payload_len), 8) + \\\n+\t\t\t\t\t VMBUS_PKT_TRAILER_SIZE)\n+\n+union hvs_service_id {\n+\tuuid_le\tsrv_id;\n+\n+\tstruct {\n+\t\tunsigned int svm_port;\n+\t\tunsigned char b[sizeof(uuid_le) - sizeof(unsigned int)];\n+\t};\n+};\n+\n+/* Per-socket state (accessed via vsk->trans) */\n+struct hvsock {\n+\tstruct vsock_sock *vsk;\n+\n+\tuuid_le vm_srv_id;\n+\tuuid_le host_srv_id;\n+\n+\tstruct vmbus_channel *chan;\n+\tstruct vmpacket_descriptor *recv_desc;\n+\n+\t/* The length of the payload not delivered to userland yet */\n+\tu32 recv_data_len;\n+\t/* The offset of the payload */\n+\tu32 recv_data_off;\n+\n+\t/* Have we sent the zero-length packet (FIN)? */\n+\tbool fin_sent;\n+};\n+\n+/* In the VM, we support Hyper-V Sockets with AF_VSOCK, and the endpoint is\n+ * <cid, port> (see struct sockaddr_vm). Note: cid is not really used here:\n+ * when we write apps to connect to the host, we can only use VMADDR_CID_ANY\n+ * or VMADDR_CID_HOST (both are equivalent) as the remote cid, and when we\n+ * write apps to bind() & listen() in the VM, we can only use VMADDR_CID_ANY\n+ * as the local cid.\n+ *\n+ * On the host, Hyper-V Sockets are supported by Winsock AF_HYPERV:\n+ * https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-\n+ * guide/make-integration-service, and the endpoint is <VmID, ServiceId> with\n+ * the below sockaddr:\n+ *\n+ * struct SOCKADDR_HV\n+ * {\n+ *    ADDRESS_FAMILY Family;\n+ *    USHORT Reserved;\n+ *    GUID VmId;\n+ *    GUID ServiceId;\n+ * };\n+ * Note: VmID is not used by Linux VM and actually it isn't transmitted via\n+ * VMBus, because here it's obvious the host and the VM can easily identify\n+ * each other. Though the VmID is useful on the host, especially in the case\n+ * of Windows container, Linux VM doesn't need it at all.\n+ *\n+ * To make use of the AF_VSOCK infrastructure in Linux VM, we have to limit\n+ * the available GUID space of SOCKADDR_HV so that we can create a mapping\n+ * between AF_VSOCK port and SOCKADDR_HV Service GUID. The rule of writing\n+ * Hyper-V Sockets apps on the host and in Linux VM is:\n+ *\n+ ****************************************************************************\n+ * The only valid Service GUIDs, from the perspectives of both the host and *\n+ * Linux VM, that can be connected by the other end, must conform to this   *\n+ * format: <port>-facb-11e6-bd58-64006a7986d3, and the \"port\" must be in    *\n+ * this range [0, 0x7FFFFFFF].                                              *\n+ ****************************************************************************\n+ *\n+ * When we write apps on the host to connect(), the GUID ServiceID is used.\n+ * When we write apps in Linux VM to connect(), we only need to specify the\n+ * port and the driver will form the GUID and use that to request the host.\n+ *\n+ * From the perspective of Linux VM:\n+ * 1. the local ephemeral port (i.e. the local auto-bound port when we call\n+ * connect() without explicit bind()) is generated by __vsock_bind_stream(),\n+ * and the range is [1024, 0xFFFFFFFF).\n+ * 2. the remote ephemeral port (i.e. the auto-generated remote port for\n+ * a connect request initiated by the host's connect()) is generated by\n+ * hvs_remote_addr_init() and the range is [0x80000000, 0xFFFFFFFF).\n+ */\n+\n+#define MAX_LISTEN_PORT\t\t\t((u32)0x7FFFFFFF)\n+#define MAX_VM_LISTEN_PORT\t\tMAX_LISTEN_PORT\n+#define MAX_HOST_LISTEN_PORT\t\tMAX_LISTEN_PORT\n+#define MIN_HOST_EPHEMERAL_PORT\t\t(MAX_HOST_LISTEN_PORT + 1)\n+\n+/* 00000000-facb-11e6-bd58-64006a7986d3 */\n+static const uuid_le srv_id_template =\n+\tUUID_LE(0x00000000, 0xfacb, 0x11e6, 0xbd, 0x58,\n+\t\t0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3);\n+\n+static bool is_valid_srv_id(const uuid_le *id)\n+{\n+\treturn !memcmp(&id->b[4], &srv_id_template.b[4], sizeof(uuid_le) - 4);\n+}\n+\n+static unsigned int get_port_by_srv_id(const uuid_le *svr_id)\n+{\n+\treturn *((unsigned int *)svr_id);\n+}\n+\n+static void hvs_addr_init(struct sockaddr_vm *addr, const uuid_le *svr_id)\n+{\n+\tunsigned int port = get_port_by_srv_id(svr_id);\n+\n+\tvsock_addr_init(addr, VMADDR_CID_ANY, port);\n+}\n+\n+static void hvs_remote_addr_init(struct sockaddr_vm *remote,\n+\t\t\t\t struct sockaddr_vm *local)\n+{\n+\tstatic u32 host_ephemeral_port = MIN_HOST_EPHEMERAL_PORT;\n+\tstruct sock *sk;\n+\n+\tvsock_addr_init(remote, VMADDR_CID_ANY, VMADDR_PORT_ANY);\n+\n+\twhile (1) {\n+\t\t/* Wrap around ? */\n+\t\tif (host_ephemeral_port < MIN_HOST_EPHEMERAL_PORT ||\n+\t\t    host_ephemeral_port == VMADDR_PORT_ANY)\n+\t\t\thost_ephemeral_port = MIN_HOST_EPHEMERAL_PORT;\n+\n+\t\tremote->svm_port = host_ephemeral_port++;\n+\n+\t\tsk = vsock_find_connected_socket(remote, local);\n+\t\tif (!sk) {\n+\t\t\t/* Found an available ephemeral port */\n+\t\t\treturn;\n+\t\t}\n+\n+\t\t/* Release refcnt got in vsock_find_connected_socket */\n+\t\tsock_put(sk);\n+\t}\n+}\n+\n+static void hvs_set_channel_pending_send_size(struct vmbus_channel *chan)\n+{\n+\tset_channel_pending_send_size(chan,\n+\t\t\t\t      HVS_PKT_LEN(HVS_SEND_BUF_SIZE));\n+\n+\t/* See hvs_stream_has_space(): we must make sure the host has seen\n+\t * the new pending send size, before we can re-check the writable\n+\t * bytes.\n+\t */\n+\tvirt_mb();\n+}\n+\n+static void hvs_clear_channel_pending_send_size(struct vmbus_channel *chan)\n+{\n+\tset_channel_pending_send_size(chan, 0);\n+\n+\t/* Ditto */\n+\tvirt_mb();\n+}\n+\n+static bool hvs_channel_readable(struct vmbus_channel *chan)\n+{\n+\tu32 readable = hv_get_bytes_to_read(&chan->inbound);\n+\n+\t/* 0-size payload means FIN */\n+\treturn readable >= HVS_PKT_LEN(0);\n+}\n+\n+static int hvs_channel_readable_payload(struct vmbus_channel *chan)\n+{\n+\tu32 readable = hv_get_bytes_to_read(&chan->inbound);\n+\n+\tif (readable > HVS_PKT_LEN(0)) {\n+\t\t/* At least we have 1 byte to read. We don't need to return\n+\t\t * the exact readable bytes: see vsock_stream_recvmsg() ->\n+\t\t * vsock_stream_has_data().\n+\t\t */\n+\t\treturn 1;\n+\t}\n+\n+\tif (readable == HVS_PKT_LEN(0)) {\n+\t\t/* 0-size payload means FIN */\n+\t\treturn 0;\n+\t}\n+\n+\t/* No payload or FIN */\n+\treturn -1;\n+}\n+\n+static size_t hvs_channel_writable_bytes(struct vmbus_channel *chan)\n+{\n+\tu32 writeable = hv_get_bytes_to_write(&chan->outbound);\n+\tsize_t ret;\n+\n+\t/* The ringbuffer mustn't be 100% full, and we should reserve a\n+\t * zero-length-payload packet for the FIN: see hv_ringbuffer_write()\n+\t * and hvs_shutdown().\n+\t */\n+\tif (writeable <= HVS_PKT_LEN(1) + HVS_PKT_LEN(0))\n+\t\treturn 0;\n+\n+\tret = writeable - HVS_PKT_LEN(1) - HVS_PKT_LEN(0);\n+\n+\treturn round_down(ret, 8);\n+}\n+\n+static int hvs_send_data(struct vmbus_channel *chan,\n+\t\t\t struct hvs_send_buf *send_buf, size_t to_write)\n+{\n+\tsend_buf->hdr.pkt_type = 1;\n+\tsend_buf->hdr.data_size = to_write;\n+\treturn vmbus_sendpacket(chan, &send_buf->hdr,\n+\t\t\t\tsizeof(send_buf->hdr) + to_write,\n+\t\t\t\t0, VM_PKT_DATA_INBAND, 0);\n+}\n+\n+static void hvs_channel_cb(void *ctx)\n+{\n+\tstruct sock *sk = (struct sock *)ctx;\n+\tstruct vsock_sock *vsk = vsock_sk(sk);\n+\tstruct hvsock *hvs = vsk->trans;\n+\tstruct vmbus_channel *chan = hvs->chan;\n+\n+\tif (hvs_channel_readable(chan))\n+\t\tsk->sk_data_ready(sk);\n+\n+\t/* See hvs_stream_has_space(): when we reach here, the writable bytes\n+\t * may be already less than HVS_PKT_LEN(HVS_SEND_BUF_SIZE).\n+\t */\n+\tif (hv_get_bytes_to_write(&chan->outbound) > 0)\n+\t\tsk->sk_write_space(sk);\n+}\n+\n+static void hvs_close_connection(struct vmbus_channel *chan)\n+{\n+\tstruct sock *sk = get_per_channel_state(chan);\n+\tstruct vsock_sock *vsk = vsock_sk(sk);\n+\n+\tsk->sk_state = SS_UNCONNECTED;\n+\tsock_set_flag(sk, SOCK_DONE);\n+\tvsk->peer_shutdown |= SEND_SHUTDOWN | RCV_SHUTDOWN;\n+\n+\tsk->sk_state_change(sk);\n+}\n+\n+static void hvs_open_connection(struct vmbus_channel *chan)\n+{\n+\tuuid_le *if_instance, *if_type;\n+\tunsigned char conn_from_host;\n+\n+\tstruct sockaddr_vm addr;\n+\tstruct sock *sk, *new = NULL;\n+\tstruct vsock_sock *vnew;\n+\tstruct hvsock *hvs, *hvs_new;\n+\tint ret;\n+\n+\tif_type = &chan->offermsg.offer.if_type;\n+\tif_instance = &chan->offermsg.offer.if_instance;\n+\tconn_from_host = chan->offermsg.offer.u.pipe.user_def[0];\n+\n+\t/* The host or the VM should only listen on a port in\n+\t * [0, MAX_LISTEN_PORT]\n+\t */\n+\tif (!is_valid_srv_id(if_type) ||\n+\t    get_port_by_srv_id(if_type) > MAX_LISTEN_PORT)\n+\t\treturn;\n+\n+\thvs_addr_init(&addr, conn_from_host ? if_type : if_instance);\n+\tsk = vsock_find_bound_socket(&addr);\n+\tif (!sk)\n+\t\treturn;\n+\n+\tif ((conn_from_host && sk->sk_state != VSOCK_SS_LISTEN) ||\n+\t    (!conn_from_host && sk->sk_state != SS_CONNECTING))\n+\t\tgoto out;\n+\n+\tif (conn_from_host) {\n+\t\tif (sk->sk_ack_backlog >= sk->sk_max_ack_backlog)\n+\t\t\tgoto out;\n+\n+\t\tnew = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL,\n+\t\t\t\t     sk->sk_type, 0);\n+\t\tif (!new)\n+\t\t\tgoto out;\n+\n+\t\tnew->sk_state = SS_CONNECTING;\n+\t\tvnew = vsock_sk(new);\n+\t\thvs_new = vnew->trans;\n+\t\thvs_new->chan = chan;\n+\t} else {\n+\t\thvs = vsock_sk(sk)->trans;\n+\t\thvs->chan = chan;\n+\t}\n+\n+\tset_channel_read_mode(chan, HV_CALL_DIRECT);\n+\tret = vmbus_open(chan, RINGBUFFER_HVS_SND_SIZE,\n+\t\t\t RINGBUFFER_HVS_RCV_SIZE, NULL, 0,\n+\t\t\t hvs_channel_cb, conn_from_host ? new : sk);\n+\tif (ret != 0) {\n+\t\tif (conn_from_host) {\n+\t\t\thvs_new->chan = NULL;\n+\t\t\tsock_put(new);\n+\t\t} else {\n+\t\t\thvs->chan = NULL;\n+\t\t}\n+\t\tgoto out;\n+\t}\n+\n+\tset_per_channel_state(chan, conn_from_host ? new : sk);\n+\tvmbus_set_chn_rescind_callback(chan, hvs_close_connection);\n+\n+\tif (conn_from_host) {\n+\t\tnew->sk_state = SS_CONNECTED;\n+\t\tsk->sk_ack_backlog++;\n+\n+\t\thvs_addr_init(&vnew->local_addr, if_type);\n+\t\thvs_remote_addr_init(&vnew->remote_addr, &vnew->local_addr);\n+\n+\t\thvs_new->vm_srv_id = *if_type;\n+\t\thvs_new->host_srv_id = *if_instance;\n+\n+\t\tvsock_insert_connected(vnew);\n+\n+\t\tlock_sock(sk);\n+\t\tvsock_enqueue_accept(sk, new);\n+\t\trelease_sock(sk);\n+\t} else {\n+\t\tsk->sk_state = SS_CONNECTED;\n+\t\tsk->sk_socket->state = SS_CONNECTED;\n+\n+\t\tvsock_insert_connected(vsock_sk(sk));\n+\t}\n+\n+\tsk->sk_state_change(sk);\n+\n+out:\n+\t/* Release refcnt obtained when we called vsock_find_bound_socket() */\n+\tsock_put(sk);\n+}\n+\n+static u32 hvs_get_local_cid(void)\n+{\n+\treturn VMADDR_CID_ANY;\n+}\n+\n+static int hvs_sock_init(struct vsock_sock *vsk, struct vsock_sock *psk)\n+{\n+\tstruct hvsock *hvs;\n+\n+\thvs = kzalloc(sizeof(*hvs), GFP_KERNEL);\n+\tif (!hvs)\n+\t\treturn -ENOMEM;\n+\n+\tvsk->trans = hvs;\n+\thvs->vsk = vsk;\n+\n+\treturn 0;\n+}\n+\n+static int hvs_connect(struct vsock_sock *vsk)\n+{\n+\tunion hvs_service_id vm, host;\n+\tstruct hvsock *h = vsk->trans;\n+\n+\tvm.srv_id = srv_id_template;\n+\tvm.svm_port = vsk->local_addr.svm_port;\n+\th->vm_srv_id = vm.srv_id;\n+\n+\thost.srv_id = srv_id_template;\n+\thost.svm_port = vsk->remote_addr.svm_port;\n+\th->host_srv_id = host.srv_id;\n+\n+\treturn vmbus_send_tl_connect_request(&h->vm_srv_id, &h->host_srv_id);\n+}\n+\n+static int hvs_shutdown(struct vsock_sock *vsk, int mode)\n+{\n+\tstruct sock *sk = sk_vsock(vsk);\n+\tstruct vmpipe_proto_header hdr;\n+\tstruct hvs_send_buf *send_buf;\n+\tstruct hvsock *hvs;\n+\n+\tif (!(mode & SEND_SHUTDOWN))\n+\t\treturn 0;\n+\n+\tlock_sock(sk);\n+\n+\thvs = vsk->trans;\n+\tif (hvs->fin_sent)\n+\t\tgoto out;\n+\n+\tsend_buf = (struct hvs_send_buf *)&hdr;\n+\n+\t/* It can't fail: see hvs_channel_writable_bytes(). */\n+\t(void)hvs_send_data(hvs->chan, send_buf, 0);\n+\n+\thvs->fin_sent = true;\n+out:\n+\trelease_sock(sk);\n+\treturn 0;\n+}\n+\n+static void hvs_release(struct vsock_sock *vsk)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\tstruct vmbus_channel *chan = hvs->chan;\n+\n+\tif (chan)\n+\t\thvs_shutdown(vsk, RCV_SHUTDOWN | SEND_SHUTDOWN);\n+\n+\tvsock_remove_sock(vsk);\n+}\n+\n+static void hvs_destruct(struct vsock_sock *vsk)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\tstruct vmbus_channel *chan = hvs->chan;\n+\n+\tif (chan)\n+\t\tvmbus_hvsock_device_unregister(chan);\n+\n+\tkfree(hvs);\n+}\n+\n+static int hvs_dgram_bind(struct vsock_sock *vsk, struct sockaddr_vm *addr)\n+{\n+\treturn -EOPNOTSUPP;\n+}\n+\n+static int hvs_dgram_dequeue(struct vsock_sock *vsk, struct msghdr *msg,\n+\t\t\t     size_t len, int flags)\n+{\n+\treturn -EOPNOTSUPP;\n+}\n+\n+static int hvs_dgram_enqueue(struct vsock_sock *vsk,\n+\t\t\t     struct sockaddr_vm *remote, struct msghdr *msg,\n+\t\t\t     size_t dgram_len)\n+{\n+\treturn -EOPNOTSUPP;\n+}\n+\n+static bool hvs_dgram_allow(u32 cid, u32 port)\n+{\n+\treturn false;\n+}\n+\n+static int hvs_update_recv_data(struct hvsock *hvs)\n+{\n+\tstruct hvs_recv_buf *recv_buf;\n+\tu32 payload_len;\n+\n+\trecv_buf = (struct hvs_recv_buf *)(hvs->recv_desc + 1);\n+\tpayload_len = recv_buf->hdr.data_size;\n+\n+\tif (payload_len > HVS_MTU_SIZE)\n+\t\treturn -EIO;\n+\n+\tif (payload_len == 0)\n+\t\thvs->vsk->peer_shutdown |= SEND_SHUTDOWN;\n+\n+\thvs->recv_data_len = payload_len;\n+\thvs->recv_data_off = 0;\n+\n+\treturn 0;\n+}\n+\n+static ssize_t hvs_stream_dequeue(struct vsock_sock *vsk, struct msghdr *msg,\n+\t\t\t\t  size_t len, int flags)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\tbool need_refill = !hvs->recv_desc;\n+\tstruct hvs_recv_buf *recv_buf;\n+\tu32 to_read;\n+\tint ret;\n+\n+\tif (flags & MSG_PEEK)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tif (need_refill) {\n+\t\thvs->recv_desc = hv_pkt_iter_first(hvs->chan);\n+\t\tret = hvs_update_recv_data(hvs);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n+\trecv_buf = (struct hvs_recv_buf *)(hvs->recv_desc + 1);\n+\tto_read = min_t(u32, len, hvs->recv_data_len);\n+\tret = memcpy_to_msg(msg, recv_buf->data + hvs->recv_data_off, to_read);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\thvs->recv_data_len -= to_read;\n+\tif (hvs->recv_data_len == 0) {\n+\t\thvs->recv_desc = hv_pkt_iter_next(hvs->chan, hvs->recv_desc);\n+\t\tif (hvs->recv_desc) {\n+\t\t\tret = hvs_update_recv_data(hvs);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t} else {\n+\t\thvs->recv_data_off += to_read;\n+\t}\n+\n+\treturn to_read;\n+}\n+\n+static ssize_t hvs_stream_enqueue(struct vsock_sock *vsk, struct msghdr *msg,\n+\t\t\t\t  size_t len)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\tstruct vmbus_channel *chan = hvs->chan;\n+\tstruct hvs_send_buf *send_buf;\n+\tssize_t to_write, max_writable, ret;\n+\n+\tBUILD_BUG_ON(sizeof(*send_buf) != PAGE_SIZE_4K);\n+\n+\tsend_buf = kmalloc(sizeof(*send_buf), GFP_KERNEL);\n+\tif (!send_buf)\n+\t\treturn -ENOMEM;\n+\n+\tmax_writable = hvs_channel_writable_bytes(chan);\n+\tto_write = min_t(ssize_t, len, max_writable);\n+\tto_write = min_t(ssize_t, to_write, HVS_SEND_BUF_SIZE);\n+\n+\tret = memcpy_from_msg(send_buf->data, msg, to_write);\n+\tif (ret < 0)\n+\t\tgoto out;\n+\n+\tret = hvs_send_data(hvs->chan, send_buf, to_write);\n+\tif (ret < 0)\n+\t\tgoto out;\n+\n+\tret = to_write;\n+out:\n+\tkfree(send_buf);\n+\treturn ret;\n+}\n+\n+static s64 hvs_stream_has_data(struct vsock_sock *vsk)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\ts64 ret;\n+\n+\tif (hvs->recv_data_len > 0)\n+\t\treturn 1;\n+\n+\tswitch (hvs_channel_readable_payload(hvs->chan)) {\n+\tcase 1:\n+\t\tret = 1;\n+\t\tbreak;\n+\tcase 0:\n+\t\tvsk->peer_shutdown |= SEND_SHUTDOWN;\n+\t\tret = 0;\n+\t\tbreak;\n+\tdefault: /* -1 */\n+\t\tret = 0;\n+\t\tbreak;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static s64 hvs_stream_has_space(struct vsock_sock *vsk)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\tstruct vmbus_channel *chan = hvs->chan;\n+\ts64 ret;\n+\n+\tret = hvs_channel_writable_bytes(chan);\n+\tif (ret > 0)  {\n+\t\thvs_clear_channel_pending_send_size(chan);\n+\t} else {\n+\t\t/* See hvs_channel_cb() */\n+\t\thvs_set_channel_pending_send_size(chan);\n+\n+\t\t/* Re-check the writable bytes to avoid race */\n+\t\tret = hvs_channel_writable_bytes(chan);\n+\t\tif (ret > 0)\n+\t\t\thvs_clear_channel_pending_send_size(chan);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static u64 hvs_stream_rcvhiwat(struct vsock_sock *vsk)\n+{\n+\treturn HVS_MTU_SIZE + 1;\n+}\n+\n+static bool hvs_stream_is_active(struct vsock_sock *vsk)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\n+\treturn hvs->chan != NULL;\n+}\n+\n+static bool hvs_stream_allow(u32 cid, u32 port)\n+{\n+\t/* The host's port range [MIN_HOST_EPHEMERAL_PORT, 0xFFFFFFFF) is\n+\t * reserved as ephemeral ports, which are used as the host's ports\n+\t * when the host initiates connections.\n+\t *\n+\t * Perform this check in the guest so an immediate error is produced\n+\t * instead of a timeout.\n+\t */\n+\tif (port > MAX_HOST_LISTEN_PORT)\n+\t\treturn false;\n+\n+\tif (cid == VMADDR_CID_HOST)\n+\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+static\n+int hvs_notify_poll_in(struct vsock_sock *vsk, size_t target, bool *readable)\n+{\n+\tstruct hvsock *hvs = vsk->trans;\n+\n+\t*readable = hvs_channel_readable(hvs->chan);\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_poll_out(struct vsock_sock *vsk, size_t target, bool *writable)\n+{\n+\t*writable = hvs_stream_has_space(vsk) > 0;\n+\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_recv_init(struct vsock_sock *vsk, size_t target,\n+\t\t\t struct vsock_transport_recv_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_recv_pre_block(struct vsock_sock *vsk, size_t target,\n+\t\t\t      struct vsock_transport_recv_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_recv_pre_dequeue(struct vsock_sock *vsk, size_t target,\n+\t\t\t\tstruct vsock_transport_recv_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_recv_post_dequeue(struct vsock_sock *vsk, size_t target,\n+\t\t\t\t ssize_t copied, bool data_read,\n+\t\t\t\t struct vsock_transport_recv_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_send_init(struct vsock_sock *vsk,\n+\t\t\t struct vsock_transport_send_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_send_pre_block(struct vsock_sock *vsk,\n+\t\t\t      struct vsock_transport_send_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_send_pre_enqueue(struct vsock_sock *vsk,\n+\t\t\t\tstruct vsock_transport_send_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static\n+int hvs_notify_send_post_enqueue(struct vsock_sock *vsk, ssize_t written,\n+\t\t\t\t struct vsock_transport_send_notify_data *d)\n+{\n+\treturn 0;\n+}\n+\n+static void hvs_set_buffer_size(struct vsock_sock *vsk, u64 val)\n+{\n+\t/* Ignored. */\n+}\n+\n+static void hvs_set_min_buffer_size(struct vsock_sock *vsk, u64 val)\n+{\n+\t/* Ignored. */\n+}\n+\n+static void hvs_set_max_buffer_size(struct vsock_sock *vsk, u64 val)\n+{\n+\t/* Ignored. */\n+}\n+\n+static u64 hvs_get_buffer_size(struct vsock_sock *vsk)\n+{\n+\treturn -ENOPROTOOPT;\n+}\n+\n+static u64 hvs_get_min_buffer_size(struct vsock_sock *vsk)\n+{\n+\treturn -ENOPROTOOPT;\n+}\n+\n+static u64 hvs_get_max_buffer_size(struct vsock_sock *vsk)\n+{\n+\treturn -ENOPROTOOPT;\n+}\n+\n+static struct vsock_transport hvs_transport = {\n+\t.get_local_cid            = hvs_get_local_cid,\n+\n+\t.init                     = hvs_sock_init,\n+\t.destruct                 = hvs_destruct,\n+\t.release                  = hvs_release,\n+\t.connect                  = hvs_connect,\n+\t.shutdown                 = hvs_shutdown,\n+\n+\t.dgram_bind               = hvs_dgram_bind,\n+\t.dgram_dequeue            = hvs_dgram_dequeue,\n+\t.dgram_enqueue            = hvs_dgram_enqueue,\n+\t.dgram_allow              = hvs_dgram_allow,\n+\n+\t.stream_dequeue           = hvs_stream_dequeue,\n+\t.stream_enqueue           = hvs_stream_enqueue,\n+\t.stream_has_data          = hvs_stream_has_data,\n+\t.stream_has_space         = hvs_stream_has_space,\n+\t.stream_rcvhiwat          = hvs_stream_rcvhiwat,\n+\t.stream_is_active         = hvs_stream_is_active,\n+\t.stream_allow             = hvs_stream_allow,\n+\n+\t.notify_poll_in           = hvs_notify_poll_in,\n+\t.notify_poll_out          = hvs_notify_poll_out,\n+\t.notify_recv_init         = hvs_notify_recv_init,\n+\t.notify_recv_pre_block    = hvs_notify_recv_pre_block,\n+\t.notify_recv_pre_dequeue  = hvs_notify_recv_pre_dequeue,\n+\t.notify_recv_post_dequeue = hvs_notify_recv_post_dequeue,\n+\t.notify_send_init         = hvs_notify_send_init,\n+\t.notify_send_pre_block    = hvs_notify_send_pre_block,\n+\t.notify_send_pre_enqueue  = hvs_notify_send_pre_enqueue,\n+\t.notify_send_post_enqueue = hvs_notify_send_post_enqueue,\n+\n+\t.set_buffer_size          = hvs_set_buffer_size,\n+\t.set_min_buffer_size      = hvs_set_min_buffer_size,\n+\t.set_max_buffer_size      = hvs_set_max_buffer_size,\n+\t.get_buffer_size          = hvs_get_buffer_size,\n+\t.get_min_buffer_size      = hvs_get_min_buffer_size,\n+\t.get_max_buffer_size      = hvs_get_max_buffer_size,\n+};\n+\n+static int hvs_probe(struct hv_device *hdev,\n+\t\t     const struct hv_vmbus_device_id *dev_id)\n+{\n+\tstruct vmbus_channel *chan = hdev->channel;\n+\n+\thvs_open_connection(chan);\n+\n+\t/* Always return success to suppress the unnecessary error message\n+\t * in vmbus_probe(): on error the host will rescind the device in\n+\t * 30 seconds and we can do cleanup at that time in\n+\t * vmbus_onoffer_rescind().\n+\t */\n+\treturn 0;\n+}\n+\n+static int hvs_remove(struct hv_device *hdev)\n+{\n+\tstruct vmbus_channel *chan = hdev->channel;\n+\n+\tvmbus_close(chan);\n+\n+\treturn 0;\n+}\n+\n+/* This isn't really used. See vmbus_match() and vmbus_probe() */\n+static const struct hv_vmbus_device_id id_table[] = {\n+\t{},\n+};\n+\n+static struct hv_driver hvs_drv = {\n+\t.name\t\t= \"hv_sock\",\n+\t.hvsock\t\t= true,\n+\t.id_table\t= id_table,\n+\t.probe\t\t= hvs_probe,\n+\t.remove\t\t= hvs_remove,\n+};\n+\n+static int __init hvs_init(void)\n+{\n+\tint ret;\n+\n+\tif (vmbus_proto_version < VERSION_WIN10)\n+\t\treturn -ENODEV;\n+\n+\tret = vmbus_driver_register(&hvs_drv);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tret = vsock_core_init(&hvs_transport);\n+\tif (ret) {\n+\t\tvmbus_driver_unregister(&hvs_drv);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void __exit hvs_exit(void)\n+{\n+\tvsock_core_exit();\n+\tvmbus_driver_unregister(&hvs_drv);\n+}\n+\n+module_init(hvs_init);\n+module_exit(hvs_exit);\n+\n+MODULE_DESCRIPTION(\"Hyper-V Sockets\");\n+MODULE_VERSION(\"1.0.0\");\n+MODULE_LICENSE(\"GPL\");\n+MODULE_ALIAS_NETPROTO(PF_VSOCK);\n",
    "prefixes": [
        "v3",
        "net-next",
        "1/1"
    ]
}